]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
NoticeAuth: make sure messages are flushed immediately
[ngircd-alex.git] / src / ngircd / conn.c
index 407da1a3b0837ac2bd99c16054175a4b4070e006..8fd162b7122eee89c37ca319e8d2cafb71ebb16a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2010 Alexander Barton <alex@barton.de>
+ * Copyright (c)2001-2012 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
@@ -65,6 +65,7 @@
 #include "ngircd.h"
 #include "array.h"
 #include "client.h"
+#include "class.h"
 #include "conf.h"
 #include "conn-ssl.h"
 #include "conn-zip.h"
@@ -81,8 +82,8 @@
 #define SERVER_WAIT (NONE - 1)
 
 #define MAX_COMMANDS 3
-#define MAX_COMMANDS_SERVER 10
-#define MAX_COMMANDS_SERVICE MAX_COMMANDS_SERVER
+#define MAX_COMMANDS_SERVER_MIN 10
+#define MAX_COMMANDS_SERVICE 10
 
 
 static bool Handle_Write PARAMS(( CONN_ID Idx ));
@@ -369,7 +370,7 @@ cb_clientserver_ssl(int sock, short what)
 
 
 /**
- * Initialite connecion module.
+ * Initialize connecion module.
  */
 GLOBAL void
 Conn_Init( void )
@@ -435,12 +436,13 @@ Conn_Exit( void )
  * they don't hold connections open that the main process wants to close.
  */
 GLOBAL void
-Conn_CloseAllSockets(void)
+Conn_CloseAllSockets(int ExceptOf)
 {
        CONN_ID idx;
 
        for(idx = 0; idx < Pool_Size; idx++) {
-               if(My_Connections[idx].sock > NONE)
+               if(My_Connections[idx].sock > NONE &&
+                  My_Connections[idx].sock != ExceptOf)
                        close(My_Connections[idx].sock);
        }
 }
@@ -741,6 +743,9 @@ Conn_Handler(void)
                Check_Servers();
                Check_Connections();
 
+               /* Expire outdated class/list items */
+               Class_Expire();
+
                /* Look for non-empty read buffers ... */
                for (i = 0; i < Pool_Size; i++) {
                        if ((My_Connections[i].sock > NONE)
@@ -913,6 +918,30 @@ va_dcl
        return ok;
 } /* Conn_WriteStr */
 
+GLOBAL char*
+Conn_Password( CONN_ID Idx )
+{
+       assert( Idx > NONE );
+       if (My_Connections[Idx].pwd == NULL)
+               return (char*)"\0";
+       else
+               return My_Connections[Idx].pwd;
+} /* Conn_Password */
+
+GLOBAL void
+Conn_SetPassword( CONN_ID Idx, const char *Pwd )
+{
+       assert( Idx > NONE );
+
+       if (My_Connections[Idx].pwd)
+               free(My_Connections[Idx].pwd);
+
+       My_Connections[Idx].pwd = strdup(Pwd);
+       if (My_Connections[Idx].pwd == NULL) {
+               Log(LOG_EMERG, "Can't allocate memory! [Conn_SetPassword]");
+               exit(1);
+       }
+} /* Conn_SetPassword */
 
 /**
  * Append Data to the outbound write buffer of a connection.
@@ -931,22 +960,25 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len )
        assert( Data != NULL );
        assert( Len > 0 );
 
-       c = Conn_GetClient(Idx);
-       assert( c != NULL);
-
-       /* Servers do get special write buffer limits, so they can generate
-        * all the messages that are required while peering. */
-       if (Client_Type(c) == CLIENT_SERVER)
-               writebuf_limit = WRITEBUFFER_SLINK_LEN;
-
        /* Is the socket still open? A previous call to Conn_Write()
         * may have closed the connection due to a fatal error.
         * In this case it is sufficient to return an error, as well. */
-       if( My_Connections[Idx].sock <= NONE ) {
+       if (My_Connections[Idx].sock <= NONE) {
                LogDebug("Skipped write on closed socket (connection %d).", Idx);
                return false;
        }
 
+       /* 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 write buffer limits, so they can
+                * generate all the messages that are required while peering. */
+               if (Client_Type(c) == CLIENT_SERVER)
+                       writebuf_limit = WRITEBUFFER_SLINK_LEN;
+       } else
+               LogDebug("Write on socket without client (connection %d)!?", Idx);
+
 #ifdef ZLIB
        if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
                /* Compressed link:
@@ -1009,7 +1041,7 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len )
 GLOBAL void
 Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClient )
 {
-       /* Close connection. Open pipes of asyncronous resolver
+       /* Close connection. Open pipes of asynchronous resolver
         * sub-processes are closed down. */
 
        CLIENT *c;
@@ -1138,6 +1170,8 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie
 
        array_free(&My_Connections[Idx].rbuf);
        array_free(&My_Connections[Idx].wbuf);
+       if (My_Connections[Idx].pwd != NULL)
+               free(My_Connections[Idx].pwd);
 
        /* Clean up connection structure (=free it) */
        Init_Conn_Struct( Idx );
@@ -1218,6 +1252,20 @@ Conn_SyncServerStruct(void)
 } /* SyncServerStruct */
 
 
+/**
+ * Get IP address string of a connection.
+ *
+ * @param Idx Connection index.
+ * @return Pointer to a global buffer containing the IP address as string.
+ */
+GLOBAL const char *
+Conn_GetIPAInfo(CONN_ID Idx)
+{
+       assert(Idx > NONE);
+       return ng_ipaddr_tostr(&My_Connections[Idx].addr);
+}
+
+
 /**
  * Send out data of write buffer; connect new sockets.
  *
@@ -1416,7 +1464,7 @@ New_Connection(int Sock)
                return -1;
        }
 
-       c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false);
+       c = Client_NewLocal(new_sock, NULL, CLIENT_UNKNOWN, false);
        if (!c) {
                Log(LOG_ALERT,
                    "Can't accept connection: can't create client structure!");
@@ -1460,6 +1508,7 @@ New_Connection(int Sock)
 #endif
                                (void)Conn_WriteStr(new_sock,
                                        "NOTICE AUTH :*** Looking up your hostname");
+                       (void)Handle_Write(new_sock);
                }
                Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr,
                             identsock, cb_Read_Resolver_Result);
@@ -1567,7 +1616,7 @@ Read_Request( CONN_ID Idx )
                if (!array_catb(&My_Connections[Idx].zip.rbuf, readbuf,
                                (size_t) len)) {
                        Log(LOG_ERR,
-                           "Could not append recieved data to zip input buffer (connn %d): %d bytes!",
+                           "Could not append received data to zip input buffer (connection %d): %d bytes!",
                            Idx, len);
                        Conn_Close(Idx, "Receive buffer space exhausted", NULL,
                                   false);
@@ -1577,7 +1626,9 @@ Read_Request( CONN_ID Idx )
 #endif
        {
                if (!array_catb( &My_Connections[Idx].rbuf, readbuf, len)) {
-                       Log( LOG_ERR, "Could not append recieved data to input buffer (connn %d): %d bytes!", Idx, len );
+                       Log(LOG_ERR,
+                           "Could not append received data to input buffer (connection %d): %d bytes!",
+                           Idx, len);
                        Conn_Close(Idx, "Receive buffer space exhausted", NULL, false );
                }
        }
@@ -1650,16 +1701,15 @@ Handle_Buffer(CONN_ID Idx)
 
        assert(c != NULL);
 
-       /* Servers do get special command limits, so they can process
-        * all the messages that are required while peering. */
+       /* Servers get special command limits that depend on the user count */
        switch (Client_Type(c)) {
            case CLIENT_SERVER:
-               /* Allow servers to send more commands in the first 10 secods
+               maxcmd = (int)(Client_UserCount() / 5)
+                      + MAX_COMMANDS_SERVER_MIN;
+               /* Allow servers to handle even more commands while peering
                 * to speed up server login and network synchronisation. */
-               if (starttime - Client_StartTime(c) < 10)
-                       maxcmd = MAX_COMMANDS_SERVER * 5;
-               else
-                       maxcmd = MAX_COMMANDS_SERVER;
+               if (Conn_LastPing(Idx) == 0)
+                       maxcmd *= 5;
                break;
            case CLIENT_SERVICE:
                maxcmd = MAX_COMMANDS_SERVICE; break;
@@ -1816,17 +1866,17 @@ Check_Connections(void)
                                if (My_Connections[i].lastping <
                                    time(NULL) - Conf_PongTimeout) {
                                        /* Timeout */
-                                       LogDebug
-                                           ("Connection %d: Ping timeout: %d seconds.",
-                                            i, Conf_PongTimeout);
-                                       snprintf(msg, sizeof(msg), "Ping timeout: %d seconds", Conf_PongTimeout);
+                                       snprintf(msg, sizeof(msg),
+                                                "Ping timeout: %d seconds",
+                                                Conf_PongTimeout);
+                                       LogDebug("Connection %d: %s.", i, msg);
                                        Conn_Close(i, NULL, msg, true);
                                }
                        } else if (My_Connections[i].lastdata <
                                   time(NULL) - Conf_PingTimeout) {
                                /* We need to send a PING ... */
                                LogDebug("Connection %d: sending PING ...", i);
-                               My_Connections[i].lastping = time(NULL);
+                               Conn_UpdatePing(i);
                                Conn_WriteStr(i, "PING :%s",
                                              Client_ID(Client_ThisServer()));
                        }
@@ -1912,6 +1962,14 @@ New_Server( int Server , ng_ipaddr_t *dest)
 
        assert( Server > NONE );
 
+       /* Make sure that the remote server hasn't re-linked to this server
+        * asynchronously on its own */
+       if (Conf_Server[Server].conn_id > NONE) {
+               Log(LOG_INFO,
+                       "Connection to \"%s\" meanwhile re-established, aborting preparation.");
+               return;
+       }
+
        if (!ng_ipaddr_tostr_r(dest, ip_str)) {
                Log(LOG_WARNING, "New_Server: Could not convert IP to string");
                return;
@@ -1985,7 +2043,7 @@ New_Server( int Server , ng_ipaddr_t *dest)
        Client_SetToken( c, TOKEN_OUTBOUND );
 
        /* Register connection */
-       Conf_Server[Server].conn_id = new_sock;
+       Conf_SetServer(Server, new_sock);
        My_Connections[new_sock].sock = new_sock;
        My_Connections[new_sock].addr = *dest;
        My_Connections[new_sock].client = c;
@@ -2151,6 +2209,7 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
        char *identptr;
 #ifdef IDENTAUTH
        char readbuf[HOST_LEN + 2 + CLIENT_USER_LEN];
+       char *ptr;
 #else
        char readbuf[HOST_LEN + 1];
 #endif
@@ -2199,15 +2258,37 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
                Client_SetHostname(c, readbuf);
                if (Conf_NoticeAuth)
                        (void)Conn_WriteStr(i,
-                                       "NOTICE AUTH :*** Found your hostname");
+                                       "NOTICE AUTH :*** Found your hostname: %s",
+                                       My_Connections[i].host);
 #ifdef IDENTAUTH
                ++identptr;
                if (*identptr) {
-                       Log(LOG_INFO, "IDENT lookup for connection %d: \"%s\".", i, identptr);
-                       Client_SetUser(c, identptr, true);
-                       if (Conf_NoticeAuth)
+                       ptr = identptr;
+                       while (*ptr) {
+                               if ((*ptr < '0' || *ptr > '9') &&
+                                   (*ptr < 'A' || *ptr > 'Z') &&
+                                   (*ptr < 'a' || *ptr > 'z'))
+                                       break;
+                               ptr++;
+                       }
+                       if (*ptr) {
+                               /* Erroneous IDENT reply */
+                               Log(LOG_NOTICE,
+                                   "Got invalid IDENT reply for connection %d! Ignored.",
+                                   i);
+                       } else {
+                               Log(LOG_INFO,
+                                   "IDENT lookup for connection %d: \"%s\".",
+                                   i, identptr);
+                               Client_SetUser(c, identptr, true);
+                       }
+                       if (Conf_NoticeAuth) {
                                (void)Conn_WriteStr(i,
-                                       "NOTICE AUTH :*** Got ident response");
+                                       "NOTICE AUTH :*** Got %sident response%s%s",
+                                       *ptr ? "invalid " : "",
+                                       *ptr ? "" : ": ",
+                                       *ptr ? "" : identptr);
+                       }
                } else {
                        Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
                        if (Conf_NoticeAuth && Conf_Ident)
@@ -2215,6 +2296,11 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
                                        "NOTICE AUTH :*** No ident response");
                }
 #endif
+
+               if (Conf_NoticeAuth)
+                       (void)Handle_Write(i);
+
+               Class_HandleServerBans(c);
        }
 #ifdef DEBUG
                else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );