X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=e73dd3060e9d51887f21a610418c34b408e4c7f6;hp=9da618f1aee53ed6ff25a71409ad3bb0038b20b5;hb=03628dbeaf40a9de34b3eb6d5bf6dd34eed8248c;hpb=e4ffcd00bdbe6d66d419e2f364a0d2dd317202b5 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 9da618f1..e73dd306 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -7,8 +7,6 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. - * - * Connection management */ @@ -18,6 +16,11 @@ #include "conf-ssl.h" #include "io.h" +/** + * @file + * Connection management + */ + #include "imp.h" #include #ifdef PROTOTYPES @@ -68,14 +71,9 @@ #include "log.h" #include "ng_ipaddr.h" #include "parse.h" -#include "proc.h" #include "resolve.h" #include "tool.h" -#ifdef ZEROCONF -# include "rendezvous.h" -#endif - #include "exp.h" @@ -83,6 +81,7 @@ #define MAX_COMMANDS 3 #define MAX_COMMANDS_SERVER 10 +#define MAX_COMMANDS_SERVICE MAX_COMMANDS_SERVER static bool Handle_Write PARAMS(( CONN_ID Idx )); @@ -208,7 +207,7 @@ cb_connserver(int sock, UNUSED short what) if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) { /* more addresses to try... */ - New_Server(res, &Conf_Server[server].dst_addr[0]); + New_Server(server, &Conf_Server[server].dst_addr[0]); /* connection to dst_addr[0] is now in progress, so * remove this address... */ Conf_Server[server].dst_addr[0] = @@ -242,8 +241,10 @@ cb_connserver(int sock, UNUSED short what) static void server_login(CONN_ID idx) { - Log( LOG_INFO, "Connection %d with \"%s:%d\" established. Now logging in ...", idx, - My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port ); + Log(LOG_INFO, + "Connection %d (socket %d) with \"%s:%d\" established. Now logging in ...", + idx, My_Connections[idx].sock, My_Connections[idx].host, + Conf_Server[Conf_GetServer(idx)].port); io_event_setcb( My_Connections[idx].sock, cb_clientserver); io_event_add( My_Connections[idx].sock, IO_WANTREAD|IO_WANTWRITE); @@ -420,6 +421,23 @@ Conn_Exit( void ) } /* Conn_Exit */ +/** + * Close all sockets (file descriptors) of open connections. + * This is useful in forked child processes, for example, to make sure that + * they don't hold connections open that the main process wants to close. + */ +GLOBAL void +Conn_CloseAllSockets(void) +{ + CONN_ID idx; + + for(idx = 0; idx < Pool_Size; idx++) { + if(My_Connections[idx].sock > NONE) + close(My_Connections[idx].sock); + } +} + + static unsigned int ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) { @@ -461,11 +479,6 @@ Conn_InitListeners( void ) unsigned int created = 0; char *copy, *listen_addr; - if (!io_library_init(CONNECTION_POOL)) { - Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno)); - return -1; - } - assert(Conf_ListenAddress); /* can't use Conf_ListenAddress directly, see below */ @@ -504,9 +517,6 @@ Conn_ExitListeners( void ) /* Close down all listening sockets */ int *fd; size_t arraylen; -#ifdef ZEROCONF - Rendezvous_UnregisterListeners( ); -#endif arraylen = array_length(&My_Listeners, sizeof (int)); Log(LOG_INFO, @@ -563,9 +573,7 @@ NewListener(const char *listen_addr, UINT16 Port) /* Create new listening socket on specified port */ ng_ipaddr_t addr; int sock, af; -#ifdef ZEROCONF - char name[CLIENT_ID_LEN], *info; -#endif + if (!InitSinaddrListenAddr(&addr, listen_addr, Port)) return -1; @@ -601,38 +609,8 @@ NewListener(const char *listen_addr, UINT16 Port) return -1; } - Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); - -#ifdef ZEROCONF - /* Get best server description text */ - if( ! Conf_ServerInfo[0] ) info = Conf_ServerName; - else - { - /* Use server info string */ - info = NULL; - if( Conf_ServerInfo[0] == '[' ) - { - /* Cut off leading hostname part in "[]" */ - info = strchr( Conf_ServerInfo, ']' ); - if( info ) - { - info++; - while( *info == ' ' ) info++; - } - } - if( ! info ) info = Conf_ServerInfo; - } - - /* Add port number to description if non-standard */ - if (Port != 6667) - snprintf(name, sizeof name, "%s (port %u)", info, - (unsigned int)Port); - else - strlcpy(name, info, sizeof name); - - /* Register service */ - Rendezvous_Register( name, MDNS_TYPE, Port ); -#endif + Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", + ng_ipaddr_tostr(&addr), Port, sock); return sock; } /* NewListener */ @@ -670,9 +648,11 @@ SSL_WantWrite(const CONNECTION *c) } #else static inline bool -SSL_WantRead(UNUSED const CONNECTION *c) { return false; } +SSL_WantRead(UNUSED const CONNECTION *c) +{ return false; } static inline bool -SSL_WantWrite(UNUSED const CONNECTION *c) { return false; } +SSL_WantWrite(UNUSED const CONNECTION *c) +{ return false; } #endif @@ -695,14 +675,6 @@ Conn_Handler(void) while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) { t = time(NULL); -#ifdef ZEROCONF - Rendezvous_Handler(); -#endif - - /* Should the configuration be reloaded? */ - if (NGIRCd_SignalRehash) - NGIRCd_Rehash(); - /* Check configured servers and established links */ Check_Servers(); Check_Connections(); @@ -889,7 +861,7 @@ static bool Conn_Write( CONN_ID Idx, char *Data, size_t Len ) { CLIENT *c; - size_t writebuf_limit = WRITEBUFFER_LEN; + size_t writebuf_limit = WRITEBUFFER_MAX_LEN; assert( Idx > NONE ); assert( Data != NULL ); assert( Len > 0 ); @@ -925,7 +897,7 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len ) /* Uncompressed link: * Check if outbound buffer has enough space for the data. */ if (array_bytes(&My_Connections[Idx].wbuf) + Len >= - writebuf_limit) { + WRITEBUFFER_FLUSH_LEN) { /* Buffer is full, flush it. Handle_Write deals with * low-level errors, if any. */ if (!Handle_Write(Idx)) @@ -937,8 +909,8 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len ) if (array_bytes(&My_Connections[Idx].wbuf) + Len >= writebuf_limit) { Log(LOG_NOTICE, - "Write buffer overflow (connection %d, size %lu byte)!", - Idx, + "Write buffer overflow (connection %d, limit is %lu bytes, %lu bytes new, %lu bytes pending)!", + Idx, writebuf_limit, Len, (unsigned long)array_bytes(&My_Connections[Idx].wbuf)); Conn_Close(Idx, "Write buffer overflow!", NULL, false); return false; @@ -1011,7 +983,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie if (FwdMsg) Conn_WriteStr(Idx, "ERROR :%s", FwdMsg); else - Conn_WriteStr(Idx, "ERROR :Closing connection."); + Conn_WriteStr(Idx, "ERROR :Closing connection"); } /* Try to write out the write buffer. Note: Handle_Write() eventually @@ -1075,10 +1047,6 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie in_k, out_k); } - /* Kill possibly running subprocess */ - if (Proc_InProgress(&My_Connections[Idx].proc_stat)) - Proc_Kill(&My_Connections[Idx].proc_stat); - /* Servers: Modify time of next connect attempt? */ Conf_UnsetServer( Idx ); @@ -1127,32 +1095,32 @@ Conn_CountAccepted(void) } /* Conn_CountAccepted */ +/** + * Synchronize established connections and configured server structures + * after a configuration update and store the correct connection IDs, if any. + */ GLOBAL void -Conn_SyncServerStruct( void ) +Conn_SyncServerStruct(void) { - /* Synchronize server structures (connection IDs): - * connections <-> configuration */ - CLIENT *client; CONN_ID i; int c; - for( i = 0; i < Pool_Size; i++ ) { - /* Established connection? */ - if (My_Connections[i].sock < 0) + for (i = 0; i < Pool_Size; i++) { + if (My_Connections[i].sock == NONE) continue; - /* Server connection? */ - client = Conn_GetClient( i ); - if(( ! client ) || ( Client_Type( client ) != CLIENT_SERVER )) continue; + /* Server link? */ + client = Conn_GetClient(i); + if (!client || Client_Type(client) != CLIENT_SERVER) + continue; - for( c = 0; c < MAX_SERVERS; c++ ) - { + for (c = 0; c < MAX_SERVERS; c++) { /* Configured server? */ - if( ! Conf_Server[c].host[0] ) continue; + if (!Conf_Server[c].host[0]) + continue; - /* Duplicate? */ - if( strcmp( Conf_Server[c].name, Client_ID( client )) == 0 ) + if (strcasecmp(Conf_Server[c].name, Client_ID(client)) == 0) Conf_Server[c].conn_id = i; } } @@ -1311,7 +1279,7 @@ New_Connection(int Sock) "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt); Simple_Message(new_sock, - "ERROR :Connection refused, too many connections from your IP address!"); + "ERROR :Connection refused, too many connections from your IP address"); close(new_sock); return -1; } @@ -1375,10 +1343,10 @@ New_Connection(int Sock) identsock = new_sock; #ifdef IDENTAUTH - if (Conf_NoIdent) + if (!Conf_Ident) identsock = -1; #endif - if (!Conf_NoDNS) + if (Conf_DNS) Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr, identsock, cb_Read_Resolver_Result); @@ -1490,27 +1458,34 @@ Read_Request( CONN_ID Idx ) /* Update connection statistics */ My_Connections[Idx].bytes_in += len; + My_Connections[Idx].bps += Handle_Buffer(Idx); + + /* Make sure that there is still a valid client registered */ + c = Conn_GetClient(Idx); + if (!c) + return; /* 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(). - * Set "lastping", too, so we can handle time shifts backwards ... */ - c = Conn_GetClient(Idx); - if (c && (Client_Type(c) == CLIENT_USER - || Client_Type(c) == CLIENT_SERVER - || Client_Type(c) == CLIENT_SERVICE)) { + * Update "lastping", too, if time shifted backwards ... */ + if (Client_Type(c) == CLIENT_USER + || Client_Type(c) == CLIENT_SERVER + || Client_Type(c) == CLIENT_SERVICE) { t = time(NULL); if (My_Connections[Idx].lastdata != t) My_Connections[Idx].bps = 0; My_Connections[Idx].lastdata = t; - My_Connections[Idx].lastping = My_Connections[Idx].lastdata; + if (My_Connections[Idx].lastping > t) + My_Connections[Idx].lastping = t; } /* Look at the data in the (read-) buffer of this connection */ - My_Connections[Idx].bps += Handle_Buffer(Idx); if (Client_Type(c) != CLIENT_SERVER + && Client_Type(c) != CLIENT_UNKNOWNSERVER + && Client_Type(c) != CLIENT_SERVICE && My_Connections[Idx].bps >= maxbps) { LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)", Idx, My_Connections[Idx].bps, maxbps); @@ -1522,7 +1497,7 @@ Read_Request( CONN_ID Idx ) /** * Handle all data in the connection read-buffer. * Data is processed until no complete command is left in the read buffer, - * or MAX_COMMANDS[_SERVER] commands were processed. + * or MAX_COMMANDS[_SERVER|_SERVICE] commands were processed. * When a fatal error occurs, the connection is shut down. * @param Idx Index of the connection. * @return number of bytes processed. @@ -1547,8 +1522,12 @@ Handle_Buffer(CONN_ID Idx) /* Servers do get special command limits, so they can process * all the messages that are required while peering. */ - if (Client_Type(c) == CLIENT_SERVER) - maxcmd = MAX_COMMANDS_SERVER; + switch (Client_Type(c)) { + case CLIENT_SERVER: + maxcmd = MAX_COMMANDS_SERVER; break; + case CLIENT_SERVICE: + maxcmd = MAX_COMMANDS_SERVICE; break; + } starttime = time(NULL); for (i=0; i < maxcmd; i++) { @@ -1673,11 +1652,14 @@ Handle_Buffer(CONN_ID Idx) } /* Handle_Buffer */ +/** + * Check whether established connections are still alive or not. + * If not, play PING-PONG first; and if that doesn't help either, + * disconnect the respective peer. + */ static void Check_Connections(void) { - /* check if connections are alive. if not, play PING-PONG first. - * if this doesn't help either, disconnect client. */ CLIENT *c; CONN_ID i; char msg[64]; @@ -1729,42 +1711,50 @@ Check_Connections(void) } /* Check_Connections */ +/** + * Check if further server links should be established. + */ static void -Check_Servers( void ) +Check_Servers(void) { - /* Check if we can establish further server links */ - int i, n; time_t time_now; + time_now = time(NULL); + /* Check all configured servers */ - 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; + for (i = 0; i < MAX_SERVERS; i++) { + if (Conf_Server[i].conn_id != NONE) + continue; /* Already establishing or connected */ + if (!Conf_Server[i].host[0] || !Conf_Server[i].port > 0) + continue; /* No host and/or port configured */ + if (Conf_Server[i].flags & CONF_SFLAG_DISABLED) + continue; /* Disabled configuration entry */ + if (Conf_Server[i].lasttry > (time_now - Conf_ConnectRetry)) + continue; /* We have to wait a little bit ... */ /* Is there already a connection in this group? */ - if( Conf_Server[i].group > NONE ) { + if (Conf_Server[i].group > NONE) { for (n = 0; n < MAX_SERVERS; n++) { - if (n == i) continue; + if (n == i) + continue; if ((Conf_Server[n].conn_id != NONE) && - (Conf_Server[n].group == Conf_Server[i].group)) - break; + (Conf_Server[n].group == Conf_Server[i].group)) + break; } - if (n < MAX_SERVERS) continue; + if (n < MAX_SERVERS) + continue; } - /* Check last connect attempt? */ - time_now = time(NULL); - if( Conf_Server[i].lasttry > (time_now - Conf_ConnectRetry)) - continue; - /* Okay, try to connect now */ + Log(LOG_NOTICE, + "Preparing to establish a new server link for \"%s\" ...", + Conf_Server[i].name); Conf_Server[i].lasttry = time_now; Conf_Server[i].conn_id = SERVER_WAIT; assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0); - Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, cb_Connect_to_Server); + Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, + cb_Connect_to_Server); } } /* Check_Servers */ @@ -1784,13 +1774,17 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } - Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", - Conf_Server[Server].host, ip_str, Conf_Server[Server].port ); - af_dest = ng_ipaddr_af(dest); new_sock = socket(af_dest, SOCK_STREAM, 0); + + Log(LOG_INFO, + "Establishing connection for \"%s\" to \"%s:%d\" (%s), socket %d ...", + Conf_Server[Server].name, Conf_Server[Server].host, + Conf_Server[Server].port, ip_str, new_sock); + if (new_sock < 0) { - Log( LOG_CRIT, "Can't create socket (af %d) : %s!", af_dest, strerror( errno )); + Log(LOG_CRIT, "Can't create socket (af %d): %s!", + af_dest, strerror(errno)); return; } @@ -1917,8 +1911,8 @@ Init_Socket( int Sock ) LogDebug("Setting IP_TOS on socket %d to IPTOS_LOWDELAY.", Sock); if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value, (socklen_t) sizeof(value))) { - Log(LOG_ERR, "Can't set socket option IP_TOS: %s!", - strerror(errno)); + LogDebug("Can't set socket option IP_TOS: %s!", + strerror(errno)); /* ignore this error */ } #endif @@ -1953,9 +1947,12 @@ cb_Connect_to_Server(int fd, UNUSED short events) } /* Read result from pipe */ - len = Resolve_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs)); - if (len == 0) + len = Proc_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs)); + if (len == 0) { + /* Error resolving hostname: reset server structure */ + Conf_Server[i].conn_id = NONE; return; + } assert((len % sizeof(ng_ipaddr_t)) == 0); @@ -2006,7 +2003,7 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) } /* Read result from pipe */ - len = Resolve_Read(&My_Connections[i].proc_stat, readbuf, sizeof readbuf -1); + len = Proc_Read(&My_Connections[i].proc_stat, readbuf, sizeof readbuf -1); if (len == 0) return; @@ -2099,6 +2096,22 @@ Conn_GetClient( CONN_ID Idx ) return c ? c->client : NULL; } +/** + * Get PROC_STAT sub-process structure of a connection. + * @param Idx Connection index number + * @return PROC_STAT structure + */ +GLOBAL PROC_STAT * +Conn_GetProcStat(CONN_ID Idx) +{ + CONNECTION *c; + + assert(Idx >= 0); + c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx); + assert(c != NULL); + return &c->proc_stat; +} /* Conn_GetProcStat */ + /** * Get CONN_ID from file descriptor associated to a subprocess structure. @@ -2156,4 +2169,28 @@ Conn_UsesSSL(CONN_ID Idx) #endif +#ifdef DEBUG + +GLOBAL void +Conn_DebugDump(void) +{ + int i; + + Log(LOG_DEBUG, "Connection status:"); + for (i = 0; i < Pool_Size; i++) { + if (My_Connections[i].sock == NONE) + continue; + Log(LOG_DEBUG, + " - %d: host=%s, lastdata=%ld, lastping=%ld, delaytime=%ld, flag=%d, options=%d, bps=%d, client=%s", + My_Connections[i].sock, My_Connections[i].host, + My_Connections[i].lastdata, My_Connections[i].lastping, + My_Connections[i].delaytime, My_Connections[i].flag, + My_Connections[i].options, My_Connections[i].bps, + My_Connections[i].client ? Client_ID(My_Connections[i].client) : "-"); + } +} /* Conn_DumpClients */ + +#endif + + /* -eof- */