X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=16dfbdb4e517eb569f55bd68176b1f54a2798eff;hp=e0bd7b457151e5cec6981e5ab003447decd46937;hb=5457e0788a0b3ce610ad909e93d451c86b126803;hpb=79809118a30e8160773bf0f521100339efff6000 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index e0bd7b45..16dfbdb4 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -9,11 +9,52 @@ * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. * - * $Id: conn.c,v 1.33 2002/01/06 15:18:14 alex Exp $ + * $Id: conn.c,v 1.45 2002/03/02 02:44:01 alex Exp $ * * connect.h: Verwaltung aller Netz-Verbindungen ("connections") * * $Log: conn.c,v $ + * Revision 1.45 2002/03/02 02:44:01 alex + * - Timeouts ausgehender Verbindungen werden besser erkannt (z.B. unter Cygwin). + * - Idle-Time der Hauptschleife [Conn_Handle()] erhoeht: weniger Last. + * + * Revision 1.44 2002/03/02 00:43:31 alex + * - bei abgebrochene ausgehende Server-Verbindungen wird der naechste Ver- + * bindungsversuch in RECONNECT_DELAY Sekunden (3) unternommen und nicht + * mehr "ConnectRetry" Sekunden gewartet. + * + * Revision 1.43 2002/03/02 00:29:11 alex + * - der Wert der Konfigurations-Variable "ConnectRetry" wird besser beachtet. + * + * Revision 1.42 2002/03/02 00:23:32 alex + * - ausgehende Verbindungen werden nun asyncron connectiert und blockieren + * nicht mehr den Server. Dadurch waren einige Aenderungen noetig. + * - diverse Log-Meldungen ueberarbeitet. + * + * Revision 1.41 2002/02/27 14:47:04 alex + * - Logging bei Timeout von Verbindungen geaendert. + * + * Revision 1.40 2002/02/27 02:26:23 alex + * - an Conn_Close() werden zwei weitere Fehlermeldungen zum Forwarden uebergeben. + * + * Revision 1.39 2002/02/23 00:03:54 alex + * - Ergebnistyp von Conn_GetIdle() und Conn_LastPing() auf "time_t" geaendert. + * + * Revision 1.38 2002/02/19 20:34:31 alex + * - Bei ausgehenden Verbindungen wird der Ziel-Port ins Log geschrieben. + * + * Revision 1.37 2002/02/19 20:05:37 alex + * - "Passive-Mode" implementiert: kein Auto-Conect zu anderen Servern. + * + * Revision 1.36 2002/02/11 01:00:50 alex + * - neue Funktion Conn_LastPing(). + * + * Revision 1.35 2002/01/18 11:12:11 alex + * - der Sniffer wird nun nur noch aktiviert, wenn auf Kommandozeile angegeben. + * + * Revision 1.34 2002/01/07 15:29:52 alex + * - PASSSERVERADD definiert, wird beim PASS-Befehl an Server verwendet. + * * Revision 1.33 2002/01/06 15:18:14 alex * - Loglevel und Meldungen nochmals geaendert. Level passen nun besser. * @@ -199,6 +240,7 @@ LOCAL VOID Handle_Buffer( CONN_ID Idx ); LOCAL VOID Check_Connections( VOID ); LOCAL VOID Check_Servers( VOID ); LOCAL VOID Init_Conn_Struct( INT Idx ); +LOCAL BOOLEAN Init_Socket( INT Sock ); LOCAL VOID New_Server( INT Server, CONN_ID Idx ); LOCAL RES_STAT *ResolveAddr( struct sockaddr_in *Addr ); @@ -212,6 +254,7 @@ LOCAL CHAR *Resolv_Error( INT H_Error ); LOCAL fd_set My_Listeners; LOCAL fd_set My_Sockets; LOCAL fd_set My_Resolvers; +LOCAL fd_set My_Connects; LOCAL INT My_Max_Fd; @@ -228,6 +271,7 @@ GLOBAL VOID Conn_Init( VOID ) FD_ZERO( &My_Listeners ); FD_ZERO( &My_Sockets ); FD_ZERO( &My_Resolvers ); + FD_ZERO( &My_Connects ); My_Max_Fd = 0; @@ -254,16 +298,21 @@ GLOBAL VOID Conn_Exit( VOID ) { if( My_Connections[idx].sock == i ) break; } - if( idx < MAX_CONNECTIONS ) Conn_Close( idx, NULL, "Server going down", TRUE ); - else if( FD_ISSET( i, &My_Listeners )) + if( FD_ISSET( i, &My_Listeners )) { close( i ); Log( LOG_DEBUG, "Listening socket %d closed.", i ); } + else if( FD_ISSET( i, &My_Connects )) + { + close( i ); + Log( LOG_DEBUG, "Connection %d closed during creation (socket %d).", idx, i ); + } + else if( idx < MAX_CONNECTIONS ) Conn_Close( idx, NULL, "Server going down", TRUE ); else { + Log( LOG_WARNING, "Closing unknown connection %d ...", i ); close( i ); - Log( LOG_WARNING, "Unknown connection %d closed.", i ); } } } @@ -277,7 +326,7 @@ GLOBAL BOOLEAN Conn_NewListener( CONST INT Port ) * Socket nicht erteugt werden, so wird NULL geliefert.*/ struct sockaddr_in addr; - INT sock, on = 1; + INT sock; /* Server-"Listen"-Socket initialisieren */ memset( &addr, 0, sizeof( addr )); @@ -293,18 +342,7 @@ GLOBAL BOOLEAN Conn_NewListener( CONST INT Port ) return FALSE; } - /* Socket-Optionen setzen */ - if( fcntl( sock, F_SETFL, O_NONBLOCK ) != 0 ) - { - Log( LOG_CRIT, "Can't enable non-blocking mode: %s!", strerror( errno )); - close( sock ); - return FALSE; - } - if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t)sizeof( on )) != 0) - { - Log( LOG_ERR, "Can't set socket options: %s!", strerror( errno )); - /* dieser Fehler kann ignoriert werden. */ - } + if( ! Init_Socket( sock )) return FALSE; /* an Port binden */ if( bind( sock, (struct sockaddr *)&addr, (socklen_t)sizeof( addr )) != 0 ) @@ -360,8 +398,8 @@ GLOBAL VOID Conn_Handler( INT Timeout ) Check_Connections( ); /* Timeout initialisieren */ - tv.tv_sec = 0; - tv.tv_usec = 50000; + tv.tv_sec = 2; + tv.tv_usec = 0; /* noch volle Lese-Buffer suchen */ for( i = 0; i < MAX_CONNECTIONS; i++ ) @@ -383,6 +421,11 @@ GLOBAL VOID Conn_Handler( INT Timeout ) 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? */ read_sockets = My_Sockets; @@ -393,6 +436,11 @@ GLOBAL VOID Conn_Handler( INT Timeout ) /* 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 ); + } } for( i = 0; i < My_Max_Fd + 1; i++ ) { @@ -449,7 +497,7 @@ GLOBAL BOOLEAN Conn_WriteStr( CONN_ID Idx, CHAR *Format, ... ) } #ifdef SNIFFER - Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer ); + if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer ); #endif strcat( buffer, "\r\n" ); @@ -538,10 +586,13 @@ GLOBAL VOID Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformC free( My_Connections[Idx].res_stat ); } - /* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */ - if( My_Connections[Idx].our_server >= 0 ) Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL ); + /* Bei Server-Verbindungen lasttry-Zeitpunkt so setzen, dass + * der naechste Verbindungsversuch in RECONNECT_DELAY Sekunden + * gestartet wird */ + if( My_Connections[Idx].our_server >= 0 ) Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY; FD_CLR( My_Connections[Idx].sock, &My_Sockets ); + FD_CLR( My_Connections[Idx].sock, &My_Connects ); My_Connections[Idx].sock = NONE; } /* Conn_Close */ @@ -555,7 +606,7 @@ GLOBAL VOID Conn_UpdateIdle( CONN_ID Idx ) } -GLOBAL INT32 Conn_GetIdle( CONN_ID Idx ) +GLOBAL time_t Conn_GetIdle( CONN_ID Idx ) { /* Idle-Time einer Verbindung liefern (in Sekunden) */ @@ -564,6 +615,15 @@ GLOBAL INT32 Conn_GetIdle( CONN_ID Idx ) } /* Conn_GetIdle */ +GLOBAL time_t Conn_LastPing( CONN_ID Idx ) +{ + /* Zeitpunkt des letzten PING liefern */ + + assert( Idx >= 0 ); + return My_Connections[Idx].lastping; +} /* Conn_LastPing */ + + LOCAL BOOLEAN Try_Write( CONN_ID Idx ) { /* Versuchen, Daten aus dem Schreib-Puffer in den @@ -629,12 +689,51 @@ LOCAL VOID Handle_Read( INT Sock ) LOCAL BOOLEAN Handle_Write( CONN_ID Idx ) { - /* Daten aus Schreibpuffer versenden */ + /* Daten aus Schreibpuffer versenden bzw. Connection aufbauen */ - INT len; + INT len, res, err; assert( Idx >= 0 ); assert( My_Connections[Idx].sock > NONE ); + + if( FD_ISSET( My_Connections[Idx].sock, &My_Connects )) + { + /* es soll nichts geschrieben werden, sondern ein + * connect() hat ein Ergebnis geliefert */ + + FD_CLR( My_Connections[Idx].sock, &My_Connects ); + + /* Ergebnis des connect() ermitteln */ + len = sizeof( err ); + res = getsockopt( My_Connections[Idx].sock, SOL_SOCKET, SO_ERROR, &err, &len ); + assert( len == sizeof( err )); + + /* Fehler aufgetreten? */ + if(( res != 0 ) || ( err != 0 )) + { + /* Fehler! */ + if( res != 0 ) Log( LOG_CRIT, "getsockopt (connection %d): %s!", Idx, strerror( errno )); + else Log( LOG_CRIT, "Can't connect socket to \"%s:%d\" (connection %d): %s!", My_Connections[Idx].host, Conf_Server[My_Connections[Idx].our_server].port, Idx, strerror( err )); + + /* Socket etc. pp. aufraeumen */ + FD_CLR( My_Connections[Idx].sock, &My_Sockets ); + close( My_Connections[Idx].sock ); + Init_Conn_Struct( Idx ); + + /* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */ + Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL ); + + return FALSE; + } + Log( LOG_DEBUG, "Connection %d with \"%s:%d\" established, now sendig PASS and SERVER ...", Idx, My_Connections[Idx].host, Conf_Server[My_Connections[Idx].our_server].port ); + + /* PASS und SERVER verschicken */ + Conn_WriteStr( Idx, "PASS %s "PASSSERVERADD, Conf_Server[My_Connections[Idx].our_server].pwd ); + Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo ); + + return TRUE; + } + assert( My_Connections[Idx].wdatalen > 0 ); /* Daten schreiben */ @@ -757,7 +856,7 @@ LOCAL VOID Read_Request( CONN_ID Idx ) { /* Socket wurde geschlossen */ Log( LOG_INFO, "%s:%d is closing the connection ...", inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port)); - Conn_Close( Idx, "Socket closed.", NULL, FALSE ); + Conn_Close( Idx, NULL, "Client closed connection.", FALSE ); return; } @@ -765,7 +864,7 @@ LOCAL VOID Read_Request( CONN_ID Idx ) { /* Fehler beim Lesen */ Log( LOG_ERR, "Read error on connection %d: %s!", Idx, strerror( errno )); - Conn_Close( Idx, "Read error!", NULL, FALSE ); + Conn_Close( Idx, NULL, "Read error!", FALSE ); return; } @@ -876,8 +975,8 @@ LOCAL VOID Check_Connections( VOID ) if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout ) { /* Timeout */ - Log( LOG_INFO, "Connection %d: Timeout.", i ); - Conn_Close( i, NULL, "Timeout", TRUE ); + Log( LOG_DEBUG, "Connection %d timed out ...", i ); + Conn_Close( i, NULL, "Timeout", FALSE ); } } } @@ -891,6 +990,9 @@ LOCAL VOID Check_Servers( VOID ) INT idx, i, n; RES_STAT *s; + + /* Wenn "Passive-Mode" aktiv: nicht verbinden */ + if( NGIRCd_Passive ) return; for( i = 0; i < Conf_Server_Count; i++ ) { @@ -968,7 +1070,7 @@ LOCAL VOID New_Server( INT Server, CONN_ID Idx ) return; } - Log( LOG_INFO, "Establishing connection to \"%s\", %s (connection %d) ... ", Conf_Server[Server].host, Conf_Server[Server].ip, Idx ); + 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 ); if( inet_aton( Conf_Server[Server].ip, &inaddr ) == 0 ) { @@ -990,8 +1092,13 @@ LOCAL VOID New_Server( INT Server, CONN_ID Idx ) Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); return; } - if( connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr )) < 0) + + if( ! Init_Socket( new_sock )) return; + + connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr )); + if( errno != EINPROGRESS ) { + close( new_sock ); Init_Conn_Struct( Idx ); Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno )); @@ -1008,7 +1115,7 @@ LOCAL VOID New_Server( INT Server, CONN_ID Idx ) return; } Client_SetIntroducer( c, c ); - + /* Verbindung registrieren */ My_Connections[Idx].sock = new_sock; My_Connections[Idx].addr = new_addr; @@ -1016,11 +1123,8 @@ LOCAL VOID New_Server( INT Server, CONN_ID Idx ) /* Neuen Socket registrieren */ FD_SET( new_sock, &My_Sockets ); + FD_SET( new_sock, &My_Connects ); if( new_sock > My_Max_Fd ) My_Max_Fd = new_sock; - - /* PASS und SERVER verschicken */ - Conn_WriteStr( Idx, "PASS %s "PROTOVER""PROTOSUFFIX" IRC|"PACKAGE"-"VERSION" P", Conf_Server[Server].pwd ); - Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo ); } /* New_Server */ @@ -1042,6 +1146,28 @@ LOCAL VOID Init_Conn_Struct( INT Idx ) } /* Init_Conn_Struct */ +LOCAL BOOLEAN Init_Socket( INT Sock ) +{ + /* Socket-Optionen setzen */ + + INT on = 1; + + if( fcntl( Sock, F_SETFL, O_NONBLOCK ) != 0 ) + { + Log( LOG_CRIT, "Can't enable non-blocking mode: %s!", strerror( errno )); + close( Sock ); + return FALSE; + } + if( setsockopt( Sock, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t)sizeof( on )) != 0) + { + Log( LOG_ERR, "Can't set socket options: %s!", strerror( errno )); + /* dieser Fehler kann ignoriert werden. */ + } + + return TRUE; +} /* Init_Socket */ + + LOCAL RES_STAT *ResolveAddr( struct sockaddr_in *Addr ) { /* IP (asyncron!) aufloesen. Bei Fehler, z.B. wenn der