#include "portab.h"
#include "io.h"
-static char UNUSED id[] = "$Id: conn.c,v 1.167 2005/07/29 09:29:47 fw Exp $";
+static char UNUSED id[] = "$Id: conn.c,v 1.177 2005/09/02 13:28:30 alex Exp $";
#include "imp.h"
#include <assert.h>
#define SERVER_WAIT (NONE - 1)
-LOCAL bool Handle_Write PARAMS(( CONN_ID Idx ));
-LOCAL int New_Connection PARAMS(( int Sock ));
-LOCAL CONN_ID Socket2Index PARAMS(( int Sock ));
-LOCAL void Read_Request PARAMS(( CONN_ID Idx ));
-LOCAL bool Handle_Buffer PARAMS(( CONN_ID Idx ));
-LOCAL void Check_Connections PARAMS(( void ));
-LOCAL void Check_Servers PARAMS(( void ));
-LOCAL void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
-LOCAL bool Init_Socket PARAMS(( int Sock ));
-LOCAL void New_Server PARAMS(( int Server, CONN_ID Idx ));
-LOCAL void Simple_Message PARAMS(( int Sock, char *Msg ));
-LOCAL int Count_Connections PARAMS(( struct sockaddr_in addr ));
-LOCAL int NewListener PARAMS(( const UINT16 Port ));
+static bool Handle_Write PARAMS(( CONN_ID Idx ));
+static int New_Connection PARAMS(( int Sock ));
+static CONN_ID Socket2Index PARAMS(( int Sock ));
+static void Read_Request PARAMS(( CONN_ID Idx ));
+static bool Handle_Buffer PARAMS(( CONN_ID Idx ));
+static void Check_Connections PARAMS(( void ));
+static void Check_Servers PARAMS(( void ));
+static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
+static bool Init_Socket PARAMS(( int Sock ));
+static void New_Server PARAMS(( int Server, CONN_ID Idx ));
+static void Simple_Message PARAMS(( int Sock, char *Msg ));
+static int Count_Connections PARAMS(( struct sockaddr_in addr ));
+static int NewListener PARAMS(( const UINT16 Port ));
static array My_Listeners;
}
-LOCAL void
+static void
FreeRes_stat( CONNECTION *c )
{
assert( c != NULL );
/* return new listening port file descriptor or -1 on failure */
-LOCAL int
+static int
NewListener( const UINT16 Port )
{
/* Create new listening socket on specified port */
c = Client_GetFromConn( Idx );
/* Should the client be informed? */
- if( InformClient )
- {
+ if (InformClient) {
#ifndef STRICT_RFC
/* 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 );
+ if ((c != NULL) && (Client_Type(c) == CLIENT_USER)) {
+ Conn_WriteStr( Idx,
+ ":%s NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb.",
+ Client_ID(Client_ThisServer()), Client_ID(c),
+ NOTICE_TXTPREFIX,
+ (double)My_Connections[Idx].bytes_in / 1024,
+ (double)My_Connections[Idx].bytes_out / 1024);
}
#endif
/* Send ERROR to client (see RFC!) */
- if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg );
- else Conn_WriteStr( Idx, "ERROR :Closing connection." );
+ if (FwdMsg)
+ Conn_WriteStr(Idx, "ERROR :%s", FwdMsg);
+ else
+ Conn_WriteStr(Idx, "ERROR :Closing connection.");
}
/* Try to write out the write buffer */
} /* SyncServerStruct */
-LOCAL bool
+static bool
Handle_Write( CONN_ID Idx )
{
/* Daten aus Schreibpuffer versenden bzw. Connection aufbauen */
int len;
unsigned int wdatalen;
- Log(LOG_DEBUG, "Handle_Write");
assert( Idx > NONE );
if ( My_Connections[Idx].sock < 0 ) {
- Log(LOG_WARNING, "Handle_Write() on closed socket, idx %d", Idx);
+ Log(LOG_WARNING,
+ "Handle_Write() on closed socket, connection %d", Idx);
return false;
}
assert( My_Connections[Idx].sock > NONE );
+#ifdef DEBUG
+ Log(LOG_DEBUG, "Handle_Write() called for connection %d ...", Idx);
+#endif
+
wdatalen = array_bytes(&My_Connections[Idx].wbuf );
#ifdef ZLIB
- if(( wdatalen == 0 ) && ( ! array_bytes(&My_Connections[Idx].zip.wbuf))) {
+ if (wdatalen == 0 && !array_bytes(&My_Connections[Idx].zip.wbuf)) {
io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
return true;
}
- /* write buffer empty, but not compression buf? -> flush compression buf. */
- if( wdatalen == 0 ) Zip_Flush( Idx );
+ /* write buffer empty, but not compression buffer?
+ * -> flush compression buffer! */
+ if (wdatalen == 0)
+ Zip_Flush(Idx);
#else
- if( wdatalen == 0 ) {
+ if (wdatalen == 0) {
io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
return true;
}
#endif
- wdatalen = array_bytes(&My_Connections[Idx].wbuf ); /* Zip_Flush may change wbuf */
- len = write( My_Connections[Idx].sock, array_start(&My_Connections[Idx].wbuf), wdatalen );
+ /* Zip_Flush() may have changed the write buffer ... */
+ wdatalen = array_bytes(&My_Connections[Idx].wbuf);
+
+ len = write(My_Connections[Idx].sock,
+ array_start(&My_Connections[Idx].wbuf), wdatalen );
+
if( len < 0 ) {
- if( errno == EAGAIN || errno == EINTR)
+ if (errno == EAGAIN || errno == EINTR)
return true;
- 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 );
+ 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;
}
} /* Handle_Write */
-LOCAL int
+static int
New_Connection( int Sock )
{
/* Neue Client-Verbindung von Listen-Socket annehmen und
} /* New_Connection */
-LOCAL CONN_ID
+static CONN_ID
Socket2Index( int Sock )
{
/* zum Socket passende Connection suchen */
} /* Socket2Index */
-LOCAL void
+static void
Read_Request( CONN_ID Idx )
{
/* Daten von Socket einlesen und entsprechend behandeln.
int len;
char readbuf[1024];
+ CLIENT *c;
assert( Idx > NONE );
assert( My_Connections[Idx].sock > NONE );
}
}
- /* Connection-Statistik aktualisieren */
+ /* Update connection statistics */
My_Connections[Idx].bytes_in += len;
- /* Timestamp aktualisieren */
- My_Connections[Idx].lastdata = time( NULL );
-
- Handle_Buffer( Idx );
+ /* Update timestamp of last data received if this connection is
+ * registered as a user, server or service connection. Don't update
+ * otherwise, so users have at least Conf_PongTimeout seconds time to
+ * register with the IRC server -- see Check_Connections(). */
+ c = Client_GetFromConn(Idx);
+ if (c && (Client_Type(c) == CLIENT_USER
+ || Client_Type(c) == CLIENT_SERVER
+ || Client_Type(c) == CLIENT_SERVICE))
+ My_Connections[Idx].lastdata = time(NULL);
+
+ /* Look at the data in the (read-) buffer of this connection */
+ Handle_Buffer(Idx);
} /* Read_Request */
-LOCAL bool
+static bool
Handle_Buffer( CONN_ID Idx )
{
/* Handle Data in Connections Read-Buffer.
#endif
char *ptr;
int len, delta;
- bool action, result;
+ bool result;
#ifdef ZLIB
bool old_z;
#endif
result = false;
- do {
+ for (;;) {
/* Check penalty */
if( My_Connections[Idx].delaytime > time( NULL )) return result;
#ifdef ZLIB
}
#endif
- action = false;
if( ! ptr )
break;
return false;
}
+ if (len <= 2) { /* request was empty (only '\r\n') */
+ array_moveleft(&My_Connections[Idx].rbuf, 1, delta); /* delta is either 1 or 2 */
+ break;
+ }
#ifdef ZLIB
/* remember if stream is already compressed */
old_z = My_Connections[Idx].options & CONN_ZIP;
#endif
- if( len > delta )
- {
- /* A Request was read */
- My_Connections[Idx].msg_in++;
- if( ! Parse_Request( Idx, (char*)array_start(&My_Connections[Idx].rbuf) )) return false;
- else action = true;
+ My_Connections[Idx].msg_in++;
+ if (!Parse_Request(Idx, (char*)array_start(&My_Connections[Idx].rbuf) ))
+ return false;
+
+ result = true;
- array_moveleft(&My_Connections[Idx].rbuf, 1, len);
+ array_moveleft(&My_Connections[Idx].rbuf, 1, len);
#ifdef DEBUG
- Log(LOG_DEBUG, "%d byte left in rbuf", array_bytes(&My_Connections[Idx].rbuf));
+ Log(LOG_DEBUG,
+ "Connection %d: %d bytes left in read buffer.",
+ Idx, array_bytes(&My_Connections[Idx].rbuf));
#endif
- }
-
#ifdef ZLIB
- if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) && ( array_bytes(&My_Connections[Idx].rbuf) > 0 ))
+ if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) &&
+ ( array_bytes(&My_Connections[Idx].rbuf) > 0 ))
{
/* The last Command activated Socket-Compression.
* Data that was read after that needs to be copied to Unzip-buf
* for decompression */
if( array_bytes(&My_Connections[Idx].rbuf)> ZREADBUFFER_LEN ) {
- /* No space left */
- Log( LOG_ALERT, "Can't move receive buffer: No space left in unzip buffer (need %d bytes)!", array_bytes(&My_Connections[Idx].rbuf ));
+ Log( LOG_ALERT, "Connection %d: No space left in unzip buf (need %u bytes)!",
+ Idx, array_bytes(&My_Connections[Idx].rbuf ));
return false;
}
if (!array_copy( &My_Connections[Idx].zip.rbuf, &My_Connections[Idx].rbuf ))
array_trunc(&My_Connections[Idx].rbuf);
#ifdef DEBUG
- Log( LOG_DEBUG, "Moved already received data (%d bytes) to uncompression buffer.", array_bytes(&My_Connections[Idx].zip.rbuf));
+ Log( LOG_DEBUG, "Moved already received data (%u bytes) to uncompression buffer.",
+ array_bytes(&My_Connections[Idx].zip.rbuf));
#endif /* DEBUG */
}
#endif /* ZLIB */
- if( action ) result = true;
- } while( action );
+ }
return result;
} /* Handle_Buffer */
-LOCAL void
+static void
Check_Connections( void )
{
/* check if connections are alive. if not, play PING-PONG first.
}
else
{
- /* connection is not fully established yet */
- if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
- {
- /* Timeout */
+ /* The connection is not fully established yet, so
+ * we don't do the PING-PONG game here but instead
+ * disconnect the client after "a short time" if it's
+ * still not registered. */
+
+ if (My_Connections[i].lastdata <
+ time(NULL) - Conf_PongTimeout) {
#ifdef DEBUG
- Log( LOG_DEBUG, "Connection %d timed out ...", i );
+ Log(LOG_DEBUG,
+ "Unregistered connection %d timed out ...",
+ i);
#endif
- Conn_Close( i, NULL, "Timeout", false );
+ Conn_Close(i, NULL, "Timeout", false);
}
}
}
} /* Check_Connections */
-LOCAL void
+static void
Check_Servers( void )
{
/* Check if we can establish further server links */
CONN_ID idx;
int i, n;
- /* Serach all connections, are there results from the resolver? */
- for( idx = 0; idx < Pool_Size; idx++ )
- {
+ /* Search all connections, are there results from the resolver? */
+ for( idx = 0; idx < Pool_Size; idx++ ) {
if( My_Connections[idx].sock != SERVER_WAIT ) continue;
/* IP resolved? */
}
/* Check all configured servers */
- for( i = 0; i < MAX_SERVERS; i++ )
- {
+ 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;
+ 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( 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(( Conf_Server[n].conn_id > NONE ) &&
+ ( Conf_Server[n].group == Conf_Server[i].group ))
+ break;
}
- if( n < MAX_SERVERS ) continue;
+ if (n < MAX_SERVERS) continue;
}
/* Check last connect attempt? */
} /* Check_Servers */
-LOCAL void
+static void
New_Server( int Server, CONN_ID Idx )
{
/* Establish new server link */
/* 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_ERR, "Can't connect to \"%s\": ip address unknown!", Conf_Server[Server].host );
+ Init_Conn_Struct( Idx );
+ Conf_Server[Server].conn_id = NONE;
+ return;
}
- 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 );
+ Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", Conf_Server[Server].host,
+ Conf_Server[Server].ip, Conf_Server[Server].port );
#ifdef HAVE_INET_ATON
if( inet_aton( Conf_Server[Server].ip, &inaddr ) == 0 )
} /* New_Server */
-LOCAL void
+static void
Init_Conn_Struct( CONN_ID Idx )
{
time_t now = time( NULL );
} /* Init_Conn_Struct */
-LOCAL bool
+static bool
Init_Socket( int Sock )
{
/* Initialize socket (set options) */
char *bufptr;
char readbuf[HOST_LEN];
- Log( LOG_DEBUG, "Resolver: started, fd %d\n", r_fd );
+ Log( LOG_DEBUG, "Resolver: started, fd %d", r_fd );
/* Search associated connection ... */
- for( i = 0; i < Pool_Size; i++ )
- {
+ 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 ))
} /* Read_Resolver_Result */
-LOCAL void
+static void
Simple_Message( int Sock, char *Msg )
{
char buf[COMMAND_LEN];
} /* Simple_Error */
-LOCAL int
+static int
Count_Connections( struct sockaddr_in addr_in )
{
int i, cnt;