+
+ /* Check all configured servers */
+ for( i = 0; i < MAX_SERVERS; i++ )
+ {
+ /* Valid outgoing server which isn't already connected or disabled? */
+ if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 ) || ( Conf_Server[i].conn_id > NONE ) || ( Conf_Server[i].flags & CONF_SFLAG_DISABLED )) continue;
+
+ /* Is there already a connection in this group? */
+ if( Conf_Server[i].group > NONE )
+ {
+ for( n = 0; n < MAX_SERVERS; n++ )
+ {
+ if( n == i ) continue;
+ if(( Conf_Server[n].conn_id > NONE ) && ( Conf_Server[n].group == Conf_Server[i].group )) break;
+ }
+ if( n < MAX_SERVERS ) continue;
+ }
+
+ /* Check last connect attempt? */
+ if( Conf_Server[i].lasttry > time( NULL ) - Conf_ConnectRetry ) continue;
+
+ /* Okay, try to connect now */
+ Conf_Server[i].lasttry = time( NULL );
+
+ /* Search free connection structure */
+ for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break;
+ if( idx >= Pool_Size )
+ {
+ Log( LOG_ALERT, "Can't establist server connection: connection limit reached (%d)!", Pool_Size );
+ return;
+ }
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Preparing connection %d for \"%s\" ...", idx, Conf_Server[i].host );
+#endif
+
+ /* Verbindungs-Struktur initialisieren */
+ Init_Conn_Struct( idx );
+ My_Connections[idx].sock = SERVER_WAIT;
+ Conf_Server[i].conn_id = idx;
+
+ /* Resolve Hostname. If this fails, try to use it as an IP address */
+ strlcpy( Conf_Server[i].ip, Conf_Server[i].host, sizeof( Conf_Server[i].ip ));
+ strlcpy( My_Connections[idx].host, Conf_Server[i].host, sizeof( My_Connections[idx].host ));
+ s = Resolve_Name( Conf_Server[i].host );
+
+ /* resolver process running? */
+ if( s ) My_Connections[idx].res_stat = s;
+ }
+} /* Check_Servers */
+
+
+static void
+New_Server( int Server, CONN_ID Idx )
+{
+ /* Establish new server link */
+
+ struct sockaddr_in new_addr;
+ struct in_addr inaddr;
+ int res, new_sock;
+ CLIENT *c;
+
+ assert( Server > NONE );
+ assert( Idx > NONE );
+
+ /* Did we get a valid IP address? */
+ if( ! Conf_Server[Server].ip[0] ) {
+ /* No. Free connection structure and abort: */
+ Log( LOG_ERR, "Can't connect to \"%s\" (connection %d): ip address unknown!", Conf_Server[Server].host, Idx );
+ goto out;
+ }
+
+ Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d (connection %d) ... ", Conf_Server[Server].host, Conf_Server[Server].ip, Conf_Server[Server].port, Idx );
+
+#ifdef HAVE_INET_ATON
+ if( inet_aton( Conf_Server[Server].ip, &inaddr ) == 0 )
+#else
+ memset( &inaddr, 0, sizeof( inaddr ));
+ inaddr.s_addr = inet_addr( Conf_Server[Server].ip );
+ if( inaddr.s_addr == (unsigned)-1 )
+#endif
+ {
+ /* Can't convert IP address */
+ Log( LOG_ERR, "Can't connect to \"%s\" (connection %d): can't convert ip address %s!", Conf_Server[Server].host, Idx, Conf_Server[Server].ip );
+ goto out;
+ }
+
+ memset( &new_addr, 0, sizeof( new_addr ));
+ new_addr.sin_family = AF_INET;
+ new_addr.sin_addr = inaddr;
+ new_addr.sin_port = htons( Conf_Server[Server].port );
+
+ new_sock = socket( PF_INET, SOCK_STREAM, 0 );
+ if ( new_sock < 0 ) {
+ /* Can't create socket */
+ Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
+ goto out;
+ }
+
+ if( ! Init_Socket( new_sock )) return;
+
+ res = connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr ));
+ if(( res != 0 ) && ( errno != EINPROGRESS )) {
+ /* Can't connect socket */
+ Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
+ close( new_sock );
+ goto out;
+ }
+
+ /* Client-Struktur initialisieren */
+ c = Client_NewLocal( Idx, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWNSERVER, false );
+ if( ! c ) {
+ /* Can't create new client structure */
+ Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
+ close( new_sock );
+ goto out;
+ }
+
+ Client_SetIntroducer( c, c );
+ Client_SetToken( c, TOKEN_OUTBOUND );
+
+ /* Register connection */
+ My_Connections[Idx].sock = new_sock;
+ My_Connections[Idx].addr = new_addr;
+ strlcpy( My_Connections[Idx].host, Conf_Server[Server].host, sizeof( My_Connections[Idx].host ));
+
+ /* Register new socket */
+ if (!io_event_create( new_sock, IO_WANTWRITE, cb_connserver)) {
+ Log( LOG_ALERT, "io_event_create(): could not add fd %d", strerror(errno));
+ Conn_Close( Idx, "io_event_create() failed", NULL, false );
+ goto out;
+ }
+
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Registered new connection %d on socket %d.", Idx, My_Connections[Idx].sock );
+#endif
+ Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCONNECTING );
+ return;
+out:
+ Init_Conn_Struct( Idx );
+ Conf_Server[Server].conn_id = NONE;
+} /* New_Server */
+
+
+static void
+Init_Conn_Struct( CONN_ID Idx )
+{
+ time_t now = time( NULL );
+ /* Connection-Struktur initialisieren */
+
+ memset( &My_Connections[Idx], 0, sizeof ( CONNECTION ));
+ My_Connections[Idx].sock = NONE;
+ My_Connections[Idx].lastdata = now;
+ My_Connections[Idx].lastprivmsg = now;
+} /* Init_Conn_Struct */
+
+
+static bool
+Init_Socket( int Sock )
+{
+ /* Initialize socket (set options) */
+
+ int value;
+
+ if (!io_setnonblock(Sock)) {
+ Log( LOG_CRIT, "Can't enable non-blocking mode for socket: %s!", strerror( errno ));
+ close( Sock );
+ return false;
+ }
+
+ /* Don't block this port after socket shutdown */
+ value = 1;
+ if( setsockopt( Sock, SOL_SOCKET, SO_REUSEADDR, &value, (socklen_t)sizeof( value )) != 0 )
+ {
+ Log( LOG_ERR, "Can't set socket option SO_REUSEADDR: %s!", strerror( errno ));
+ /* ignore this error */
+ }
+
+ /* Set type of service (TOS) */
+#if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
+ value = IPTOS_LOWDELAY;
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Setting option IP_TOS on socket %d to IPTOS_LOWDELAY (%d).", Sock, value );
+#endif
+ if( setsockopt( Sock, SOL_IP, IP_TOS, &value, (socklen_t)sizeof( value )) != 0 )
+ {
+ Log( LOG_ERR, "Can't set socket option IP_TOS: %s!", strerror( errno ));
+ /* ignore this error */
+ }
+#endif
+
+ return true;
+} /* Init_Socket */
+
+
+GLOBAL
+void Read_Resolver_Result( int r_fd )
+{
+ /* Read result of resolver sub-process from pipe and update the
+ * apropriate connection/client structure(s): hostname and/or
+ * IDENT user name.*/
+
+ CLIENT *c;
+ int bytes_read, i, n;
+ unsigned int len;
+ RES_STAT *s;
+ char *ptr;
+ char *bufptr;
+ char readbuf[HOST_LEN];
+
+ Log( LOG_DEBUG, "Resolver: started, fd %d", r_fd );
+ /* Search associated connection ... */
+ for( i = 0; i < Pool_Size; i++ )
+ {
+ if(( My_Connections[i].sock != NONE )
+ && ( My_Connections[i].res_stat != NULL )
+ && ( My_Connections[i].res_stat->pipe[0] == r_fd ))
+ break;
+ }
+ if( i >= Pool_Size )
+ {
+ /* Ops, none found? Probably the connection has already
+ * been closed!? We'll ignore that ... */
+ io_close( r_fd );
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Resolver: Got result for unknown connection!?" );
+#endif
+ return;
+ }
+
+ /* Get resolver structure */
+ s = My_Connections[i].res_stat;
+ assert( s != NULL );
+
+ /* Read result from pipe */
+ bytes_read = read( r_fd, readbuf, sizeof readbuf -1 );
+ if( bytes_read < 0 ) {
+ /* Error! */
+ Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror( errno ));
+ FreeRes_stat( &My_Connections[i] );
+ return;
+ }
+ len = (unsigned int) bytes_read;
+ readbuf[len] = '\0';
+ if (!array_catb(&s->buffer, readbuf, len)) {
+ Log( LOG_CRIT, "Resolver: Can't append result %s to buffer: %s", readbuf, strerror( errno ));
+ FreeRes_stat(&My_Connections[i]);
+ return;
+ }
+
+ if (!array_cat0_temporary(&s->buffer)) {
+ Log( LOG_CRIT, "Resolver: Can't append result %s to buffer: %s", readbuf, strerror( errno ));
+ FreeRes_stat(&My_Connections[i]);
+ return;
+ }
+
+ /* If the result string is incomplete, return to main loop and
+ * wait until we can read in more bytes. */
+#ifdef IDENTAUTH
+try_resolve:
+#endif
+ bufptr = (char*) array_start(&s->buffer);
+ assert(bufptr != NULL);
+ ptr = strchr( bufptr, '\n' );
+ if( ! ptr ) return;
+ *ptr = '\0';
+
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Got result from resolver: \"%s\" (%u bytes read), stage %d.", bufptr, len, s->stage);
+#endif
+
+ /* Okay, we got a complete result: this is a host name for outgoing
+ * connections and a host name or IDENT user name (if enabled) for
+ * incoming connections.*/
+ if( My_Connections[i].sock > NONE )
+ {
+ /* Incoming connection. Search client ... */
+ c = Client_GetFromConn( i );
+ assert( c != NULL );
+
+ /* Only update client information of unregistered clients */
+ if( Client_Type( c ) == CLIENT_UNKNOWN )
+ {
+ switch(s->stage) {
+ case 0: /* host name */
+ strlcpy( My_Connections[i].host, bufptr, sizeof( My_Connections[i].host));
+
+ Client_SetHostname( c, bufptr);
+#ifdef IDENTAUTH
+ /* clean up buffer for IDENT result */
+ len = strlen(bufptr) + 1;
+ assert(len <= array_bytes(&s->buffer));
+ array_moveleft(&s->buffer, 1, len);
+
+ /* Don't close pipe and clean up, but
+ * instead wait for IDENT result */
+ s->stage = 1;
+ goto try_resolve;
+
+ case 1: /* IDENT user name */
+ if (array_bytes(&s->buffer)) {
+ bufptr = (char*) array_start(&s->buffer);
+ Log( LOG_INFO, "IDENT lookup for connection %ld: \"%s\".", i, bufptr);
+ Client_SetUser( c, bufptr, true );
+ }
+ else Log( LOG_INFO, "IDENT lookup for connection %ld: no result.", i );
+#endif
+ break;
+ default:
+ Log( LOG_ERR, "Resolver: got result for unknown stage %d!?", s->stage );
+ }
+ }
+#ifdef DEBUG
+ else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );
+#endif
+ }
+ else
+ {
+ /* Outgoing connection (server link): set the IP address
+ * so that we can connect to it in the main loop. */
+
+ /* Search server ... */
+ n = Conf_GetServer( i );
+ assert( n > NONE );
+
+ bufptr = (char*) array_start(&s->buffer);
+ strlcpy( Conf_Server[n].ip, bufptr, sizeof( Conf_Server[n].ip ));
+ }
+
+ /* Clean up ... */
+ FreeRes_stat( &My_Connections[i] );
+
+ /* Reset penalty time */
+ Conn_ResetPenalty( i );
+} /* Read_Resolver_Result */
+
+
+static void
+Simple_Message( int Sock, char *Msg )
+{
+ char buf[COMMAND_LEN];
+ /* Write "simple" message to socket, without using compression
+ * or even the connection write buffers. Used e.g. for error
+ * messages by New_Connection(). */
+ assert( Sock > NONE );
+ assert( Msg != NULL );
+
+ strlcpy( buf, Msg, sizeof buf - 2);
+ strlcat( buf, "\r\n", sizeof buf);
+ (void)write( Sock, buf, strlen( buf ) );
+} /* Simple_Error */
+
+
+static int
+Count_Connections( struct sockaddr_in addr_in )
+{
+ int i, cnt;
+
+ cnt = 0;
+ for( i = 0; i < Pool_Size; i++ )
+ {
+ if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].addr.sin_addr.s_addr == addr_in.sin_addr.s_addr )) cnt++;
+ }
+ return cnt;
+} /* Count_Connections */
+