]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
make Listen parameter a comma-seperated list of addresses.
[ngircd-alex.git] / src / ngircd / conn.c
index 9e31e4eec576e7c3a747e0c97d65ed790911b5da..7c4c8d23782cc995fc11c41baeee9041e0ae1416 100644 (file)
@@ -88,7 +88,7 @@ static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
 static bool Init_Socket PARAMS(( int Sock ));
 static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
 static void Simple_Message PARAMS(( int Sock, const char *Msg ));
-static int NewListener PARAMS(( int af, const UINT16 Port ));
+static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
 
 static array My_Listeners;
 static array My_ConnArray;
@@ -272,7 +272,7 @@ Conn_Exit( void )
 
 
 static unsigned int
-ports_initlisteners(array *a, int af, void (*func)(int,short))
+ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
 {
        unsigned int created = 0;
        size_t len;
@@ -281,15 +281,15 @@ ports_initlisteners(array *a, int af, void (*func)(int,short))
 
        len = array_length(a, sizeof (UINT16));
        port = array_start(a);
-       while(len--) {
-               fd = NewListener(af, *port);
+       while (len--) {
+               fd = NewListener(listen_addr, *port);
                if (fd < 0) {
                        port++;
                        continue;
                }
                if (!io_event_create( fd, IO_WANTREAD, func )) {
                        Log( LOG_ERR, "io_event_create(): Could not add listening fd %d (port %u): %s!",
-                                                       fd, (unsigned int) *port, strerror(errno));
+                                               fd, (unsigned int) *port, strerror(errno));
                        close(fd);
                        port++;
                        continue;
@@ -297,7 +297,6 @@ ports_initlisteners(array *a, int af, void (*func)(int,short))
                created++;
                port++;
        }
-
        return created;
 }
 
@@ -306,20 +305,39 @@ GLOBAL unsigned int
 Conn_InitListeners( void )
 {
        /* Initialize ports on which the server should accept connections */
-
        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;
        }
 
-#ifdef WANT_IPV6
-       if (!Conf_NoListenIpv6)
-               created = ports_initlisteners(&Conf_ListenPorts, AF_INET6, cb_listen);
-#endif
-       created += ports_initlisteners(&Conf_ListenPorts, AF_INET, cb_listen);
+       assert(Conf_ListenAddress);
+
+       /* can't use Conf_ListenAddress directly, see below */
+       copy = strdup(Conf_ListenAddress);
+       if (!copy) {
+               Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress, strerror(errno));
+               return 0;
+       }
+       listen_addr = strtok(copy, ",");
+
+       while (listen_addr) {
+               ngt_TrimStr(listen_addr);
+               if (*listen_addr)
+                       created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen);
+
+               listen_addr = strtok(NULL, ",");
+       }
 
+       /*
+        * 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.
+        */
+       free(copy);
        return created;
 } /* Conn_InitListeners */
 
@@ -349,25 +367,15 @@ Conn_ExitListeners( void )
 
 
 static bool
-InitSinaddrListenAddr(int af, ng_ipaddr_t *addr, UINT16 Port)
+InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port)
 {
        bool ret;
-       const char *listen_addrstr = NULL;
-#ifdef WANT_IPV6
-       if (af == AF_INET)
-               listen_addrstr = "0.0.0.0";
-#else
-       (void)af;
-#endif
-       if (Conf_ListenAddress[0]) /* overrides V4/V6 atm */
-               listen_addrstr = Conf_ListenAddress;
 
        ret = ng_ipaddr_init(addr, listen_addrstr, Port);
        if (!ret) {
-               if (!listen_addrstr)
-                       listen_addrstr = "";
-               Log(LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"",
-                                       listen_addrstr, Port, listen_addrstr);
+               assert(listen_addrstr);
+               Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"",
+                                               listen_addrstr, Port, listen_addrstr);
        }
        return ret;
 }
@@ -393,32 +401,33 @@ set_v6_only(int af, int sock)
 
 /* return new listening port file descriptor or -1 on failure */
 static int
-NewListener(int af, const UINT16 Port)
+NewListener(const char *listen_addr, UINT16 Port)
 {
        /* Create new listening socket on specified port */
        ng_ipaddr_t addr;
-       int sock;
+       int sock, af;
 #ifdef ZEROCONF
        char name[CLIENT_ID_LEN], *info;
 #endif
-       if (!InitSinaddrListenAddr(af, &addr, Port))
+       if (!InitSinaddrListenAddr(&addr, listen_addr, Port))
                return -1;
 
-       sock = socket(ng_ipaddr_af(&addr), SOCK_STREAM, 0);
+       af = ng_ipaddr_af(&addr);
+       sock = socket(af, SOCK_STREAM, 0);
        if( sock < 0 ) {
-               Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
+               Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno));
                return -1;
        }
 
-       af = ng_ipaddr_af(&addr);
-
        set_v6_only(af, sock);
 
-       if( ! Init_Socket( sock )) return -1;
+       if (!Init_Socket(sock))
+               return -1;
 
        if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) {
-               Log( LOG_CRIT, "Can't bind socket (port %d) : %s!", Port, strerror( errno ));
-               close( sock );
+               Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s",
+                       ng_ipaddr_tostr(&addr), Port, strerror(errno));
+               close(sock);
                return -1;
        }
 
@@ -435,12 +444,7 @@ NewListener(int af, const UINT16 Port)
                return -1;
        }
 
-#ifdef WANT_IPV6
-       if (af == AF_INET6)
-               Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock);
-       else
-#endif
-               Log(LOG_INFO, "Now listening on %s:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock);
+       Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock);
 
 #ifdef ZEROCONF
        /* Get best server description text */
@@ -1217,11 +1221,13 @@ Read_Request( CONN_ID Idx )
 } /* Read_Request */
 
 
+/**
+ * Handle data in connection read-buffer.
+ * @return true if a reuqest was handled, false otherwise (and on errors).
+ */
 static bool
-Handle_Buffer( CONN_ID Idx )
+Handle_Buffer(CONN_ID Idx)
 {
-       /* Handle Data in Connections Read-Buffer.
-        * Return true if a reuqest was handled, false otherwise (also returned on errors). */
 #ifndef STRICT_RFC
        char *ptr1, *ptr2;
 #endif
@@ -1237,86 +1243,104 @@ Handle_Buffer( CONN_ID Idx )
        result = false;
        for (;;) {
                /* Check penalty */
-               if( My_Connections[Idx].delaytime > starttime) return result;
+               if (My_Connections[Idx].delaytime > starttime)
+                       return result;
 #ifdef ZLIB
-               /* unpack compressed data */
-               if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP ))
-                       if( ! Unzip_Buffer( Idx )) return false;
+               /* Unpack compressed data, if compression is in use */
+               if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) {
+                       if (!Unzip_Buffer(Idx))
+                               return false;
+               }
 #endif
 
                if (0 == array_bytes(&My_Connections[Idx].rbuf))
                        break;
 
-               if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) /* make sure buf is NULL terminated */
+               /* Make sure that the buffer is NULL terminated */
+               if (!array_cat0_temporary(&My_Connections[Idx].rbuf))
                        return false;
 
-               /* A Complete Request end with CR+LF, see RFC 2812. */
-               ptr = strstr( array_start(&My_Connections[Idx].rbuf), "\r\n" );
+               /* RFC 2812, section "2.3 Messages", 5th paragraph:
+                * "IRC messages are always lines of characters terminated
+                * with a CR-LF (Carriage Return - Line Feed) pair [...]". */
+               delta = 2;
+               ptr = strstr(array_start(&My_Connections[Idx].rbuf), "\r\n");
 
-               if( ptr ) delta = 2; /* complete request */
 #ifndef STRICT_RFC
-               else {
-                       /* Check for non-RFC-compliant request (only CR or LF)? Unfortunately,
-                        * there are quite a few clients that do this (incl. "mIRC" :-( */
-                       ptr1 = strchr( array_start(&My_Connections[Idx].rbuf), '\r' );
-                       ptr2 = strchr( array_start(&My_Connections[Idx].rbuf), '\n' );
+               if (!ptr) {
+                       /* Check for non-RFC-compliant request (only CR or
+                        * LF)? Unfortunately, there are quite a few clients
+                        * out there that do this -- incl. "mIRC" :-( */
                        delta = 1;
-                       if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
-                       else if( ptr1 ) ptr = ptr1;
-                       else if( ptr2 ) ptr = ptr2;
+                       ptr1 = strchr(array_start(&My_Connections[Idx].rbuf), '\r');
+                       ptr2 = strchr(array_start(&My_Connections[Idx].rbuf), '\n');
+                       if (ptr1 && ptr2)
+                               ptr = ptr1 > ptr2 ? ptr2 : ptr1;
+                       else if (ptr1)
+                               ptr = ptr1;
+                       else if (ptr2)
+                               ptr = ptr2;
                }
 #endif
 
-               if( ! ptr )
+               if (!ptr)
                        break;
 
-               /* End of request found */
+               /* Complete (=line terminated) request found, handle it! */
                *ptr = '\0';
 
-               len = ( ptr - (char*) array_start(&My_Connections[Idx].rbuf)) + delta;
+               len = ptr - (char *)array_start(&My_Connections[Idx].rbuf) + delta;
 
-               if( len > ( COMMAND_LEN - 1 )) {
-                       /* Request must not exceed 512 chars (incl. CR+LF!), see
-                        * RFC 2812. Disconnect Client if this happens. */
-                       Log( LOG_ERR, "Request too long (connection %d): %d bytes (max. %d expected)!",
-                                               Idx, array_bytes(&My_Connections[Idx].rbuf), COMMAND_LEN - 1 );
-                       Conn_Close( Idx, NULL, "Request too long", true );
+               if (len > (COMMAND_LEN - 1)) {
+                       /* Request must not exceed 512 chars (incl. CR+LF!),
+                        * see RFC 2812. Disconnect Client if this happens. */
+                       Log(LOG_ERR,
+                           "Request too long (connection %d): %d bytes (max. %d expected)!",
+                           Idx, array_bytes(&My_Connections[Idx].rbuf),
+                           COMMAND_LEN - 1);
+                       Conn_Close(Idx, NULL, "Request too long", true);
                        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 */
+               if (len <= delta) {
+                       /* Request is empty (only '\r\n', '\r' or '\n');
+                        * delta is 2 ('\r\n') or 1 ('\r' or '\n'), see above */
+                       array_moveleft(&My_Connections[Idx].rbuf, 1, len);
                        break;
                }
+
 #ifdef ZLIB
                /* remember if stream is already compressed */
                old_z = My_Connections[Idx].options & CONN_ZIP;
 #endif
 
                My_Connections[Idx].msg_in++;
-               if (!Parse_Request(Idx, (char*)array_start(&My_Connections[Idx].rbuf) ))
+               if (!Parse_Request
+                   (Idx, (char *)array_start(&My_Connections[Idx].rbuf)))
                        return false;
 
                result = true;
 
                array_moveleft(&My_Connections[Idx].rbuf, 1, len);
                LogDebug("Connection %d: %d bytes left in read buffer.",
-                   Idx, array_bytes(&My_Connections[Idx].rbuf));
+                        Idx, array_bytes(&My_Connections[Idx].rbuf));
 #ifdef ZLIB
-               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_copy( &My_Connections[Idx].zip.rbuf, &My_Connections[Idx].rbuf ))
+               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 the unzip buffer for decompression: */
+                       if (!array_copy
+                           (&My_Connections[Idx].zip.rbuf,
+                            &My_Connections[Idx].rbuf))
                                return false;
 
                        array_trunc(&My_Connections[Idx].rbuf);
-                       LogDebug("Moved already received data (%u bytes) to uncompression buffer.",
-                                                               array_bytes(&My_Connections[Idx].zip.rbuf));
+                       LogDebug
+                           ("Moved already received data (%u bytes) to uncompression buffer.",
+                            array_bytes(&My_Connections[Idx].zip.rbuf));
                }
-#endif /* ZLIB */
+#endif
        }
        return result;
 } /* Handle_Buffer */
@@ -1438,7 +1462,7 @@ New_Server( int Server , ng_ipaddr_t *dest)
        af_dest = ng_ipaddr_af(dest);
        new_sock = socket(af_dest, SOCK_STREAM, 0);
        if (new_sock < 0) {
-               Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
+               Log( LOG_CRIT, "Can't create socket (af %d) : %s!", af_dest, strerror( errno ));
                return;
        }