]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
Implement support for systemd(8) "socket activation"
[ngircd-alex.git] / src / ngircd / conn.c
index d9d73e842b9ade409ef280c47f1d8e9602046d4b..378509f96f09bc35eb9e3ebc2eb12140c24509fb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
+ * 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
 # include <netinet/ip.h>
 #endif
 
-#ifdef HAVE_STDINT_H
-# include <stdint.h>                   /* e.g. for Mac OS X */
-#endif
-
 #ifdef TCPWRAP
 # include <tcpd.h>                     /* for TCP Wrappers */
 #endif
@@ -67,6 +63,7 @@
 #include "client.h"
 #include "class.h"
 #include "conf.h"
+#include "conn-encoding.h"
 #include "conn-ssl.h"
 #include "conn-zip.h"
 #include "conn-func.h"
 #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
+
+#define SD_LISTEN_FDS_START 3
 
 
 static bool Handle_Write PARAMS(( CONN_ID Idx ));
 static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
-static int New_Connection PARAMS(( int Sock ));
+static int New_Connection PARAMS(( int Sock, bool IsSSL ));
 static CONN_ID Socket2Index PARAMS(( int Sock ));
 static void Read_Request PARAMS(( CONN_ID Idx ));
 static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx ));
@@ -123,6 +122,40 @@ static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what));
 static void cb_clientserver PARAMS((int sock, short what));
 
 
+/**
+ * Get number of sockets available from systemd(8).
+ *
+ * ngIRCd needs to implement its own sd_listen_fds(3) function and can't
+ * use the one provided by systemd itself, becaus the sockets will be
+ * used in a forked child process with a new PID, and this would trigger
+ * an error in the standard implementation.
+ *
+ * @return Number of sockets available, -1 if sockets have already been
+ *         initialized, or 0 when no sockets have been passed.
+ */
+static int
+my_sd_listen_fds(void)
+{
+       const char *e;
+       long count;
+
+       /* Check if LISTEN_PID exists; but we ignore the result, because
+        * normally ngircd forks a child before checking this, and therefore
+        * the PID set in the environment is always wrong ... */
+       e = getenv("LISTEN_PID");
+       if (!e || !*e)
+               return 0;
+
+       e = getenv("LISTEN_FDS");
+       if (!e || !*e)
+               return -1;
+       count = atol(e);
+       unsetenv("LISTEN_FDS");
+
+       return count;
+}
+
+
 /**
  * IO callback for listening sockets: handle new connections. This callback
  * gets called when a new non-SSL connection should be accepted.
@@ -134,7 +167,7 @@ static void
 cb_listen(int sock, short irrelevant)
 {
        (void) irrelevant;
-       (void) New_Connection(sock);
+       (void) New_Connection(sock, false);
 }
 
 
@@ -152,7 +185,7 @@ cb_listen_ssl(int sock, short irrelevant)
        int fd;
 
        (void) irrelevant;
-       fd = New_Connection(sock);
+       fd = New_Connection(sock, true);
        if (fd < 0)
                return;
        io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
@@ -208,7 +241,7 @@ cb_connserver(int sock, UNUSED short what)
                            My_Connections[idx].host, Conf_Server[server].port,
                            idx, strerror(err));
 
-               Conn_Close(idx, "Can't connect!", NULL, false);
+               Conn_Close(idx, "Can't connect", NULL, false);
 
                if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) {
                        /* more addresses to try... */
@@ -285,7 +318,7 @@ cb_connserver_login_ssl(int sock, short unused)
                return;
        case -1:
                Log(LOG_ERR, "SSL connection on socket %d failed!", sock);
-               Conn_Close(idx, "Can't connect!", NULL, false);
+               Conn_Close(idx, "Can't connect", NULL, false);
                return;
        }
 
@@ -457,7 +490,7 @@ Conn_CloseAllSockets(int ExceptOf)
  * @returns            Number of listening sockets created.
  */
 static unsigned int
-ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
+Init_Listeners(array *a, const char *listen_addr, void (*func)(int,short))
 {
        unsigned int created = 0;
        size_t len;
@@ -473,8 +506,9 @@ ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
                        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));
+                       Log(LOG_ERR,
+                           "io_event_create(): Can't add fd %d (port %u): %s!",
+                           fd, (unsigned int) *port, strerror(errno));
                        close(fd);
                        port++;
                        continue;
@@ -497,13 +531,43 @@ Conn_InitListeners( void )
        /* Initialize ports on which the server should accept connections */
        unsigned int created = 0;
        char *copy, *listen_addr;
+       int count, fd, i;
 
        assert(Conf_ListenAddress);
 
+       count = my_sd_listen_fds();
+       if (count < 0) {
+               Log(LOG_INFO,
+                   "Not re-initializing listening sockets of systemd(8) ...");
+               return 0;
+       }
+       if (count > 0) {
+               /* systemd(8) passed sockets to us, so don't try to initialize
+                * listening sockets on our own but use the passed ones */
+               LogDebug("Initializing %d systemd sockets ...", count);
+               for (i = 0; i < count; i++) {
+                       fd = SD_LISTEN_FDS_START + i;
+                       Init_Socket(fd);
+                       if (!io_event_create(fd, IO_WANTREAD, cb_listen)) {
+                               Log(LOG_ERR,
+                                   "io_event_create(): Can't add fd %d: %s!",
+                                   fd, strerror(errno));
+                               continue;
+                       }
+                       Log(LOG_INFO,
+                           "Initialized socket %d from systemd.", fd);
+                       created++;
+               }
+               return created;
+       }
+
+       /* not using systemd socket activation, initialize listening sockets: */
+
        /* 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));
+               Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress,
+                   strerror(errno));
                return 0;
        }
        listen_addr = strtok(copy, ",");
@@ -511,9 +575,11 @@ Conn_InitListeners( void )
        while (listen_addr) {
                ngt_TrimStr(listen_addr);
                if (*listen_addr) {
-                       created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen);
+                       created += Init_Listeners(&Conf_ListenPorts,
+                                                 listen_addr, cb_listen);
 #ifdef SSL_SUPPORT
-                       created += ports_initlisteners(&Conf_SSLOptions.ListenPorts, listen_addr, cb_listen_ssl);
+                       created += Init_Listeners(&Conf_SSLOptions.ListenPorts,
+                                                 listen_addr, cb_listen_ssl);
 #endif
                }
 
@@ -540,7 +606,12 @@ Conn_ExitListeners( void )
        int *fd;
        size_t arraylen;
 
+       /* Get number of listening sockets to shut down. There can be none
+        * if ngIRCd has been "socket activated" by systemd. */
        arraylen = array_length(&My_Listeners, sizeof (int));
+       if (arraylen < 1)
+               return;
+
        Log(LOG_INFO,
            "Shutting down all listening sockets (%d total) ...", arraylen);
        fd = array_start(&My_Listeners);
@@ -571,7 +642,7 @@ InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port
        ret = ng_ipaddr_init(addr, listen_addrstr, Port);
        if (!ret) {
                assert(listen_addrstr);
-               Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"",
+               Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"!",
                                                listen_addrstr, Port, listen_addrstr);
        }
        return ret;
@@ -623,8 +694,9 @@ NewListener(const char *listen_addr, UINT16 Port)
 
        af = ng_ipaddr_af(&addr);
        sock = socket(af, SOCK_STREAM, 0);
-       if( sock < 0 ) {
-               Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno));
+       if (sock < 0) {
+               Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af,
+                   strerror(errno));
                return -1;
        }
 
@@ -634,22 +706,23 @@ NewListener(const char *listen_addr, UINT16 Port)
                return -1;
 
        if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) {
-               Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s",
-                       ng_ipaddr_tostr(&addr), Port, strerror(errno));
+               Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s!",
+                   ng_ipaddr_tostr(&addr), Port, strerror(errno));
                close(sock);
                return -1;
        }
 
-       if( listen( sock, 10 ) != 0 ) {
-               Log( LOG_CRIT, "Can't listen on socket: %s!", strerror( errno ));
-               close( sock );
+       if (listen(sock, 10) != 0) {
+               Log(LOG_CRIT, "Can't listen on socket: %s!", strerror(errno));
+               close(sock);
                return -1;
        }
 
        /* keep fd in list so we can close it when ngircd restarts/shuts down */
-       if (!array_catb( &My_Listeners,(char*) &sock, sizeof(int) )) {
-               Log( LOG_CRIT, "Can't add socket to My_Listeners array: %s!", strerror( errno ));
-               close( sock );
+       if (!array_catb(&My_Listeners, (char *)&sock, sizeof(int))) {
+               Log(LOG_CRIT, "Can't add socket to My_Listeners array: %s!",
+                   strerror(errno));
+               close(sock);
                return -1;
        }
 
@@ -865,6 +938,9 @@ va_dcl
 #endif
 {
        char buffer[COMMAND_LEN];
+#ifdef ICONV
+       char *ptr, *message;
+#endif
        size_t len;
        bool ok;
        va_list ap;
@@ -905,6 +981,16 @@ va_dcl
                        CUT_TXTSUFFIX);
        }
 
+#ifdef ICONV
+       ptr = strchr(buffer + 1, ':');
+       if (ptr) {
+               ptr++;
+               message = Conn_EncodingTo(Idx, ptr);
+               if (message != ptr)
+                       strlcpy(ptr, message, sizeof(buffer) - (ptr - buffer));
+       }
+#endif
+
 #ifdef SNIFFER
        if (NGIRCd_Sniffer)
                Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer);
@@ -918,6 +1004,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.
@@ -936,22 +1046,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:
@@ -1041,7 +1154,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie
        Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCLOSING );
 
        port = ng_ipaddr_getport(&My_Connections[Idx].addr);
-       Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx,
+       Log(LOG_INFO, "Shutting down connection %d (%s) with \"%s:%d\" ...", Idx,
            LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port);
 
        /* Search client, if any */
@@ -1115,7 +1228,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie
                in_p = (int)(( in_k * 100 ) / in_z_k );
                out_p = (int)(( out_k * 100 ) / out_z_k );
                Log(LOG_INFO,
-                   "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
+                   "Connection %d with \"%s:%d\" closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
                    Idx, My_Connections[Idx].host, port,
                    in_k, in_z_k, in_p, out_k, out_z_k, out_p);
        }
@@ -1123,7 +1236,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie
 #endif
        {
                Log(LOG_INFO,
-                   "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).",
+                   "Connection %d with \"%s:%d\" closed (in: %.1fk, out: %.1fk).",
                    Idx, My_Connections[Idx].host, port,
                    in_k, out_k);
        }
@@ -1143,6 +1256,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 );
@@ -1223,6 +1338,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.
  *
@@ -1319,17 +1448,18 @@ Count_Connections(ng_ipaddr_t *a)
  * Initialize new client connection on a listening socket.
  *
  * @param Sock Listening socket descriptor.
+ * @param IsSSL        true if this socket expects SSL-encrypted data.
  * @returns    Accepted socket descriptor or -1 on error.
  */
 static int
-New_Connection(int Sock)
+New_Connection(int Sock, UNUSED bool IsSSL)
 {
 #ifdef TCPWRAP
        struct request_info req;
 #endif
        ng_ipaddr_t new_addr;
        char ip_str[NG_INET_ADDRSTRLEN];
-       int new_sock, new_sock_len, identsock;
+       int new_sock, new_sock_len;
        CLIENT *c;
        long cnt;
 
@@ -1421,7 +1551,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!");
@@ -1446,33 +1576,59 @@ New_Connection(int Sock)
 
        Client_SetHostname(c, My_Connections[new_sock].host);
 
-       Log(LOG_INFO, "Accepted connection %d from %s:%d on socket %d.",
+       Log(LOG_INFO, "Accepted connection %d from \"%s:%d\" on socket %d.",
            new_sock, My_Connections[new_sock].host,
            ng_ipaddr_getport(&new_addr), Sock);
+       Account_Connection();
+
+#ifdef SSL_SUPPORT
+       /* Delay connection initalization until SSL handshake is finished */
+       if (!IsSSL)
+#endif
+               Conn_StartLogin(new_sock);
+
+       return new_sock;
+} /* New_Connection */
+
+
+/**
+ * Finish connection initialization, start resolver subprocess.
+ *
+ * @param Idx Connection index.
+ */
+GLOBAL void
+Conn_StartLogin(CONN_ID Idx)
+{
+       int ident_sock = -1;
+
+       assert(Idx >= 0);
+
+       /* Nothing to do if DNS (and resolver subprocess) is disabled */
+       if (!Conf_DNS)
+               return;
 
-       identsock = new_sock;
 #ifdef IDENTAUTH
-       if (!Conf_Ident)
-               identsock = -1;
+       /* Should we make an IDENT request? */
+       if (Conf_Ident)
+               ident_sock = My_Connections[Idx].sock;
 #endif
-       if (Conf_DNS) {
-               if (Conf_NoticeAuth) {
+
+       if (Conf_NoticeAuth) {
+               /* Send "NOTICE AUTH" messages to the client */
 #ifdef IDENTAUTH
-                       if (Conf_Ident)
-                               (void)Conn_WriteStr(new_sock,
-                                       "NOTICE AUTH :*** Looking up your hostname and checking ident");
-                       else
+               if (Conf_Ident)
+                       (void)Conn_WriteStr(Idx,
+                               "NOTICE AUTH :*** Looking up your hostname and checking ident");
+               else
 #endif
-                               (void)Conn_WriteStr(new_sock,
-                                       "NOTICE AUTH :*** Looking up your hostname");
-               }
-               Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr,
-                            identsock, cb_Read_Resolver_Result);
+                       (void)Conn_WriteStr(Idx,
+                               "NOTICE AUTH :*** Looking up your hostname");
+               (void)Handle_Write(Idx);
        }
 
-       Account_Connection();
-       return new_sock;
-} /* New_Connection */
+       Resolve_Addr(&My_Connections[Idx].proc_stat, &My_Connections[Idx].addr,
+                    ident_sock, cb_Read_Resolver_Result);
+}
 
 
 /**
@@ -1549,13 +1705,10 @@ Read_Request( CONN_ID Idx )
 #endif
        len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
        if (len == 0) {
-               Log(LOG_INFO, "%s:%u (%s) is closing the connection ...",
-                               My_Connections[Idx].host,
-                               (unsigned int) ng_ipaddr_getport(&My_Connections[Idx].addr),
-                               ng_ipaddr_tostr(&My_Connections[Idx].addr));
-               Conn_Close(Idx,
-                          "Socket closed!", "Client closed connection",
-                          false);
+               LogDebug("Client \"%s:%u\" is closing connection %d ...",
+                        My_Connections[Idx].host,
+                        ng_ipaddr_tostr(&My_Connections[Idx].addr), Idx);
+               Conn_Close(Idx, NULL, "Client closed connection", false);
                return;
        }
 
@@ -1563,7 +1716,7 @@ Read_Request( CONN_ID Idx )
                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",
+               Conn_Close(Idx, "Read error", "Client closed connection",
                           false);
                return;
        }
@@ -1572,7 +1725,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 (connection %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);
@@ -1583,7 +1736,7 @@ Read_Request( CONN_ID Idx )
        {
                if (!array_catb( &My_Connections[Idx].rbuf, readbuf, len)) {
                        Log(LOG_ERR,
-                           "Could not append recieved data to input buffer (connection %d): %d bytes!",
+                           "Could not append received data to input buffer (connection %d): %d bytes!",
                            Idx, len);
                        Conn_Close(Idx, "Receive buffer space exhausted", NULL, false );
                }
@@ -1657,16 +1810,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;
@@ -1823,17 +1975,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()));
                        }
@@ -1919,6 +2071,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;
@@ -1992,7 +2152,8 @@ New_Server( int Server , ng_ipaddr_t *dest)
        Client_SetToken( c, TOKEN_OUTBOUND );
 
        /* Register connection */
-       Conf_Server[Server].conn_id = new_sock;
+       if (!Conf_SetServer(Server, new_sock))
+               return;
        My_Connections[new_sock].sock = new_sock;
        My_Connections[new_sock].addr = *dest;
        My_Connections[new_sock].client = c;
@@ -2032,6 +2193,11 @@ Init_Conn_Struct(CONN_ID Idx)
        My_Connections[Idx].lastdata = now;
        My_Connections[Idx].lastprivmsg = now;
        Proc_InitStruct(&My_Connections[Idx].proc_stat);
+
+#ifdef ICONV
+       My_Connections[Idx].iconv_from = (iconv_t)(-1);
+       My_Connections[Idx].iconv_to = (iconv_t)(-1);
+#endif
 } /* Init_Conn_Struct */
 
 
@@ -2158,6 +2324,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
@@ -2206,15 +2373,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)
@@ -2222,6 +2411,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 );