]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
Connection functions: add some more documentation comments
[ngircd-alex.git] / src / ngircd / conn.c
index cd5921a46d7206e4b9009b58e310280354670b7d..7b07114b0730fede7080ae8246bc8c3dcbabbf92 100644 (file)
@@ -109,10 +109,17 @@ extern struct SSLOptions Conf_SSLOptions;
 static void cb_connserver_login_ssl PARAMS((int sock, short what));
 static void cb_clientserver_ssl PARAMS((int sock, short what));
 #endif
-static void cb_Read_Resolver_Result PARAMS(( int sock, UNUSED short what));
-static void cb_Connect_to_Server PARAMS(( int sock, UNUSED short what));
+static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what));
+static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what));
 static void cb_clientserver PARAMS((int sock, short what));
 
+
+/**
+ * IO callback for listening sockets: handle new connections. This callback
+ * gets called when a new non-SSL connection should be accepted.
+ * @param sock Socket descriptor
+ * @param irrelevant (ignored IO specification)
+ */
 static void
 cb_listen(int sock, short irrelevant)
 {
@@ -124,10 +131,17 @@ cb_listen(int sock, short irrelevant)
 
 
 #ifdef SSL_SUPPORT
+/**
+ * IO callback for listening SSL sockets: handle new connections. This callback
+ * gets called when a new SSL-enabled connection should be accepted.
+ * @param sock Socket descriptor
+ * @param irrelevant (ignored IO specification)
+ */
 static void
 cb_listen_ssl(int sock, short irrelevant)
 {
        int fd;
+
        (void) irrelevant;
        fd = New_Connection(sock);
        if (fd < 0)
@@ -140,24 +154,41 @@ cb_listen_ssl(int sock, short irrelevant)
 #endif
 
 
+/**
+ * IO callback for new outgoing non-SSL server connections.
+ * @param sock Socket descriptor
+ * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
+ */
 static void
 cb_connserver(int sock, UNUSED short what)
 {
-       int res, err;
+       int res, err, server;
        socklen_t sock_len;
        CONN_ID idx = Socket2Index( sock );
+
        if (idx <= NONE) {
                LogDebug("cb_connserver wants to write on unknown socket?!");
                io_close(sock);
                return;
        }
 
-       assert( what & IO_WANTWRITE);
+       assert(what & IO_WANTWRITE);
+
+       /* Make sure that the server is still configured; it could have been
+        * removed in the meantime! */
+       server = Conf_GetServer(idx);
+       if (server < 0) {
+               Log(LOG_ERR, "Connection on socket %d to \"%s\" aborted!",
+                   sock, My_Connections[idx].host);
+               Conn_Close(idx, "Connection aborted!", NULL, false);
+               return;
+       }
 
        /* connect() finished, get result. */
        sock_len = (socklen_t)sizeof(err);
-       res = getsockopt( My_Connections[idx].sock, SOL_SOCKET, SO_ERROR, &err, &sock_len );
-       assert( sock_len == sizeof( err ));
+       res = getsockopt(My_Connections[idx].sock, SOL_SOCKET, SO_ERROR,
+                        &err, &sock_len );
+       assert(sock_len == sizeof(err));
 
        /* Error while connecting? */
        if ((res != 0) || (err != 0)) {
@@ -167,32 +198,28 @@ cb_connserver(int sock, UNUSED short what)
                else
                        Log(LOG_CRIT,
                            "Can't connect socket to \"%s:%d\" (connection %d): %s!",
-                           My_Connections[idx].host,
-                           Conf_Server[Conf_GetServer(idx)].port,
+                           My_Connections[idx].host, Conf_Server[server].port,
                            idx, strerror(err));
 
-               res = Conf_GetServer(idx);
-               assert(res >= 0);
-
                Conn_Close(idx, "Can't connect!", NULL, false);
 
-               if (res < 0)
-                       return;
-               if (ng_ipaddr_af(&Conf_Server[res].dst_addr[0])) {
+               if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) {
                        /* more addresses to try... */
-                       New_Server(res, &Conf_Server[res].dst_addr[0]);
-                       /* connection to dst_addr[0] in progress, remove this address... */
-                       Conf_Server[res].dst_addr[0] = Conf_Server[res].dst_addr[1];
-
-                       memset(&Conf_Server[res].dst_addr[1], 0, sizeof(&Conf_Server[res].dst_addr[1]));
+                       New_Server(res, &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] =
+                               Conf_Server[server].dst_addr[1];
+                       memset(&Conf_Server[server].dst_addr[1], 0,
+                              sizeof(Conf_Server[server].dst_addr[1]));
                }
                return;
        }
 
-       res = Conf_GetServer(idx);
-       assert(res >= 0);
-       if (res >= 0) /* connect succeeded, remove all additional addresses */
-               memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].dst_addr));
+       /* connect() succeeded, remove all additional addresses */
+       memset(&Conf_Server[server].dst_addr, 0,
+              sizeof(Conf_Server[server].dst_addr));
+
        Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
 #ifdef SSL_SUPPORT
        if ( Conn_OPTION_ISSET( &My_Connections[idx], CONN_SSL_CONNECT )) {
@@ -205,6 +232,10 @@ cb_connserver(int sock, UNUSED short what)
 }
 
 
+/**
+ * Login to a remote server.
+ * @param idx Connection index
+ */
 static void
 server_login(CONN_ID idx)
 {
@@ -221,6 +252,11 @@ server_login(CONN_ID idx)
 
 
 #ifdef SSL_SUPPORT
+/**
+ * IO callback for new outgoing SSL-enabled server connections.
+ * @param sock Socket descriptor
+ * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
+ */
 static void
 cb_connserver_login_ssl(int sock, short unused)
 {
@@ -250,6 +286,11 @@ cb_connserver_login_ssl(int sock, short unused)
 #endif
 
 
+/**
+ * IO callback for established non-SSL client and server connections.
+ * @param sock Socket descriptor
+ * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
+ */
 static void
 cb_clientserver(int sock, short what)
 {
@@ -262,18 +303,27 @@ cb_clientserver(int sock, short what)
                return;
        }
 #ifdef SSL_SUPPORT
-       if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE)))
-               Read_Request( idx ); /* if TLS layer needs to write additional data, call Read_Request instead so SSL/TLS can continue */
+       if (what & IO_WANTREAD
+           || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) {
+               /* if TLS layer needs to write additional data, call
+                * Read_Request() instead so that SSL/TLS can continue */
+               Read_Request(idx);
+       }
 #else
        if (what & IO_WANTREAD)
-               Read_Request( idx );
+               Read_Request(idx);
 #endif
        if (what & IO_WANTWRITE)
-               Handle_Write( idx );
+               Handle_Write(idx);
 }
 
 
 #ifdef SSL_SUPPORT
+/**
+ * IO callback for established SSL-enabled client and server connections.
+ * @param sock Socket descriptor
+ * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
+ */
 static void
 cb_clientserver_ssl(int sock, short what)
 {
@@ -287,11 +337,13 @@ cb_clientserver_ssl(int sock, short what)
        }
 
        switch (ConnSSL_Accept(&My_Connections[idx])) {
-               case 1: break;  /* OK */
-               case 0: return; /* EAGAIN: this callback will be invoked again by the io layer */
-               default:
-                       Conn_Close( idx, "Socket closed!", "SSL accept error", false );
-                       return;
+       case 1:
+               break;  /* OK */
+       case 0:
+               return; /* EAGAIN: callback will be invoked again by IO layer */
+       default:
+               Conn_Close(idx, "Socket closed!", "SSL accept error", false);
+               return;
        }
        if (what & IO_WANTREAD)
                Read_Request(idx);
@@ -304,6 +356,9 @@ cb_clientserver_ssl(int sock, short what)
 #endif
 
 
+/**
+ * Initialite connecion module.
+ */
 GLOBAL void
 Conn_Init( void )
 {
@@ -339,6 +394,9 @@ Conn_Init( void )
 } /* Conn_Init */
 
 
+/**
+ * Clean up connection module.
+ */
 GLOBAL void
 Conn_Exit( void )
 {
@@ -391,6 +449,10 @@ ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
 }
 
 
+/**
+ * Initialize all listening sockets.
+ * @return Number of created listening sockets
+ */
 GLOBAL unsigned int
 Conn_InitListeners( void )
 {
@@ -425,13 +487,12 @@ Conn_InitListeners( void )
                listen_addr = strtok(NULL, ",");
        }
 
-       /*
-        * can't free() Conf_ListenAddress here. On /REHASH, if the config file
+       /* Can't free() Conf_ListenAddress here: on REHASH, if the config file
         * cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress.
         * Instead, free() takes place in conf.c, before the config file
-        * is being parsed.
-        */
+        * is being parsed. */
        free(copy);
+
        return created;
 } /* Conn_InitListeners */
 
@@ -574,6 +635,7 @@ NewListener(const char *listen_addr, UINT16 Port)
        return sock;
 } /* NewListener */
 
+
 #ifdef SSL_SUPPORT
 /*
  * SSL/TLS connections require extra treatment:
@@ -1155,12 +1217,14 @@ Count_Connections(ng_ipaddr_t *a)
 } /* Count_Connections */
 
 
+/**
+ * Initialize new client connection on a listening socket.
+ * @param Sock Listening socket descriptor
+ * @return Accepted socket descriptor or -1 on error
+ */
 static int
-New_Connection( int Sock )
+New_Connection(int Sock)
 {
-       /* Neue Client-Verbindung von Listen-Socket annehmen und
-        * CLIENT-Struktur anlegen. */
-
 #ifdef TCPWRAP
        struct request_info req;
 #endif
@@ -1170,10 +1234,9 @@ New_Connection( int Sock )
        CLIENT *c;
        long cnt;
 
-       assert( Sock > NONE );
-       /* Connection auf Listen-Socket annehmen */
-       new_sock_len = (int)sizeof(new_addr);
+       assert(Sock > NONE);
 
+       new_sock_len = (int)sizeof(new_addr);
        new_sock = accept(Sock, (struct sockaddr *)&new_addr,
                          (socklen_t *)&new_sock_len);
        if (new_sock < 0) {
@@ -1190,49 +1253,56 @@ New_Connection( int Sock )
 
 #ifdef TCPWRAP
        /* Validate socket using TCP Wrappers */
-       request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL );
+       request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock,
+                    RQ_CLIENT_SIN, &new_addr, NULL);
        fromhost(&req);
        if (!hosts_access(&req)) {
-               Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str);
-               Simple_Message( new_sock, "ERROR :Connection refused" );
-               close( new_sock );
+               Log(deny_severity,
+                   "Refused connection from %s (by TCP Wrappers)!", ip_str);
+               Simple_Message(new_sock, "ERROR :Connection refused");
+               close(new_sock);
                return -1;
        }
 #endif
 
-       /* Socket initialisieren */
-       if (!Init_Socket( new_sock ))
+       if (!Init_Socket(new_sock))
+               return -1;
+
+       /* 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);
+               Simple_Message(new_sock, "ERROR :Connection limit reached");
+               close(new_sock);
                return -1;
+       }
 
        /* Check IP-based connection limit */
        cnt = Count_Connections(&new_addr);
        if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
                /* Access denied, too many connections from this IP address! */
-               Log( LOG_ERR, "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!" );
-               close( new_sock );
-               return -1;
-       }
-
-       if ((Conf_MaxConnections > 0) &&
-               (NumConnections >= (size_t) Conf_MaxConnections))
-       {
-               Log( LOG_ALERT, "Can't accept connection: limit (%d) reached!", Conf_MaxConnections);
-               Simple_Message( new_sock, "ERROR :Connection limit reached" );
-               close( new_sock );
+               Log(LOG_ERR,
+                   "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!");
+               close(new_sock);
                return -1;
        }
 
-       if( new_sock >= Pool_Size ) {
+       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 );
+                                (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));
+                        new_sock, array_length(&My_ConnArray,
+                        sizeof(CONNECTION)), array_bytes(&My_ConnArray));
 
                /* Adjust pointer to new block */
                My_Connections = array_start(&My_ConnArray);
@@ -1241,22 +1311,24 @@ New_Connection( int Sock )
        }
 
        /* register callback */
-       if (!io_event_create( new_sock, IO_WANTREAD, cb_clientserver)) {
-               Log(LOG_ALERT, "Can't accept connection: io_event_create failed!");
+       if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) {
+               Log(LOG_ALERT,
+                   "Can't accept connection: io_event_create failed!");
                Simple_Message(new_sock, "ERROR :Internal error");
                close(new_sock);
                return -1;
        }
 
-       c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false );
-       if( ! c ) {
-               Log(LOG_ALERT, "Can't accept connection: can't create client structure!");
+       c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false);
+       if (!c) {
+               Log(LOG_ALERT,
+                   "Can't accept connection: can't create client structure!");
                Simple_Message(new_sock, "ERROR :Internal error");
                io_close(new_sock);
                return -1;
        }
 
-       Init_Conn_Struct( new_sock );
+       Init_Conn_Struct(new_sock);
        My_Connections[new_sock].sock = new_sock;
        My_Connections[new_sock].addr = new_addr;
        My_Connections[new_sock].client = c;
@@ -1284,6 +1356,10 @@ New_Connection( int Sock )
        if (!Conf_NoDNS)
                Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr,
                             identsock, cb_Read_Resolver_Result);
+
+       /* ngIRCd waits up to 4 seconds for the result of the asynchronous
+        * DNS and IDENT resolver subprocess using the "penalty" mechanism.
+        * If there are results earlier, the delay is aborted. */
        Conn_SetPenalty(new_sock, 4);
        return new_sock;
 } /* New_Connection */
@@ -1817,7 +1893,6 @@ Init_Socket( int Sock )
 } /* Init_Socket */
 
 
-
 static void
 cb_Connect_to_Server(int fd, UNUSED short events)
 {
@@ -1964,24 +2039,34 @@ Simple_Message( int Sock, const char *Msg )
 } /* Simple_Error */
 
 
+/**
+ * Get CLIENT structure that belongs to a local connection identified by its
+ * index number. Each connection belongs to a client by definition, so it is
+ * not required that the caller checks for NULL return values.
+ * @param Idx Connection index number
+ * @return Pointer to CLIENT structure
+ */
 GLOBAL CLIENT *
 Conn_GetClient( CONN_ID Idx ) 
 {
-       /* return Client-Structure that belongs to the local Connection Idx.
-        * If none is found, return NULL.
-        */
        CONNECTION *c;
-       assert( Idx >= 0 );
 
+       assert(Idx >= 0);
        c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx);
-
        assert(c != NULL);
-
        return c ? c->client : NULL;
 }
 
+
 #ifdef SSL_SUPPORT
-/* we cannot access My_Connections in irc-info.c */
+
+/**
+ * Get information about used SSL chiper.
+ * @param Idx Connection index number
+ * @param buf Buffer for returned information text
+ * @param len Size of return buffer "buf"
+ * @return true on success, false otherwise
+ */
 GLOBAL bool
 Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len)
 {
@@ -1992,6 +2077,11 @@ Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len)
 }
 
 
+/**
+ * Check if a connection is SSL-enabled or not.
+ * @param Idx Connection index number
+ * @return true if connection is SSL-enabled, false otherwise.
+ */
 GLOBAL bool
 Conn_UsesSSL(CONN_ID Idx)
 {
@@ -2000,6 +2090,7 @@ Conn_UsesSSL(CONN_ID Idx)
        assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
        return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL);
 }
+
 #endif