X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=ef0f95fa73e8912d8e349d7c0ba71c5bd81c836d;hb=c6e3c13f27744971fcb1d2de4e561d3bcdaa5aed;hp=4a028ac7794b0fc7eeb9be7c825c0d94e506ff97;hpb=9811223fb882413645db38948ac05fa21ddd3514;p=ngircd.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 4a028ac7..ef0f95fa 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2019 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -10,6 +10,7 @@ */ #define CONN_MODULE +#define CONN_MODULE_GLOBAL_INIT #include "portab.h" @@ -182,7 +183,6 @@ cb_connserver(int sock, UNUSED short what) CONN_ID idx = Socket2Index( sock ); if (idx <= NONE) { - LogDebug("cb_connserver wants to write on unknown socket?!"); io_close(sock); return; } @@ -280,12 +280,11 @@ cb_clientserver(int sock, short what) { CONN_ID idx = Socket2Index(sock); - assert(idx >= 0); - - if (idx < 0) { + if (idx <= NONE) { io_close(sock); return; } + #ifdef SSL_SUPPORT if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) { @@ -307,32 +306,20 @@ cb_clientserver(int sock, short what) GLOBAL void Conn_Init( void ) { - CONN_ID i; - - Pool_Size = CONNECTION_POOL; - if ((Conf_MaxConnections > 0) && - (Pool_Size > Conf_MaxConnections)) - Pool_Size = Conf_MaxConnections; + int size; - if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Pool_Size)) { - Log(LOG_EMERG, "Can't allocate memory! [Conn_Init]"); + /* Initialize the "connection pool". + * FIXME: My_Connetions/Pool_Size is needed by other parts of the + * code; remove them! */ + Pool_Size = 0; + size = Conf_MaxConnections > 0 ? Conf_MaxConnections : CONNECTION_POOL; + if (Socket2Index(size) <= NONE) { + Log(LOG_EMERG, "Failed to initialize connection pool!"); exit(1); } - /* FIXME: My_Connetions/Pool_Size is needed by other parts of the - * code; remove them! */ - My_Connections = (CONNECTION*) array_start(&My_ConnArray); - - LogDebug("Allocated connection pool for %d items (%ld bytes).", - array_length(&My_ConnArray, sizeof(CONNECTION)), - array_bytes(&My_ConnArray)); - - assert(array_length(&My_ConnArray, sizeof(CONNECTION)) >= (size_t)Pool_Size); - + /* Initialize "listener" array. */ array_free( &My_Listeners ); - - for (i = 0; i < Pool_Size; i++) - Init_Conn_Struct(i); } /* Conn_Init */ /** @@ -570,8 +557,8 @@ InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port if (!ret) { assert(listen_addrstr); Log(LOG_CRIT, - "Can't bind to [%s]:%u: can't convert ip address \"%s\"!", - listen_addrstr, Port, listen_addrstr); + "Can't listen on [%s]:%u: Failed to parse IP address!", + listen_addrstr, Port); } return ret; } @@ -674,6 +661,9 @@ Conn_Handler(void) struct timeval tv; time_t t; + Log(LOG_NOTICE, "Server \"%s\" (on \"%s\") ready.", + Client_ID(Client_ThisServer()), Client_Hostname(Client_ThisServer())); + while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) { t = time(NULL); @@ -1095,9 +1085,9 @@ Conn_Close(CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClien * the calculation of in_p and out_p: in_z_k and out_z_k * are non-zero, that's guaranteed by the protocol until * compression can be enabled. */ - if (! in_z_k) + if (in_z_k <= 0) in_z_k = in_k; - if (! out_z_k) + if (out_z_k <= 0) out_z_k = out_k; in_p = (int)(( in_k * 100 ) / in_z_k ); out_p = (int)(( out_k * 100 ) / out_z_k ); @@ -1282,6 +1272,9 @@ Handle_Write( CONN_ID Idx ) if (errno == EAGAIN || errno == EINTR) return true; + /* Log write errors but do not close the connection yet. + * Calling Conn_Close() now could result in too many recursive calls. + */ if (!Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ISCLOSING)) Log(LOG_ERR, "Write error on connection %d (socket %d): %s!", @@ -1289,7 +1282,7 @@ Handle_Write( CONN_ID Idx ) else LogDebug("Recursive write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror(errno)); - Conn_Close(Idx, "Write error", NULL, false); + return false; } @@ -1378,8 +1371,8 @@ New_Connection(int Sock, UNUSED bool IsSSL) /* Check global connection limit */ if ((Conf_MaxConnections > 0) && (NumConnections >= (size_t) Conf_MaxConnections)) { - Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!", - Conf_MaxConnections); + Log(LOG_ALERT, "Can't accept new connection on socket %d: Limit (%d) reached!", + Sock, Conf_MaxConnections); Simple_Message(new_sock, "ERROR :Connection limit reached"); close(new_sock); return -1; @@ -1398,23 +1391,10 @@ New_Connection(int Sock, UNUSED bool IsSSL) return -1; } - if (new_sock >= Pool_Size) { - if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), - (size_t) new_sock)) { - Log(LOG_EMERG, - "Can't allocate memory! [New_Connection]"); - Simple_Message(new_sock, "ERROR: Internal error"); - close(new_sock); - return -1; - } - LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)", - new_sock, array_length(&My_ConnArray, - sizeof(CONNECTION)), array_bytes(&My_ConnArray)); - - /* Adjust pointer to new block */ - My_Connections = array_start(&My_ConnArray); - while (Pool_Size <= new_sock) - Init_Conn_Struct(Pool_Size++); + if (Socket2Index(new_sock) <= NONE) { + Simple_Message(new_sock, "ERROR: Internal error"); + close(new_sock); + return -1; } /* register callback */ @@ -1523,24 +1503,38 @@ Account_Connection(void) } /* Account_Connection */ /** - * Translate socket handle into connection index. + * Translate socket handle into connection index (for historical reasons, it is + * a 1:1 mapping today) and enlarge the "connection pool" accordingly. * * @param Sock Socket handle. - * @returns Connecion index or NONE, if no connection could be found. + * @returns Connecion index or NONE when the pool is too small. */ static CONN_ID Socket2Index( int Sock ) { - assert( Sock >= 0 ); + assert(Sock > 0); + assert(Pool_Size >= 0); - if( Sock >= Pool_Size || My_Connections[Sock].sock != Sock ) { - /* the Connection was already closed again, likely due to - * an error. */ - LogDebug("Socket2Index: can't get connection for socket %d!", Sock); + if (Sock < Pool_Size) + return Sock; + + /* Try to allocate more memory ... */ + if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Sock)) { + Log(LOG_EMERG, + "Can't allocate memory to enlarge connection pool!"); return NONE; } + LogDebug("Enlarged connection pool for %ld sockets (%ld items, %ld bytes)", + Sock, array_length(&My_ConnArray, sizeof(CONNECTION)), + array_bytes(&My_ConnArray)); + + /* Adjust pointer to new block, update size and initialize new items. */ + My_Connections = array_start(&My_ConnArray); + while (Pool_Size <= Sock) + Init_Conn_Struct(Pool_Size++); + return Sock; -} /* Socket2Index */ +} /** * Read data from the network to the read buffer. If an error occurs, @@ -1552,34 +1546,46 @@ static void Read_Request( CONN_ID Idx ) { ssize_t len; + size_t readbuf_limit = READBUFFER_LEN; static const unsigned int maxbps = COMMAND_LEN / 2; - char readbuf[READBUFFER_LEN]; + char readbuf[READBUFFER_MAX_LEN]; time_t t; CLIENT *c; assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); + /* Make sure that there still exists a CLIENT structure associated + * with this connection and check if this is a server or not: */ + c = Conn_GetClient(Idx); + if (c) { + /* Servers do get special read buffer limits, so they can + * process all the messages that are required while peering. */ + if (Client_Type(c) == CLIENT_SERVER) + readbuf_limit = READBUFFER_SLINK_LEN; + } else + LogDebug("Read request without client (connection %d)!?", Idx); + #ifdef ZLIB - if ((array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) || - (array_bytes(&My_Connections[Idx].zip.rbuf) >= READBUFFER_LEN)) + if ((array_bytes(&My_Connections[Idx].rbuf) >= readbuf_limit) || + (array_bytes(&My_Connections[Idx].zip.rbuf) >= readbuf_limit)) #else - if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) + if (array_bytes(&My_Connections[Idx].rbuf) >= readbuf_limit) #endif { /* Read buffer is full */ Log(LOG_ERR, "Receive buffer space exhausted (connection %d): %d/%d bytes", - Idx, array_bytes(&My_Connections[Idx].rbuf), READBUFFER_LEN); + Idx, array_bytes(&My_Connections[Idx].rbuf), readbuf_limit); Conn_Close(Idx, "Receive buffer space exhausted", NULL, false); return; } #ifdef SSL_SUPPORT if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL)) - len = ConnSSL_Read( &My_Connections[Idx], readbuf, sizeof(readbuf)); + len = ConnSSL_Read( &My_Connections[Idx], readbuf, readbuf_limit); else #endif - len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); + len = read(My_Connections[Idx].sock, readbuf, readbuf_limit); if (len == 0) { LogDebug("Client \"%s:%u\" is closing connection %d ...", My_Connections[Idx].host, @@ -1931,8 +1937,11 @@ Check_Servers(void) 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); + + /* Start resolver subprocess ... */ + if (!Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, + cb_Connect_to_Server)) + Conf_Server[i].conn_id = NONE; } } /* Check_Servers */ @@ -2007,10 +2016,7 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } - if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) { - Log(LOG_ALERT, - "Cannot allocate memory for server connection (socket %d)", - new_sock); + if (Socket2Index(new_sock) <= NONE) { close( new_sock ); Conf_Server[Server].conn_id = NONE; return; @@ -2024,8 +2030,6 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } - My_Connections = array_start(&My_ConnArray); - assert(My_Connections[new_sock].sock <= 0); Init_Conn_Struct(new_sock); @@ -2417,7 +2421,7 @@ Conn_GetFromProc(int fd) * @param Reason The reason, see THROTTLE_xxx constants. * @param Idx The connection index. * @param Client The client of this connection. - * @param Seconds The time to delay this connection. + * @param Value The time to delay this connection. */ static void Throttle_Connection(const CONN_ID Idx, CLIENT *Client, const int Reason, @@ -2472,9 +2476,7 @@ cb_clientserver_ssl(int sock, UNUSED short what) { CONN_ID idx = Socket2Index(sock); - assert(idx >= 0); - - if (idx < 0) { + if (idx <= NONE) { io_close(sock); return; } @@ -2524,12 +2526,13 @@ cb_connserver_login_ssl(int sock, short unused) { CONN_ID idx = Socket2Index(sock); - assert(idx >= 0); - if (idx < 0) { + (void) unused; + + if (idx <= NONE) { io_close(sock); return; } - (void) unused; + switch (ConnSSL_Connect( &My_Connections[idx])) { case 1: break; case 0: LogDebug("ConnSSL_Connect: not ready");