+ Check_Servers( );
+
+ Check_Connections( );
+
+ /* Timeout initialisieren */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ /* noch volle Lese-Buffer suchen */
+ for( i = 0; i < MAX_CONNECTIONS; i++ )
+ {
+ if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].rdatalen > 0 ))
+ {
+ /* Kann aus dem Buffer noch ein Befehl extrahiert werden? */
+ Handle_Buffer( i );
+ }
+ }
+
+ /* noch volle Schreib-Puffer suchen */
+ FD_ZERO( &write_sockets );
+ for( i = 0; i < MAX_CONNECTIONS; i++ )
+ {
+ if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].wdatalen > 0 ))
+ {
+ /* Socket der Verbindung in Set aufnehmen */
+ FD_SET( My_Connections[i].sock, &write_sockets );
+ }
+ }
+ /* Sockets mit im Aufbau befindlichen ausgehenden Verbindungen suchen */
+ for( i = 0; i < MAX_CONNECTIONS; i++ )
+ {
+ if(( My_Connections[i].sock > NONE ) && ( FD_ISSET( My_Connections[i].sock, &My_Connects ))) FD_SET( My_Connections[i].sock, &write_sockets );
+ }
+
+ /* von welchen Sockets koennte gelesen werden? */
+ t = time( NULL );
+ read_sockets = My_Sockets;
+ for( i = 0; i < MAX_CONNECTIONS; i++ )
+ {
+ if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].host[0] == '\0' ))
+ {
+ /* Hier muss noch auf den Resolver Sub-Prozess gewartet werden */
+ FD_CLR( My_Connections[i].sock, &read_sockets );
+ }
+ if(( My_Connections[i].sock > NONE ) && ( FD_ISSET( My_Connections[i].sock, &My_Connects )))
+ {
+ /* Hier laeuft noch ein asyncrones connect() */
+ FD_CLR( My_Connections[i].sock, &read_sockets );
+ }
+ if( My_Connections[i].delaytime > t )
+ {
+ /* Fuer die Verbindung ist eine "Penalty-Zeit" gesetzt */
+ FD_CLR( My_Connections[i].sock, &read_sockets );
+ }
+ }
+ for( i = 0; i < Conn_MaxFD + 1; i++ )
+ {
+ /* Pipes von Resolver Sub-Prozessen aufnehmen */
+ if( FD_ISSET( i, &Resolver_FDs ))
+ {
+ FD_SET( i, &read_sockets );
+ }
+ }
+
+ /* Auf Aktivitaet warten */
+ if( select( Conn_MaxFD + 1, &read_sockets, &write_sockets, NULL, &tv ) == -1 )
+ {
+ if( errno != EINTR )
+ {
+ Log( LOG_EMERG, "select(): %s!", strerror( errno ));
+ Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE );
+ exit( 1 );
+ }
+ continue;
+ }
+
+ /* Koennen Daten geschrieben werden? */
+ for( i = 0; i < Conn_MaxFD + 1; i++ )
+ {
+ if( FD_ISSET( i, &write_sockets )) Handle_Write( Socket2Index( i ));
+ }
+
+ /* Daten zum Lesen vorhanden? */
+ for( i = 0; i < Conn_MaxFD + 1; i++ )
+ {
+ if( FD_ISSET( i, &read_sockets )) Handle_Read( i );
+ }
+ }
+} /* Conn_Handler */
+
+
+#ifdef PROTOTYPES
+GLOBAL BOOLEAN
+Conn_WriteStr( CONN_ID Idx, CHAR *Format, ... )
+#else
+GLOBAL BOOLEAN
+Conn_WriteStr( Idx, Format, va_alist )
+CONN_ID Idx;
+CHAR *Format;
+va_dcl
+#endif
+{
+ /* String in Socket schreiben. CR+LF wird von dieser Funktion
+ * automatisch angehaengt. Im Fehlerfall wird dir Verbindung
+ * getrennt und FALSE geliefert. */
+
+ CHAR buffer[COMMAND_LEN];
+ BOOLEAN ok;
+ va_list ap;
+
+ assert( Idx >= 0 );
+ assert( My_Connections[Idx].sock > NONE );
+ assert( Format != NULL );
+
+#ifdef PROTOTYPES
+ va_start( ap, Format );
+#else
+ va_start( ap );
+#endif
+ if( vsnprintf( buffer, COMMAND_LEN - 2, Format, ap ) == COMMAND_LEN - 2 )
+ {
+ Log( LOG_CRIT, "Text too long to send (connection %d)!", Idx );
+ Conn_Close( Idx, "Text too long to send!", NULL, FALSE );
+ return FALSE;
+ }
+
+#ifdef SNIFFER
+ if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer );
+#endif
+
+ strcat( buffer, "\r\n" );
+ ok = Conn_Write( Idx, buffer, strlen( buffer ));
+
+ va_end( ap );
+ return ok;
+} /* Conn_WriteStr */
+
+
+GLOBAL BOOLEAN
+Conn_Write( CONN_ID Idx, CHAR *Data, INT Len )
+{
+ /* Daten in Socket schreiben. Bei "fatalen" Fehlern wird
+ * der Client disconnectiert und FALSE geliefert. */
+
+ assert( Idx >= 0 );
+ assert( My_Connections[Idx].sock > NONE );
+ assert( Data != NULL );
+ assert( Len > 0 );
+
+ /* pruefen, ob Daten im Schreibpuffer sind. Wenn ja, zunaechst
+ * pruefen, ob diese gesendet werden koennen */
+ if( My_Connections[Idx].wdatalen > 0 )
+ {
+ if( ! Try_Write( Idx )) return FALSE;
+ }
+
+ /* pruefen, ob im Schreibpuffer genuegend Platz ist */
+ if( WRITEBUFFER_LEN - My_Connections[Idx].wdatalen - Len <= 0 )
+ {
+ /* der Puffer ist dummerweise voll ... */
+ Log( LOG_NOTICE, "Write buffer overflow (connection %d)!", Idx );
+ Conn_Close( Idx, "Write buffer overflow!", NULL, FALSE );
+ return FALSE;
+ }
+
+ /* Daten in Puffer kopieren */
+ memcpy( My_Connections[Idx].wbuf + My_Connections[Idx].wdatalen, Data, Len );
+ My_Connections[Idx].wdatalen += Len;
+
+ /* pruefen, on Daten vorhanden sind und geschrieben werden koennen */
+ if( My_Connections[Idx].wdatalen > 0 )
+ {
+ if( ! Try_Write( Idx )) return FALSE;
+ }
+
+ return TRUE;
+} /* Conn_Write */
+
+
+GLOBAL VOID
+Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient )
+{
+ /* Verbindung schliessen. Evtl. noch von Resolver
+ * Sub-Prozessen offene Pipes werden geschlossen. */
+
+ CLIENT *c;
+
+ assert( Idx >= 0 );
+ assert( My_Connections[Idx].sock > NONE );
+
+ if( InformClient )
+ {
+ if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg );
+ else Conn_WriteStr( Idx, "ERROR :Closing connection." );
+ if( My_Connections[Idx].sock == NONE ) return;