#include "portab.h"
-static char UNUSED id[] = "$Id: conn.c,v 1.105 2002/12/17 11:46:54 alex Exp $";
+static char UNUSED id[] = "$Id: conn.c,v 1.111 2002/12/30 00:01:45 alex Exp $";
#include "imp.h"
#include <assert.h>
#ifdef USE_ZLIB
typedef struct _ZipData
{
- z_stream in; /* "Handle" fuer Input-Stream */
- z_stream out; /* "Handle" fuer Output-Stream */
- CHAR rbuf[READBUFFER_LEN]; /* Lesepuffer */
- INT rdatalen; /* Laenge der Daten im Lesepuffer (komprimiert) */
- CHAR wbuf[WRITEBUFFER_LEN]; /* Schreibpuffer */
- INT wdatalen; /* Laenge der Daten im Schreibpuffer (unkomprimiert) */
- LONG bytes_in, bytes_out; /* Counter fuer Statistik (unkomprimiert!) */
+ z_stream in; /* "Handle" for input stream */
+ z_stream out; /* "Handle" for output stream */
+ CHAR rbuf[READBUFFER_LEN]; /* Read buffer */
+ INT rdatalen; /* Length of data in read buffer (compressed) */
+ CHAR wbuf[WRITEBUFFER_LEN]; /* Write buffer */
+ INT wdatalen; /* Length of data in write buffer (uncompressed) */
+ LONG bytes_in, bytes_out; /* Counter for statistics (uncompressed!) */
} ZIPDATA;
#endif
typedef struct _Connection
{
- INT sock; /* Socket Handle */
- struct sockaddr_in addr; /* Adresse des Client */
- RES_STAT *res_stat; /* "Resolver-Status", s.o. */
+ INT sock; /* Socket handle */
+ struct sockaddr_in addr; /* Client address */
+ RES_STAT *res_stat; /* Status of resolver process, if any */
CHAR host[HOST_LEN]; /* Hostname */
- CHAR rbuf[READBUFFER_LEN]; /* Lesepuffer */
- INT rdatalen; /* Laenge der Daten im Lesepuffer */
- CHAR wbuf[WRITEBUFFER_LEN]; /* Schreibpuffer */
- INT wdatalen; /* Laenge der Daten im Schreibpuffer */
- INT our_server; /* wenn von uns zu connectender Server: ID */
- time_t starttime; /* Startzeit des Links */
- time_t lastdata; /* Letzte Aktivitaet */
- time_t lastping; /* Letzter PING */
- time_t lastprivmsg; /* Letzte PRIVMSG */
- time_t delaytime; /* Nicht beachten bis ("penalty") */
- LONG bytes_in, bytes_out; /* Empfangene uns gesendete Bytes */
- LONG msg_in, msg_out; /* Empfangene uns gesendete Nachtichten */
- INT flag; /* "Markierungs-Flag" (vgl. "irc-write"-Modul) */
- INT options; /* Link-Optionen */
+ CHAR rbuf[READBUFFER_LEN]; /* Read buffer */
+ INT rdatalen; /* Length of data in read buffer */
+ CHAR wbuf[WRITEBUFFER_LEN]; /* Write buffer */
+ INT wdatalen; /* Length of data in write buffer */
+ time_t starttime; /* Start time of link */
+ time_t lastdata; /* Last activity */
+ time_t lastping; /* Last PING */
+ time_t lastprivmsg; /* Last PRIVMSG */
+ time_t delaytime; /* Ignore link ("penalty") */
+ LONG bytes_in, bytes_out; /* Received and sent bytes */
+ LONG msg_in, msg_out; /* Received and sent IRC messages */
+ INT flag; /* Flag (see "irc-write" module) */
+ INT options; /* Link options */
#ifdef USE_ZLIB
- ZIPDATA zip; /* Kompressionsinformationen */
+ ZIPDATA zip; /* Compression information */
#endif
} CONNECTION;
LOCAL fd_set My_Connects;
LOCAL CONNECTION *My_Connections;
-LOCAL LONG Pool_Size;
+LOCAL LONG Pool_Size, WCounter;
GLOBAL VOID
/* Connection-Struktur initialisieren */
for( i = 0; i < Pool_Size; i++ ) Init_Conn_Struct( i );
+
+ /* Global write counter */
+ WCounter = 0;
} /* Conn_Init */
}
else if( idx < Pool_Size )
{
- if( NGIRCd_Restart ) Conn_Close( idx, NULL, "Server going down (restarting)", TRUE );
+ if( NGIRCd_SignalRestart ) Conn_Close( idx, NULL, "Server going down (restarting)", TRUE );
else Conn_Close( idx, NULL, "Server going down", TRUE );
}
else
BOOLEAN timeout;
start = time( NULL );
- while(( ! NGIRCd_Quit ) && ( ! NGIRCd_Restart ))
+ while(( ! NGIRCd_SignalQuit ) && ( ! NGIRCd_SignalRestart ))
{
timeout = TRUE;
-
- Check_Servers( );
+ /* Should the configuration be reloaded? */
+ if( NGIRCd_SignalRehash ) NGIRCd_Rehash( );
+
+ /* Check configured servers and established links */
+ Check_Servers( );
Check_Connections( );
/* noch volle Lese-Buffer suchen */
if( FD_ISSET( i, &read_sockets )) Handle_Read( i );
}
}
+
+ if( NGIRCd_SignalQuit ) Log( LOG_NOTICE|LOG_snotice, "Server going down NOW!" );
+ else if( NGIRCd_SignalRestart ) Log( LOG_NOTICE|LOG_snotice, "Server restarting NOW!" );
} /* Conn_Handler */
if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer );
#endif
- strcat( buffer, "\r\n" );
+ strlcat( buffer, "\r\n", sizeof( buffer ));
ok = Conn_Write( Idx, buffer, strlen( buffer ));
My_Connections[Idx].msg_out++;
My_Connections[Idx].bytes_out += Len;
}
+ /* Adjust global write counter */
+ WCounter += Len;
+
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. */
+ /* Close connection. Open pipes of asyncronous resolver
+ * sub-processes are closed down. */
CLIENT *c;
DOUBLE in_k, out_k;
assert( Idx > NONE );
assert( My_Connections[Idx].sock > NONE );
+ /* Search client, if any */
c = Client_GetFromConn( Idx );
+ /* Should the client be informed? */
if( InformClient )
{
#ifndef STRICT_RFC
- /* Statistik an Client melden, wenn User */
+ /* Send statistics to client if registered as user: */
if(( c != NULL ) && ( Client_Type( c ) == CLIENT_USER ))
{
Conn_WriteStr( Idx, "NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb.", Client_ThisServer( ), NOTICE_TXTPREFIX, (DOUBLE)My_Connections[Idx].bytes_in / 1024, (DOUBLE)My_Connections[Idx].bytes_out / 1024 );
}
#endif
- /* ERROR an Client schicken (von RFC so vorgesehen!) */
+ /* Send ERROR to client (see RFC!) */
if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg );
else Conn_WriteStr( Idx, "ERROR :Closing connection." );
if( My_Connections[Idx].sock == NONE ) return;
}
- /* zunaechst versuchen, noch im Schreibpuffer vorhandene
- * Daten auf den Socket zu schreiben ... */
+ /* Try to write out the write buffer */
Try_Write( Idx );
+ /* Shut down socket */
if( close( My_Connections[Idx].sock ) != 0 )
{
- Log( LOG_ERR, "Error closing connection %d (socket %d) with %s:%d - %s!", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port), strerror( errno ));
- }
- else
- {
- in_k = (DOUBLE)My_Connections[Idx].bytes_in / 1024;
- out_k = (DOUBLE)My_Connections[Idx].bytes_out / 1024;
-#ifdef USE_ZLIB
- if( My_Connections[Idx].options & CONN_ZIP )
- {
- in_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_in / 1024;
- out_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_out / 1024;
- in_p = (INT)(( in_k * 100 ) / in_z_k );
- out_p = (INT)(( out_k * 100 ) / out_z_k );
- Log( LOG_INFO, "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", Idx, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, in_z_k, in_p, out_k, out_z_k, out_p );
- }
- else
-#endif
- {
- Log( LOG_INFO, "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).", Idx, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, out_k );
- }
+ /* Oops, we can't close the socket!? This is fatal! */
+ Log( LOG_EMERG, "Error closing connection %d (socket %d) with %s:%d - %s!", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port), strerror( errno ));
+ Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE );
+ exit( 1 );
}
-
- /* Socket als "ungueltig" markieren */
+
+ /* Mark socket as invalid: */
FD_CLR( My_Connections[Idx].sock, &My_Sockets );
FD_CLR( My_Connections[Idx].sock, &My_Connects );
My_Connections[Idx].sock = NONE;
+ /* If there is still a client, unregister it now */
if( c ) Client_Destroy( c, LogMsg, FwdMsg, TRUE );
+ /* Calculate statistics and log information */
+ in_k = (DOUBLE)My_Connections[Idx].bytes_in / 1024;
+ out_k = (DOUBLE)My_Connections[Idx].bytes_out / 1024;
+#ifdef USE_ZLIB
+ if( My_Connections[Idx].options & CONN_ZIP )
+ {
+ in_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_in / 1024;
+ out_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_out / 1024;
+ in_p = (INT)(( in_k * 100 ) / in_z_k );
+ out_p = (INT)(( out_k * 100 ) / out_z_k );
+ Log( LOG_INFO, "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", Idx, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, in_z_k, in_p, out_k, out_z_k, out_p );
+ }
+ else
+#endif
+ {
+ Log( LOG_INFO, "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).", Idx, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, out_k );
+ }
+
+ /* Is there a resolver sub-process running? */
if( My_Connections[Idx].res_stat )
{
- /* Resolver-Strukturen freigeben, wenn noch nicht geschehen */
+ /* Free resolver structures */
FD_CLR( My_Connections[Idx].res_stat->pipe[0], &Resolver_FDs );
close( My_Connections[Idx].res_stat->pipe[0] );
close( My_Connections[Idx].res_stat->pipe[1] );
free( My_Connections[Idx].res_stat );
}
- /* Startzeit des naechsten Connect-Versuchs modifizieren? */
- if(( My_Connections[Idx].our_server > NONE ) && ( Conf_Server[My_Connections[Idx].our_server].lasttry < time( NULL ) - Conf_ConnectRetry ))
- {
- /* Okay, die Verbindung stand schon "genuegend lange":
- * lasttry-Zeitpunkt so setzen, dass der naechste
- * Verbindungsversuch in RECONNECT_DELAY Sekunden
- * gestartet wird. */
- Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY;
- }
+ /* Servers: Modify time of next connect attempt? */
+ Conf_UnsetServer( Idx );
#ifdef USE_ZLIB
- /* Ggf. zlib abmelden */
+ /* Clean up zlib, if link was compressed */
if( Conn_Options( Idx ) & CONN_ZIP )
{
inflateEnd( &My_Connections[Idx].zip.in );
}
#endif
- /* Connection-Struktur loeschen (=freigeben) */
+ /* Clean up connection structure (=free it) */
Init_Conn_Struct( Idx );
} /* Conn_Close */
} /* Conn_Next */
-GLOBAL VOID
-Conn_SetServer( CONN_ID Idx, INT ConfServer )
-{
- /* Connection als Server markieren: Index des konfigurierten
- * Servers speichern. Verbindung muss bereits bestehen! */
-
- assert( Idx > NONE );
- assert( My_Connections[Idx].sock > NONE );
-
- My_Connections[Idx].our_server = ConfServer;
-} /* Conn_SetServer */
-
-
GLOBAL VOID
Conn_SetOption( CONN_ID Idx, INT Option )
{
} /* Conn_RecvBytes */
+GLOBAL VOID
+Conn_ResetWCounter( VOID )
+{
+ WCounter = 0;
+} /* Conn_ResetWCounter */
+
+
+GLOBAL LONG
+Conn_WCounter( VOID )
+{
+ return WCounter;
+} /* Conn_WCounter */
+
+
LOCAL BOOLEAN
Try_Write( CONN_ID Idx )
{
{
/* 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 ));
+ else Log( LOG_CRIT, "Can't connect socket to \"%s:%d\" (connection %d): %s!", My_Connections[Idx].host, Conf_Server[Conf_GetServer( Idx )].port, Idx, strerror( err ));
/* Socket etc. pp. aufraeumen */
FD_CLR( My_Connections[Idx].sock, &My_Sockets );
Init_Conn_Struct( Idx );
/* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */
- Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL );
+ Conf_Server[Conf_GetServer( Idx )].lasttry = time( NULL );
+ Conf_UnsetServer( Idx );
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 );
+ Log( LOG_DEBUG, "Connection %d with \"%s:%d\" established, now sendig PASS and SERVER ...", Idx, My_Connections[Idx].host, Conf_Server[Conf_GetServer( Idx )].port );
/* PASS und SERVER verschicken */
- Conn_WriteStr( Idx, "PASS %s %s", Conf_Server[My_Connections[Idx].our_server].pwd_out, NGIRCd_ProtoID );
+ Conn_WriteStr( Idx, "PASS %s %s", Conf_Server[Conf_GetServer( Idx )].pwd_out, NGIRCd_ProtoID );
return Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
}
Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", idx, inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port), Sock );
/* Hostnamen ermitteln */
- strcpy( My_Connections[idx].host, inet_ntoa( new_addr.sin_addr ));
+ strlcpy( My_Connections[idx].host, inet_ntoa( new_addr.sin_addr ), sizeof( My_Connections[idx].host ));
Client_SetHostname( c, My_Connections[idx].host );
s = Resolve_Addr( &new_addr );
if( s )
LOCAL VOID
Check_Servers( VOID )
{
- /* Pruefen, ob Server-Verbindungen aufgebaut werden
- * muessen bzw. koennen */
+ /* Check if we can establish further server links */
RES_STAT *s;
- LONG idx, n;
- INT i;
+ CONN_ID idx;
+ INT i, n;
- /* Wenn "Passive-Mode" aktiv: nicht verbinden */
+ /* Don't connect in "passive mode" */
if( NGIRCd_Passive ) return;
- for( i = 0; i < Conf_Server_Count; i++ )
+ /* Serach all connections, are there results from the resolver? */
+ for( idx = 0; idx < Pool_Size; idx++ )
{
- /* Ist ein Hostname und Port definiert? */
- if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 )) continue;
+ if( My_Connections[idx].sock != SERVER_WAIT ) continue;
- /* Haben wir schon eine Verbindung? */
- for( n = 0; n < Pool_Size; n++ )
- {
- if( My_Connections[n].sock == NONE ) continue;
-
- /* Verbindung zu diesem Server? */
- if( My_Connections[n].our_server == i )
- {
- /* Komplett aufgebaute Verbindung? */
- if( My_Connections[n].sock > NONE ) break;
+ /* IP resolved? */
+ if( My_Connections[idx].res_stat == NULL ) New_Server( Conf_GetServer( idx ), idx );
+ }
- /* IP schon aufgeloest? */
- if( My_Connections[n].res_stat == NULL ) New_Server( i, n );
- }
+ /* Check all configured servers */
+ for( i = 0; i < MAX_SERVERS; i++ )
+ {
+ /* Valid outgoing server which isn't already connected? */
+ if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 ) || ( Conf_Server[i].conn_id > NONE )) continue;
- /* Verbindung in dieser Server-Gruppe? */
- if(( My_Connections[n].our_server != NONE ) && ( Conf_Server[i].group != NONE ))
+ /* Is there already a connection in this group? */
+ if( Conf_Server[i].group > NONE )
+ {
+ for( n = 0; n < MAX_SERVERS; n++ )
{
- if( Conf_Server[My_Connections[n].our_server].group == Conf_Server[i].group ) break;
+ 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;
}
- if( n < Pool_Size ) continue;
- /* Wann war der letzte Connect-Versuch? */
+ /* Check last connect attempt? */
if( Conf_Server[i].lasttry > time( NULL ) - Conf_ConnectRetry ) continue;
- /* Okay, Verbindungsaufbau versuchen */
+ /* Okay, try to connect now */
Conf_Server[i].lasttry = time( NULL );
- /* Freie Connection-Struktur suschen */
+ /* Search free connection structure */
for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break;
if( idx >= Pool_Size )
{
/* Verbindungs-Struktur initialisieren */
Init_Conn_Struct( idx );
My_Connections[idx].sock = SERVER_WAIT;
- My_Connections[idx].our_server = i;
+ Conf_Server[i].conn_id = idx;
- /* Hostnamen in IP aufloesen (Default bzw. im Fehlerfall: versuchen, den
- * konfigurierten Text direkt als IP-Adresse zu verwenden ... */
- strcpy( Conf_Server[My_Connections[idx].our_server].ip, Conf_Server[i].host );
- strcpy( My_Connections[idx].host, Conf_Server[i].host );
+ /* 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 );
if( s )
{
/* Verbindung registrieren */
My_Connections[Idx].sock = new_sock;
My_Connections[Idx].addr = new_addr;
- strcpy( My_Connections[Idx].host, Conf_Server[Server].host );
+ strlcpy( My_Connections[Idx].host, Conf_Server[Server].host, sizeof( My_Connections[Idx].host ));
/* Neuen Socket registrieren */
FD_SET( new_sock, &My_Sockets );
My_Connections[Idx].rdatalen = 0;
My_Connections[Idx].wbuf[0] = '\0';
My_Connections[Idx].wdatalen = 0;
- My_Connections[Idx].our_server = NONE;
My_Connections[Idx].starttime = time( NULL );
My_Connections[Idx].lastdata = time( NULL );
My_Connections[Idx].lastping = 0;
CHAR result[HOST_LEN];
CLIENT *c;
- INT len, i;
+ INT len, i, n;
FD_CLR( r_fd, &Resolver_FDs );
/* Eingehende Verbindung: Hostnamen setzen */
c = Client_GetFromConn( i );
assert( c != NULL );
- strcpy( My_Connections[i].host, result );
+ strlcpy( My_Connections[i].host, result, sizeof( My_Connections[i].host ));
Client_SetHostname( c, result );
}
else
{
/* Ausgehende Verbindung (=Server): IP setzen */
- assert( My_Connections[i].our_server > NONE );
- strcpy( Conf_Server[My_Connections[i].our_server].ip, result );
+ n = Conf_GetServer( i );
+ if( n > NONE ) strlcpy( Conf_Server[n].ip, result, sizeof( Conf_Server[n].ip ));
+ else Log( LOG_ERR, "Got resolver result for non-configured server!?" );
}
/* Penalty-Zeit zurueck setzen */