]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
Read_Request(): Clean up code and add some more comments
[ngircd-alex.git] / src / ngircd / conn.c
index 6b3b51eaf5c10dc6b8555d8a99b53dee3b178a79..7d1576e1efcb4ec9b1cbcaf4f7fdd92093b31405 100644 (file)
@@ -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);
 
@@ -796,7 +786,7 @@ Conn_Handler(void)
 GLOBAL bool
 Conn_WriteStr(CONN_ID Idx, const char *Format, ...)
 #else
-GLOBAL bool 
+GLOBAL bool
 Conn_WriteStr(Idx, Format, va_alist)
 CONN_ID Idx;
 const char *Format;
@@ -829,7 +819,7 @@ va_dcl
                 * IRC_WriteXXX() functions when the prefix of this server had
                 * to be added to an already "quite long" command line which
                 * has been received from a regular IRC client, for example.
-                * 
+                *
                 * We are not allowed to send such "oversized" messages to
                 * other servers and clients, see RFC 2812 2.3 and 2813 3.3
                 * ("these messages SHALL NOT exceed 512 characters in length,
@@ -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,
@@ -1549,15 +1543,16 @@ Socket2Index( int Sock )
  * @param Idx  Connection index.
  */
 static void
-Read_Request( CONN_ID Idx )
+Read_Request(CONN_ID Idx)
 {
        ssize_t len;
        static const unsigned int maxbps = COMMAND_LEN / 2;
        char readbuf[READBUFFER_LEN];
        time_t t;
        CLIENT *c;
-       assert( Idx > NONE );
-       assert( My_Connections[Idx].sock > NONE );
+
+       assert(Idx > NONE);
+       assert(My_Connections[Idx].sock > NONE);
 
 #ifdef ZLIB
        if ((array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) ||
@@ -1574,28 +1569,37 @@ Read_Request( CONN_ID Idx )
                return;
        }
 
+       /* Now read new data from the network, up to READBUFFER_LEN bytes ... */
 #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, sizeof(readbuf));
        else
 #endif
-       len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
+               len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
+
        if (len == 0) {
                LogDebug("Client \"%s:%u\" is closing connection %d ...",
                         My_Connections[Idx].host,
-                        ng_ipaddr_tostr(&My_Connections[Idx].addr), Idx);
+                        ng_ipaddr_getport(&My_Connections[Idx].addr), Idx);
                Conn_Close(Idx, NULL, "Client closed connection", false);
                return;
        }
 
        if (len < 0) {
-               if( errno == EAGAIN ) return;
+               if (errno == EAGAIN)
+                       return;
+
                Log(LOG_ERR, "Read error on connection %d (socket %d): %s!",
                    Idx, My_Connections[Idx].sock, strerror(errno));
                Conn_Close(Idx, "Read error", "Client closed connection",
                           false);
                return;
        }
+
+       /* Now append the newly received data to the connection buffer.
+        * NOTE: This can lead to connection read buffers being bigger(!) than
+        * READBUFFER_LEN bytes, as we add up to READBUFFER_LEN new bytes to a
+        * buffer possibly being "almost" READBUFFER_LEN bytes already! */
 #ifdef ZLIB
        if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) {
                if (!array_catb(&My_Connections[Idx].zip.rbuf, readbuf,
@@ -1931,8 +1935,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 +2014,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 +2028,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);
@@ -2364,7 +2366,7 @@ Simple_Message(int Sock, const char *Msg)
  * @returns    Pointer to CLIENT structure.
  */
 GLOBAL CLIENT *
-Conn_GetClient( CONN_ID Idx ) 
+Conn_GetClient( CONN_ID Idx )
 {
        CONNECTION *c;
 
@@ -2417,7 +2419,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 +2474,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 +2524,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");