- assert( Idx > NONE );
- assert( Option != 0 );
-
- My_Connections[Idx].options &= ~Option;
-} /* Conn_UnsetOption */
-
-
-GLOBAL INT
-Conn_Options( CONN_ID Idx )
-{
- assert( Idx > NONE );
- return My_Connections[Idx].options;
-} /* Conn_Options */
-
-
-#ifdef USE_ZLIB
-
-GLOBAL BOOLEAN
-Conn_InitZip( CONN_ID Idx )
-{
- /* Kompression fuer Link initialisieren */
-
- assert( Idx > NONE );
-
- My_Connections[Idx].zip.in.avail_in = 0;
- My_Connections[Idx].zip.in.total_in = 0;
- My_Connections[Idx].zip.in.total_out = 0;
- My_Connections[Idx].zip.in.zalloc = NULL;
- My_Connections[Idx].zip.in.zfree = NULL;
- My_Connections[Idx].zip.in.data_type = Z_ASCII;
-
- if( inflateInit( &My_Connections[Idx].zip.in ) != Z_OK )
- {
- /* Fehler! */
- Log( LOG_ALERT, "Can't initialize compression on connection %d (zlib inflate)!", Idx );
- return FALSE;
- }
-
- My_Connections[Idx].zip.out.total_in = 0;
- My_Connections[Idx].zip.out.total_in = 0;
- My_Connections[Idx].zip.out.zalloc = NULL;
- My_Connections[Idx].zip.out.zfree = NULL;
- My_Connections[Idx].zip.out.data_type = Z_ASCII;
-
- if( deflateInit( &My_Connections[Idx].zip.out, Z_DEFAULT_COMPRESSION ) != Z_OK )
- {
- /* Fehler! */
- Log( LOG_ALERT, "Can't initialize compression on connection %d (zlib deflate)!", Idx );
- return FALSE;
- }
-
- My_Connections[Idx].zip.bytes_in = My_Connections[Idx].bytes_in;
- My_Connections[Idx].zip.bytes_out = My_Connections[Idx].bytes_out;
-
- Log( LOG_INFO, "Enabled link compression (zlib) on connection %d.", Idx );
- Conn_SetOption( Idx, CONN_ZIP );
-
- return TRUE;
-} /* Conn_InitZip */
-
-
-GLOBAL LONG
-Conn_SendBytesZip( CONN_ID Idx )
-{
- /* Anzahl gesendeter Bytes (komprimiert!) liefern */
-
- assert( Idx > NONE );
- return My_Connections[Idx].zip.bytes_out;
-} /* Conn_SendBytesZip */
-
-
-GLOBAL LONG
-Conn_RecvBytesZip( CONN_ID Idx )
-{
- /* Anzahl gesendeter Bytes (komprimiert!) liefern */
-
- assert( Idx > NONE );
- return My_Connections[Idx].zip.bytes_in;
-} /* Conn_RecvBytesZip */
-
-#endif
-
-
-GLOBAL time_t
-Conn_StartTime( CONN_ID Idx )
-{
- /* Zeitpunkt des Link-Starts liefern (in Sekunden) */
-
- assert( Idx > NONE );
- return My_Connections[Idx].starttime;
-} /* Conn_Uptime */
-
-
-GLOBAL INT
-Conn_SendQ( CONN_ID Idx )
-{
- /* Laenge der Daten im Schreibbuffer liefern */
-
- assert( Idx > NONE );
-#ifdef USE_ZLIB
- if( My_Connections[Idx].options & CONN_ZIP ) return My_Connections[Idx].zip.wdatalen;
- else
-#endif
- return My_Connections[Idx].wdatalen;
-} /* Conn_SendQ */
-
-
-GLOBAL LONG
-Conn_SendMsg( CONN_ID Idx )
-{
- /* Anzahl gesendeter Nachrichten liefern */
-
- assert( Idx > NONE );
- return My_Connections[Idx].msg_out;
-} /* Conn_SendMsg */
-
-
-GLOBAL LONG
-Conn_SendBytes( CONN_ID Idx )
-{
- /* Anzahl gesendeter Bytes (unkomprimiert) liefern */
-
- assert( Idx > NONE );
- return My_Connections[Idx].bytes_out;
-} /* Conn_SendBytes */
-
-
-GLOBAL INT
-Conn_RecvQ( CONN_ID Idx )
-{
- /* Laenge der Daten im Lesebuffer liefern */
-
- assert( Idx > NONE );
-#ifdef USE_ZLIB
- if( My_Connections[Idx].options & CONN_ZIP ) return My_Connections[Idx].zip.rdatalen;
- else
-#endif
- return My_Connections[Idx].rdatalen;
-} /* Conn_RecvQ */
-
-
-GLOBAL LONG
-Conn_RecvMsg( CONN_ID Idx )
-{
- /* Anzahl empfangener Nachrichten liefern */
-
- assert( Idx > NONE );
- return My_Connections[Idx].msg_in;
-} /* Conn_RecvMsg */
-
-
-GLOBAL LONG
-Conn_RecvBytes( CONN_ID Idx )
-{
- /* Anzahl empfangener Bytes (unkomprimiert) liefern */
-
- assert( Idx > NONE );
- return My_Connections[Idx].bytes_in;
-} /* 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 )
-{
- /* Versuchen, Daten aus dem Schreib-Puffer in den Socket zu
- * schreiben. TRUE wird geliefert, wenn entweder keine Daten
- * zum Versenden vorhanden sind oder erfolgreich bearbeitet
- * werden konnten. Im Fehlerfall wird FALSE geliefert und
- * die Verbindung geschlossen. */
-
- fd_set write_socket;
- struct timeval tv;
-
- assert( Idx > NONE );
- assert( My_Connections[Idx].sock > NONE );
-
- /* sind ueberhaupt Daten vorhanden? */
-#ifdef USE_ZLIB
- if(( ! My_Connections[Idx].wdatalen > 0 ) && ( ! My_Connections[Idx].zip.wdatalen )) return TRUE;
-#else
- if( ! My_Connections[Idx].wdatalen > 0 ) return TRUE;
-#endif
-
- /* Timeout initialisieren: 0 Sekunden, also nicht blockieren */
- tv.tv_sec = 0; tv.tv_usec = 0;
-
- FD_ZERO( &write_socket );
- FD_SET( My_Connections[Idx].sock, &write_socket );
- if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, &tv ) == -1 )
- {
- /* Fehler! */
- if( errno != EINTR )
- {
- Log( LOG_ALERT, "Try_Write(): select() failed: %s (con=%d, sock=%d)!", strerror( errno ), Idx, My_Connections[Idx].sock );
- Conn_Close( Idx, "Server error!", NULL, FALSE );
- return FALSE;
- }
- }
-
- if( FD_ISSET( My_Connections[Idx].sock, &write_socket )) return Handle_Write( Idx );
- else return TRUE;
-} /* Try_Write */
-
-
-LOCAL VOID
-Handle_Read( INT Sock )
-{
- /* Aktivitaet auf einem Socket verarbeiten:
- * - neue Clients annehmen,
- * - Daten von Clients verarbeiten,
- * - Resolver-Rueckmeldungen annehmen. */
-
- CONN_ID idx;
-
- assert( Sock > NONE );
-
- if( FD_ISSET( Sock, &My_Listeners ))
- {
- /* es ist einer unserer Listener-Sockets: es soll
- * also eine neue Verbindung aufgebaut werden. */
-
- New_Connection( Sock );
- }
- else if( FD_ISSET( Sock, &Resolver_FDs ))
- {
- /* Rueckmeldung von einem Resolver Sub-Prozess */
-
- Read_Resolver_Result( Sock );
- }
- else
- {
- /* Ein Client Socket: entweder ein User oder Server */
-
- idx = Socket2Index( Sock );
- if( idx > NONE ) Read_Request( idx );
- }
-} /* Handle_Read */
-
-
-LOCAL BOOLEAN
-Handle_Write( CONN_ID Idx )
-{
- /* Daten aus Schreibpuffer versenden bzw. Connection aufbauen */
-
- INT len, res, err;
-
- assert( Idx > NONE );
- 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 %s", Conf_Server[My_Connections[Idx].our_server].pwd_out, NGIRCd_ProtoID );
- return Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
- }
-
-#ifdef USE_ZLIB
- /* Schreibpuffer leer, aber noch Daten im Kompressionsbuffer?
- * Dann muss dieser nun geflushed werden! */
- if( My_Connections[Idx].wdatalen == 0 ) Zip_Flush( Idx );
-#endif
-
- assert( My_Connections[Idx].wdatalen > 0 );
-
- /* Daten schreiben */
- len = send( My_Connections[Idx].sock, My_Connections[Idx].wbuf, My_Connections[Idx].wdatalen, 0 );
- if( len < 0 )
- {
- /* Operation haette Socket "nur" blockiert ... */
- if( errno == EAGAIN ) return TRUE;
-
- /* Oops, ein Fehler! */
- Log( LOG_ERR, "Write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror( errno ));
- Conn_Close( Idx, "Write error!", NULL, FALSE );
- return FALSE;
- }
-
- /* Puffer anpassen */
- My_Connections[Idx].wdatalen -= len;
- memmove( My_Connections[Idx].wbuf, My_Connections[Idx].wbuf + len, My_Connections[Idx].wdatalen );
-
- return TRUE;
-} /* Handle_Write */
-
-
-LOCAL VOID
-New_Connection( INT Sock )
-{
- /* Neue Client-Verbindung von Listen-Socket annehmen und
- * CLIENT-Struktur anlegen. */
-
- struct sockaddr_in new_addr;
- INT new_sock, new_sock_len;
- RES_STAT *s;
- CONN_ID idx;
- CLIENT *c;
- POINTER *ptr;
- LONG new_size;
-
- assert( Sock > NONE );
-
- /* Connection auf Listen-Socket annehmen */
- new_sock_len = sizeof( new_addr );
- new_sock = accept( Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len );
- if( new_sock < 0 )
- {
- Log( LOG_CRIT, "Can't accept connection: %s!", strerror( errno ));
- return;
- }
-
- /* Socket initialisieren */
- Init_Socket( new_sock );
-
- /* Freie Connection-Struktur suchen */
- for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break;
- if( idx >= Pool_Size )
- {
- new_size = Pool_Size + CONNECTION_POOL;
-
- /* Im bisherigen Pool wurde keine freie Connection-Struktur mehr gefunden.
- * Wenn erlaubt und moeglich muss nun der Pool vergroessert werden: */
-
- if( Conf_MaxConnections > 0 )
- {
- /* Es ist ein Limit konfiguriert */
- if( Pool_Size >= Conf_MaxConnections )
- {
- /* Mehr Verbindungen duerfen wir leider nicht mehr annehmen ... */
- Log( LOG_ALERT, "Can't accept connection: limit (%d) reached!", Pool_Size );
- close( new_sock );
- return;
- }
- if( new_size > Conf_MaxConnections ) new_size = Conf_MaxConnections;
- }
-
- /* zunaechst realloc() versuchen; wenn das scheitert, malloc() versuchen
- * und Daten ggf. "haendisch" umkopieren. (Haesslich! Eine wirklich
- * dynamische Verwaltung waere wohl _deutlich_ besser ...) */
- ptr = realloc( My_Connections, sizeof( CONNECTION ) * new_size );
- if( ! ptr )
- {
- /* realloc() ist fehlgeschlagen. Nun malloc() probieren: */
- ptr = malloc( sizeof( CONNECTION ) * new_size );
- if( ! ptr )
- {
- /* Offenbar steht kein weiterer Sepeicher zur Verfuegung :-( */
- Log( LOG_EMERG, "Can't allocate memory! [New_Connection]" );
- close( new_sock );
- return;
- }
-
- /* Struktur umkopieren ... */
- memcpy( ptr, My_Connections, sizeof( CONNECTION ) * Pool_Size );
-
- Log( LOG_DEBUG, "Allocated new connection pool for %ld items (%ld bytes). [malloc()/memcpy()]", new_size, sizeof( CONNECTION ) * new_size );
- }
- else Log( LOG_DEBUG, "Allocated new connection pool for %ld items (%ld bytes). [realloc()]", new_size, sizeof( CONNECTION ) * new_size );
-
- /* Adjust pointer to new block */
- My_Connections = ptr;
-
- /* Initialize new items */
- for( idx = Pool_Size; idx < new_size; idx++ ) Init_Conn_Struct( idx );
- idx = Pool_Size;
-
- /* Adjust new pool size */
- Pool_Size = new_size;
- }
-
- /* Client-Struktur initialisieren */
- c = Client_NewLocal( idx, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWN, FALSE );
- if( ! c )
- {
- Log( LOG_ALERT, "Can't accept connection: can't create client structure!" );
- close( new_sock );
- return;
- }
-
- /* Verbindung registrieren */
- Init_Conn_Struct( idx );
- My_Connections[idx].sock = new_sock;
- My_Connections[idx].addr = new_addr;
-
- /* Neuen Socket registrieren */
- FD_SET( new_sock, &My_Sockets );
- if( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock;