updates.
[silc.git] / apps / silcd / server.c
index 85cd3c0066ab64953937b8d05ecc527b69f43518..bb633a65ecd6c4839e404b2f6153dd013f1450c4 100644 (file)
@@ -10,7 +10,7 @@
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -28,6 +28,7 @@
 #include "server_internal.h"
 
 /* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
@@ -37,9 +38,13 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second);
 SILC_TASK_CALLBACK(silc_server_accept_new_connection_final);
 SILC_TASK_CALLBACK(silc_server_packet_process);
 SILC_TASK_CALLBACK(silc_server_packet_parse_real);
+SILC_TASK_CALLBACK(silc_server_close_connection_final);
+SILC_TASK_CALLBACK(silc_server_free_client_data_timeout);
 SILC_TASK_CALLBACK(silc_server_timeout_remote);
+SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
 SILC_TASK_CALLBACK(silc_server_failure_callback);
 SILC_TASK_CALLBACK(silc_server_rekey_callback);
+SILC_TASK_CALLBACK(silc_server_get_stats);
 
 /* Allocates a new SILC server object. This has to be done before the server
    can be used. After allocation one must call silc_server_init to initialize
@@ -74,18 +79,8 @@ void silc_server_free(SilcServer server)
 {
   if (server) {
 #ifdef SILC_SIM
-    SilcSimContext *sim;
-#endif
-
-    silc_free(server->local_list);
-    silc_free(server->global_list);
-    if (server->rng)
-      silc_rng_free(server->rng);
-
-    if (server->pkcs)
-      silc_pkcs_free(server->pkcs);
+    SilcSim sim;
 
-#ifdef SILC_SIM
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
       silc_sim_free(sim);
@@ -93,13 +88,50 @@ void silc_server_free(SilcServer server)
     silc_dlist_uninit(server->sim);
 #endif
 
+    silc_server_config_unref(&server->config_ref);
+    if (server->rng)
+      silc_rng_free(server->rng);
+    if (server->pkcs)
+      silc_pkcs_free(server->pkcs);
+    if (server->public_key)
+      silc_pkcs_public_key_free(server->public_key);
+    if (server->private_key)
+      silc_pkcs_private_key_free(server->private_key);
     if (server->pending_commands)
       silc_dlist_uninit(server->pending_commands);
+    if (server->id_entry)
+      silc_idlist_del_server(server->local_list, server->id_entry);
+
+    silc_idcache_free(server->local_list->clients);
+    silc_idcache_free(server->local_list->servers);
+    silc_idcache_free(server->local_list->channels);
+    silc_idcache_free(server->global_list->clients);
+    silc_idcache_free(server->global_list->servers);
+    silc_idcache_free(server->global_list->channels);
 
+    silc_free(server->sockets);
     silc_free(server);
   }
 }
 
+/* Opens a listening port.
+   XXX This function will become more general and will support multiple
+   listening ports */
+
+static bool silc_server_listen(SilcServer server, int *sock)
+{
+
+  *sock = silc_net_create_server(server->config->server_info->port,
+                               server->config->server_info->server_ip);
+  if (*sock < 0) {
+    SILC_LOG_ERROR(("Could not create server listener: %s on %hu",
+                   server->config->server_info->server_ip,
+                   server->config->server_info->port));
+    return FALSE;
+  }
+  return TRUE;
+}
+
 /* Initializes the entire SILC server. This is called always before running
    the server. This is called only once at the initialization of the program.
    This binds the server to its listenning port. After this function returns
@@ -107,29 +139,27 @@ void silc_server_free(SilcServer server)
    when everything is ok to run the server. Configuration file must be
    read and parsed before calling this. */
 
-int silc_server_init(SilcServer server)
+bool silc_server_init(SilcServer server)
 {
   int sock;
   SilcServerID *id;
   SilcServerEntry id_entry;
   SilcIDListPurge purge;
+  SilcSocketConnection newsocket = NULL;
 
   SILC_LOG_DEBUG(("Initializing server"));
-  assert(server);
-  assert(server->config);
-
-  /* Set public and private keys */
-  if (!server->config->server_info ||
-      !server->config->server_info->public_key ||
-      !server->config->server_info->private_key) {
-    SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
-    return FALSE;
-  }
+
+  server->starttime = time(NULL);
+
+  /* Take config object for us */
+  silc_server_config_ref(&server->config_ref, server->config, 
+                        server->config);
+
+  /* Steal public and private key from the config object */
   server->public_key = server->config->server_info->public_key;
   server->private_key = server->config->server_info->private_key;
-
-  /* Set default to configuration parameters */
-  silc_server_config_set_defaults(server);
+  server->config->server_info->public_key = NULL;
+  server->config->server_info->private_key = NULL;
 
   /* Register all configured ciphers, PKCS and hash functions. */
   if (!silc_server_config_register_ciphers(server))
@@ -151,19 +181,18 @@ int silc_server_init(SilcServer server)
   silc_hash_alloc("sha1", &server->sha1hash);
 
   /* Allocate PKCS context for local public and private keys */
-  silc_pkcs_alloc(server->public_key->name, &server->pkcs);
+  if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
+    goto err;
   silc_pkcs_public_key_set(server->pkcs, server->public_key);
   silc_pkcs_private_key_set(server->pkcs, server->private_key);
 
-  /* Create a listening server */
-  sock = silc_net_create_server(server->config->server_info->port,
-                               server->config->server_info->server_ip);
-  if (sock < 0) {
-    SILC_LOG_ERROR(("Could not create server listener: %s on %hu",
-                   server->config->server_info->server_ip,
-                   server->config->server_info->port));
+  /* Initialize the scheduler */
+  server->schedule = silc_schedule_init(server->config->param.connections_max);
+  if (!server->schedule)
     goto err;
-  }
+
+  /* First, register log files configuration for error output */
+  silc_server_config_setlogfiles(server);
 
   /* Initialize ID caches */
   server->local_list->clients =
@@ -179,87 +208,84 @@ int silc_server_init(SilcServer server)
   server->global_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
   server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
+  /* Create a listening server */
+  if (!silc_server_listen(server, &sock))
+    goto err;
+
+  /* Set socket to non-blocking mode */
+  silc_net_set_socket_nonblock(sock);
+  server->sock = sock;
+
   /* Allocate the entire socket list that is used in server. Eventually
      all connections will have entry in this table (it is a table of
      pointers to the actual object that is allocated individually
      later). */
   server->sockets = silc_calloc(server->config->param.connections_max,
                                sizeof(*server->sockets));
+  if (!server->sockets)
+    goto err;
 
-  do {
-    SilcSocketConnection newsocket = NULL;
-
-    /* Set socket to non-blocking mode */
-    silc_net_set_socket_nonblock(sock);
-    server->sock = sock;
-
-    /* Add ourselves also to the socket table. The entry allocated above
-       is sent as argument for fast referencing in the future. */
-    silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
-    server->sockets[sock] = newsocket;
-
-    /* Perform name and address lookups to resolve the listenning address
-       and port. */
-    if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
-                                     &newsocket->ip)) {
-      if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
-         !newsocket->ip) {
-       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
-                       newsocket->hostname ? newsocket->hostname :
-                       newsocket->ip ? newsocket->ip : ""));
-       server->stat.conn_failures++;
-       goto err;
-      }
-      if (!newsocket->hostname)
-       newsocket->hostname = strdup(newsocket->ip);
-    }
-    newsocket->port = silc_net_get_local_port(sock);
-
-    /* Create a Server ID for the server. */
-    silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
-    if (!id)
-      goto err;
+  /* Add ourselves also to the socket table. The entry allocated above
+     is sent as argument for fast referencing in the future. */
+  silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+  server->sockets[sock] = newsocket;
 
-    server->id = id;
-    server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
-    server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
-    server->id_type = SILC_ID_SERVER;
-    server->server_name = server->config->server_info->server_name;
-
-    /* Add ourselves to the server list. We don't have a router yet
-       beacuse we haven't established a route yet. It will be done later.
-       For now, NULL is sent as router. This allocates new entry to
-       the ID list. */
-    id_entry =
-      silc_idlist_add_server(server->local_list,
-                            server->config->server_info->server_name,
-                            server->server_type, server->id, NULL, NULL);
-    if (!id_entry) {
-      SILC_LOG_ERROR(("Could not add ourselves to cache"));
+  /* Perform name and address lookups to resolve the listenning address
+     and port. */
+  if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
+                                   &newsocket->ip)) {
+    if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
+       !newsocket->ip) {
+      SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+                     newsocket->hostname ? newsocket->hostname :
+                     newsocket->ip ? newsocket->ip : ""));
+      server->stat.conn_failures++;
       goto err;
     }
-    id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+    if (!newsocket->hostname)
+      newsocket->hostname = strdup(newsocket->ip);
+  }
+  newsocket->port = silc_net_get_local_port(sock);
+
+  /* Create a Server ID for the server. */
+  silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+  if (!id)
+    goto err;
+
+  server->id = id;
+  server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
+  server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
+  server->id_type = SILC_ID_SERVER;
+  server->server_name = server->config->server_info->server_name;
+  server->config->server_info->server_name = NULL;
+
+  /* Add ourselves to the server list. We don't have a router yet
+     beacuse we haven't established a route yet. It will be done later.
+     For now, NULL is sent as router. This allocates new entry to
+     the ID list. */
+  id_entry =
+    silc_idlist_add_server(server->local_list, strdup(server->server_name),
+                          server->server_type, server->id, NULL, NULL);
+  if (!id_entry) {
+    SILC_LOG_ERROR(("Could not add ourselves to cache"));
+    goto err;
+  }
+  id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
 
-    /* Put the allocated socket pointer also to the entry allocated above
-       for fast back-referencing to the socket list. */
-    newsocket->user_data = (void *)id_entry;
-    id_entry->connection = (void *)newsocket;
-    server->id_entry = id_entry;
-  } while (0);
+  /* Put the allocated socket pointer also to the entry allocated above
+     for fast back-referencing to the socket list. */
+  newsocket->user_data = (void *)id_entry;
+  id_entry->connection = (void *)newsocket;
+  server->id_entry = id_entry;
 
   /* Register protocols */
   silc_server_protocols_register();
 
-  /* Initialize the scheduler. */
-  server->schedule = silc_schedule_init(server->config->param.connections_max);
-  if (!server->schedule)
-    goto err;
-
   /* Add the first task to the scheduler. This is task that is executed by
      timeout. It expires as soon as the caller calls silc_server_run. This
      task performs authentication protocol and key exchange with our
      primary router. */
-  silc_schedule_task_add(server->schedule, sock,
+  silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_to_router,
                         (void *)server, 0, 1,
                         SILC_TASK_TIMEOUT,
@@ -275,9 +301,6 @@ int silc_server_init(SilcServer server)
                         SILC_TASK_PRI_NORMAL);
   server->listenning = TRUE;
 
-  /* Send log file configuration */
-  silc_server_config_setlogfiles(server);
-
   /* If server connections has been configured then we must be router as
      normal server cannot have server connections, only router connections. */
   if (server->config->servers) {
@@ -318,117 +341,128 @@ int silc_server_init(SilcServer server)
                         (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
+  /* If we are normal server we'll retrieve network statisticial information
+     once in a while from the router. */
+  if (server->server_type == SILC_SERVER)
+    silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats,
+                          server, 10, 0, SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
   return TRUE;
 
  err:
+  silc_server_config_unref(&server->config_ref);
   silc_net_close_server(sock);
   return FALSE;
 }
 
-/* Fork server to background */
+/* This function basically reads the config file again and switches the config
+   object pointed by the server object. After that, we have to fix various
+   things such as the server_name and the listening ports.
+   Keep in mind that we no longer have the root privileges at this point. */
 
-void silc_server_daemonise(SilcServer server)
+bool silc_server_rehash(SilcServer server)
 {
-  int i;
+  SilcServerConfig newconfig;
 
-  SILC_LOG_DEBUG(("Forking SILC server to background"));
+  SILC_LOG_INFO(("Rehashing server"));
 
-  i = fork();
+  /* Reset the logging system */
+  silc_log_quick = TRUE;
+  silc_log_flush_all();
 
-  if (i < 0) {
-    SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
-    exit(1);
-  }
-  else if (i) {
-    if (geteuid())
-      SILC_LOG_DEBUG(("Server started as user"));
-    else
-      SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
-    exit(0);
+  /* Start the main rehash phase (read again the config file) */
+  newconfig = silc_server_config_alloc(server->config_file);
+  if (!newconfig) {
+    SILC_LOG_ERROR(("Rehash FAILED."));
+    return FALSE;
   }
-  setsid();
-}
 
-/* Drop root privligies. If this cannot be done, die. */
+  /* Reinit scheduler if necessary */
+  if (newconfig->param.connections_max > server->config->param.connections_max)
+    if (!silc_schedule_reinit(server->schedule, 
+                             newconfig->param.connections_max))
+      return FALSE;
 
-void silc_server_drop(SilcServer server)
-{
-  /* Are we executing silcd as root or a regular user? */
-  if (!geteuid()) {
-    struct passwd *pw;
-    struct group *gr;
-    char *user, *group;
-
-    /* Get the values given for user and group in configuration file */
-    user = server->config->server_info->user;
-    group = server->config->server_info->group;
-
-    if (!user || !group) {
-      fprintf(stderr, "Error:" /* XXX update this error message */
-       "\tSILC server must not be run as root.  For the security of your\n"
-       "\tsystem it is strongly suggested that you run SILC under dedicated\n"
-       "\tuser account.  Modify the [Identity] configuration section to run\n"
-       "\tthe server as non-root user.\n");
-      exit(1);
-    }
+  /* Fix the server_name field */
+  if (strcmp(server->server_name, newconfig->server_info->server_name)) {
+    silc_free(server->server_name);
+    server->server_name = newconfig->server_info->server_name;
+    newconfig->server_info->server_name = NULL;
+
+    /* Update the idcache list with a fresh pointer */
+    silc_free(server->id_entry->server_name);
+    server->id_entry->server_name = strdup(server->server_name);
+    if (!silc_idcache_del_by_context(server->local_list->servers, 
+                                    server->id_entry))
+      return FALSE;
+    if (!silc_idcache_add(server->local_list->servers,
+                         server->id_entry->server_name,
+                         server->id_entry->id, server->id_entry, 0, NULL))
+      return FALSE;
+  }
 
-    /* Check whether the user/group does not begin with a number */
-    if (isdigit(user[0]) || isdigit(group[0])) {
-      SILC_LOG_DEBUG(("User and/or group starts with a number"));
-      fprintf(stderr, "Invalid user and/or group information\n");
-      fprintf(stderr, "Please assign them as names, not numbers\n");
-      exit(1);
-    }
+  /* Set logging */
+  silc_server_config_setlogfiles(server);
 
-    if (!(pw = getpwnam(user))) {
-      fprintf(stderr, "Error: No such user %s found.\n", user);
-      exit(1);
-    }
-    if (!(gr = getgrnam(group))) {
-      fprintf(stderr, "Error: No such group %s found.\n", group);
-      exit(1);
-    }
+  /* Change new key pair if necessary */
+  if (newconfig->server_info->public_key &&
+      !silc_pkcs_public_key_compare(server->public_key,
+                                   newconfig->server_info->public_key)) {
+    silc_pkcs_public_key_free(server->public_key);
+    silc_pkcs_private_key_free(server->private_key);
+    server->public_key = newconfig->server_info->public_key;
+    server->private_key = newconfig->server_info->private_key;
+    newconfig->server_info->public_key = NULL;
+    newconfig->server_info->private_key = NULL;
+
+    /* Allocate PKCS context for local public and private keys */
+    silc_pkcs_free(server->pkcs);
+    if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
+      return FALSE;
+    silc_pkcs_public_key_set(server->pkcs, server->public_key);
+    silc_pkcs_private_key_set(server->pkcs, server->private_key);
+  }
 
-    /* Check whether user and/or group is set to root. If yes, exit
-       immediately. Otherwise, setgid and setuid server to user.group */
-    if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
-      fprintf(stderr, "Error:"
-       "\tSILC server must not be run as root.  For the security of your\n"
-       "\tsystem it is strongly suggested that you run SILC under dedicated\n"
-       "\tuser account.  Modify the [Identity] configuration section to run\n"
-       "\tthe server as non-root user.\n");
-      exit(1);
-    }
+  /* Go through all configured routers after rehash */
+  silc_schedule_task_add(server->schedule, 0,
+                        silc_server_connect_to_router,
+                        (void *)server, 0, 1,
+                        SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_NORMAL);
 
-    SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
-    if (setgid(gr->gr_gid) != 0) {
-      fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
-             group, gr->gr_gid);
-      exit(1);
-    }
-#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
-    SILC_LOG_DEBUG(("Removing supplementary groups"));
-    if (setgroups(0, NULL) != 0) {
-      fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
-      exit(1);
-    }
-    SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
-    if (initgroups(user, gr->gr_gid) != 0) {
-      fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
-             "Exiting.\n", user, gr->gr_gid);
-      exit(1);
-    }
-#endif
-    SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
-    if (setuid(pw->pw_uid) != 0) {
-      fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
-              user, pw->pw_uid);
-      exit(1);
+  /* Check whether our router status has changed */
+  if (newconfig->servers) {
+    SilcServerConfigServer *ptr = newconfig->servers;
+
+    server->server_type = SILC_ROUTER;
+    while (ptr) {
+      if (ptr->backup_router) {
+       server->server_type = SILC_BACKUP_ROUTER;
+       server->backup_router = TRUE;
+       server->id_entry->server_type = SILC_BACKUP_ROUTER;
+       break;
+      }
+      ptr = ptr->next;
     }
   }
+
+  /* Our old config is gone now. We'll unreference our reference made in
+     silc_server_init and then destroy it since we are destroying it
+     underneath the application (layer which called silc_server_init). */
+  silc_server_config_unref(&server->config_ref);
+  silc_server_config_destroy(server->config);
+
+  /* Take new config context */
+  server->config = newconfig;
+  silc_server_config_ref(&server->config_ref, server->config, server->config);
+
+  SILC_LOG_DEBUG(("Server rehashed"));
+
+  return TRUE;
 }
 
 /* The heart of the server. This runs the scheduler thus runs the server.
@@ -437,8 +471,6 @@ void silc_server_drop(SilcServer server)
 
 void silc_server_run(SilcServer server)
 {
-  SILC_LOG_DEBUG(("Running server"));
-
   SILC_LOG_INFO(("SILC Server started"));
 
   /* Start the scheduler, the heart of the SILC server. When this returns
@@ -476,7 +508,8 @@ void silc_server_start_key_exchange(SilcServer server,
   SilcSocketConnection newsocket;
   SilcProtocol protocol;
   SilcServerKEInternalContext *proto_ctx;
-  SilcServerConfigRouter *conn = sconn->conn;
+  SilcServerConfigRouter *conn =
+    (SilcServerConfigRouter *) sconn->conn.ref_ptr;
   void *context;
 
   /* Cancel any possible retry timeouts */
@@ -515,22 +548,22 @@ void silc_server_start_key_exchange(SilcServer server,
 
   /* Perform key exchange protocol. silc_server_connect_to_router_second
      will be called after the protocol is finished. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
                      &protocol, proto_ctx,
                      silc_server_connect_to_router_second);
   newsocket->protocol = protocol;
-      
+
   /* Register a timeout task that will be executed if the protocol
      is not executed within set limit. */
-  proto_ctx->timeout_task = 
-    silc_schedule_task_add(server->schedule, sock, 
+  proto_ctx->timeout_task =
+    silc_schedule_task_add(server->schedule, sock,
                           silc_server_timeout_remote,
                           server, server->config->key_exchange_timeout, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
   /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
+     that scheduler will listen for incoming packets for this connection
      and sets that outgoing packets may be sent to this connection as
      well. However, this doesn't set the scheduler for outgoing traffic,
      it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
@@ -551,8 +584,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 {
   SilcServerConnection sconn = (SilcServerConnection)context;
   SilcServer server = sconn->server;
-  SilcServerConfigConnParams *param = 
-    (sconn->param ? sconn->param : &server->config->param);
+  SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+  SilcServerConfigConnParams *param =
+               (conn->param ? conn->param : &server->config->param);
 
   SILC_LOG_INFO(("Retrying connecting to a router"));
 
@@ -569,16 +603,21 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
     silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
 
   /* If we've reached max retry count, give up. */
-  if (sconn->retry_count > param->reconnect_count &&
-      param->reconnect_keep_trying == FALSE) {
+  if ((sconn->retry_count > param->reconnect_count) &&
+      !param->reconnect_keep_trying) {
     SILC_LOG_ERROR(("Could not connect to router, giving up"));
+    silc_server_config_unref(&sconn->conn);
     silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
     return;
   }
 
+  /* We will lookup a fresh pointer later */
+  silc_server_config_unref(&sconn->conn);
+
   /* Wait one before retrying */
-  silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
+  silc_schedule_task_add(server->schedule, 0, silc_server_connect_router,
                         context, sconn->retry_timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
@@ -589,33 +628,48 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
 {
   SilcServerConnection sconn = (SilcServerConnection)context;
   SilcServer server = sconn->server;
+  SilcServerConfigRouter *rconn;
   int sock;
 
-  SILC_LOG_INFO(("Connecting to the %s %s on port %d", 
-                (sconn->backup ? "backup router" : "router"), 
+  SILC_LOG_INFO(("Connecting to the %s %s on port %d",
+                (sconn->backup ? "backup router" : "router"),
                 sconn->remote_host, sconn->remote_port));
 
   server->router_connect = time(NULL);
+  rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
+                                             sconn->remote_port);
+  if (!rconn) {
+    SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
+                  (sconn->backup ? "backup router" : "router"),
+                  sconn->remote_host, sconn->remote_port));
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
+    return;
+  }
+  silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
 
   /* Connect to remote host */
   sock = silc_net_create_connection(server->config->server_info->server_ip,
-                                   sconn->remote_port, 
+                                   sconn->remote_port,
                                    sconn->remote_host);
   if (sock < 0) {
     SILC_LOG_ERROR(("Could not connect to router %s:%d",
                    sconn->remote_host, sconn->remote_port));
     if (!sconn->no_reconnect)
-      silc_schedule_task_add(server->schedule, fd,
+      silc_schedule_task_add(server->schedule, 0,
                             silc_server_connect_to_router_retry,
                             context, 0, 1, SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
+    else
+      silc_server_config_unref(&sconn->conn);
     return;
   }
 
   /* Continue with key exchange protocol */
   silc_server_start_key_exchange(server, sconn, sock);
 }
-  
+
 /* This function connects to our primary router or if we are a router this
    establishes all our primary routes. This is called at the start of the
    server to do authentication and key exchange with our router - called
@@ -637,16 +691,40 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
     SILC_LOG_DEBUG(("We are backup router/normal server"));
   }
 
+  if (!server->config->routers) {
+    /* There wasn't a configured router, we will continue but we don't
+       have a connection to outside world.  We will be standalone server. */
+    SILC_LOG_DEBUG(("No router(s), server will be standalone"));
+    server->standalone = TRUE;
+    return;
+  }
+
+  /* Cancel any possible retry timeouts */
+  silc_schedule_task_del_by_callback(server->schedule,
+                                    silc_server_connect_router);
+  silc_schedule_task_del_by_callback(server->schedule,
+                                    silc_server_connect_to_router_retry);
+
   /* Create the connections to all our routes */
-  ptr = server->config->routers;
-  while (ptr) {
-    
+  for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+
     SILC_LOG_DEBUG(("%s connection [%s] %s:%d",
                    ptr->backup_router ? "Backup router" : "Router",
                    ptr->initiator ? "Initiator" : "Responder",
                    ptr->host, ptr->port));
 
     if (ptr->initiator) {
+      /* Check whether we are connected to this host already */
+      if (silc_server_num_sockets_by_remote(server, 
+                                           silc_net_is_ip(ptr->host) ?
+                                           ptr->host : NULL,
+                                           silc_net_is_ip(ptr->host) ?
+                                           NULL : ptr->host, ptr->port,
+                                           SILC_SOCKET_TYPE_ROUTER)) {
+       SILC_LOG_DEBUG(("We are already connected to this router"));
+       continue;
+      }
+
       /* Allocate connection object for hold connection specific stuff. */
       sconn = silc_calloc(1, sizeof(*sconn));
       sconn->server = server;
@@ -661,26 +739,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       if (!server->router_conn && !sconn->backup)
        server->router_conn = sconn;
 
-      sconn->conn = ptr;
-      sconn->param = ptr->param;
-
-      silc_schedule_task_add(server->schedule, fd, 
+      silc_schedule_task_add(server->schedule, 0,
                             silc_server_connect_router,
-                            (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
+                            (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
     }
-
-    if (!ptr->next)
-      return;
-    
-    ptr = ptr->next;
   }
-
-  SILC_LOG_DEBUG(("No router(s), server will be standalone"));
-  
-  /* There wasn't a configured router, we will continue but we don't
-     have a connection to outside world.  We will be standalone server. */
-  server->standalone = TRUE;
 }
 
 /* Second part of connecting to router(s). Key exchange protocol has been
@@ -689,7 +753,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
 SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx = 
+  SilcServerKEInternalContext *ctx =
     (SilcServerKEInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcServerConnection sconn = (SilcServerConnection)ctx->context;
@@ -711,17 +775,21 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
     return;
   }
-  
+
   /* We now have the key material as the result of the key exchange
      protocol. Take the key material into use. Free the raw key material
      as soon as we've set them into use. */
-  if (!silc_server_protocol_ke_set_keys(server, ctx->ske, 
+  if (!silc_server_protocol_ke_set_keys(server, ctx->ske,
                                        ctx->sock, ctx->keymat,
                                        ctx->ske->prop->cipher,
                                        ctx->ske->prop->pkcs,
@@ -738,12 +806,16 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
     return;
-  }    
+  }
   silc_ske_free_key_material(ctx->keymat);
 
   /* Allocate internal context for the authentication protocol. This
@@ -756,29 +828,27 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   proto_ctx->dest_id_type = ctx->dest_id_type;
   proto_ctx->dest_id = ctx->dest_id;
 
-  /* Resolve the authentication method used in this connection. Check if 
+  /* Resolve the authentication method used in this connection. Check if
      we find a match from user configured connections */
-  if (!sconn->conn)
+  if (!sconn->conn.ref_ptr)
     conn = silc_server_config_find_router_conn(server, sock->hostname,
                                               sock->port);
   else
-    conn = sconn->conn;
+    conn = sconn->conn.ref_ptr;
 
   if (conn) {
-    /* Match found. Use the configured authentication method */
+    /* Match found. Use the configured authentication method. Take only
+       the passphrase, since for public key auth we automatically use
+       our local key pair. */
     if (conn->passphrase) {
-      if (conn->publickey && !server->config->prefer_passphrase_auth) {
-       proto_ctx->auth_data = conn->publickey;
-       proto_ctx->auth_data_len = 0;
+      if (conn->publickeys && !server->config->prefer_passphrase_auth) {
        proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
       } else {
        proto_ctx->auth_data = strdup(conn->passphrase);
        proto_ctx->auth_data_len = strlen(conn->passphrase);
        proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
       }
-    } else if (conn->publickey) {
-      proto_ctx->auth_data = conn->publickey;
-      proto_ctx->auth_data_len = 0;
+    } else if (conn->publickeys) {
       proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
     } else {
       proto_ctx->auth_meth = SILC_AUTH_NONE;
@@ -794,6 +864,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
@@ -812,8 +886,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
      but we won't start it yet. We will be receiving party of this
      protocol thus we will wait that connecting party will make
      their first move. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH, 
-                     &sock->protocol, proto_ctx, 
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+                     &sock->protocol, proto_ctx,
                      silc_server_connect_to_router_final);
 
   /* Register timeout task. If the protocol is not executed inside
@@ -821,8 +895,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   proto_ctx->timeout_task =
     silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_timeout_remote,
-                          (void *)server, 
-                          server->config->conn_auth_timeout, 0, 
+                          (void *)server,
+                          server->config->conn_auth_timeout, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
@@ -847,7 +921,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   unsigned char *id_string;
   SilcUInt32 id_len;
   SilcIDListData idata;
-  SilcServerConfigConnParams *param;
+  SilcServerConfigRouter *conn = NULL;
+  SilcServerConfigConnParams *param = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -894,14 +969,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SILC_LOG_INFO(("Connected to router %s", sock->hostname));
 
   /* Check that we do not have this ID already */
-  id_entry = silc_idlist_find_server_by_id(server->local_list, 
+  id_entry = silc_idlist_find_server_by_id(server->local_list,
                                           ctx->dest_id, TRUE, NULL);
   if (id_entry) {
     silc_idcache_del_by_context(server->local_list->servers, id_entry);
   } else {
-    id_entry = silc_idlist_find_server_by_id(server->global_list, 
+    id_entry = silc_idlist_find_server_by_id(server->global_list,
                                             ctx->dest_id, TRUE, NULL);
-    if (id_entry) 
+    if (id_entry)
       silc_idcache_del_by_context(server->global_list->servers, id_entry);
   }
 
@@ -909,7 +984,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
                  silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
 
   /* Add the connected router to global server list */
-  id_entry = silc_idlist_add_server(server->global_list, 
+  id_entry = silc_idlist_add_server(server->global_list,
                                    strdup(sock->hostname),
                                    SILC_ROUTER, ctx->dest_id, NULL, sock);
   if (!id_entry) {
@@ -927,7 +1002,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   idata = (SilcIDListData)sock->user_data;
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
 
-  param = (sconn->param ? sconn->param : &server->config->param);
+  conn = sconn->conn.ref_ptr;
+  param = &server->config->param;
+  if (conn && conn->param)
+    param = conn->param;
 
   /* Perform keepalive. The `hb_context' will be freed automatically
      when finally calling the silc_socket_free function. */
@@ -940,7 +1018,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   /* Register re-key timeout */
   idata->rekey->timeout = param->key_exchange_rekey;
   idata->rekey->context = (void *)server;
-  silc_schedule_task_add(server->schedule, sock->sock, 
+  silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_rekey_callback,
                         (void *)sock, idata->rekey->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -951,10 +1029,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       server->id_entry->router = id_entry;
       server->router = id_entry;
       server->standalone = FALSE;
-    
+
       /* If we are router then announce our possible servers. */
       if (server->server_type == SILC_ROUTER)
-       silc_server_announce_servers(server, FALSE, 0, 
+       silc_server_announce_servers(server, FALSE, 0,
                                     server->router->connection);
 
       /* Announce our clients and channels to the router */
@@ -977,6 +1055,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
  out:
   /* Free the temporary connection data context */
   if (sconn) {
+    silc_server_config_unref(&sconn->conn);
     silc_free(sconn->remote_host);
     silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
@@ -997,12 +1076,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   silc_free(ctx);
 }
 
-/* Host lookup callbcak that is called after the incoming connection's
+/* Host lookup callback that is called after the incoming connection's
    IP and FQDN lookup is performed. This will actually check the acceptance
    of the incoming connection and will register the key exchange protocol
    for this connection. */
 
-static void 
+static void
 silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
                                         void *context)
 {
@@ -1029,7 +1108,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   }
 
   /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
+     that scheduler will listen for incoming packets for this connection
      and sets that outgoing packets may be sent to this connection as well.
      However, this doesn't set the scheduler for outgoing traffic, it
      will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
@@ -1047,8 +1126,8 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     deny = silc_server_config_find_denied(server, sock->hostname);
   if (deny) {
     /* The connection is denied */
-    SILC_LOG_INFO(("Connection %s (%s) is denied", 
-                   sock->hostname, sock->ip));
+    SILC_LOG_INFO(("Connection %s (%s) is denied",
+                  sock->hostname, sock->ip));
     silc_server_disconnect_remote(server, sock, deny->reason ?
                                  deny->reason :
                                  "Server closed connection: "
@@ -1057,7 +1136,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     return;
   }
 
-  /* Check whether we have configred this sort of connection at all. We
+  /* Check whether we have configured this sort of connection at all. We
      have to check all configurations since we don't know what type of
      connection this is. */
   if (!(cconfig = silc_server_config_find_client(server, sock->ip)))
@@ -1065,15 +1144,15 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   if (!(sconfig = silc_server_config_find_server_conn(server, sock->ip)))
     sconfig = silc_server_config_find_server_conn(server, sock->hostname);
   if (server->server_type == SILC_ROUTER) {
-    if (!(rconfig = silc_server_config_find_router_conn(server, 
+    if (!(rconfig = silc_server_config_find_router_conn(server,
                                                        sock->ip, port)))
-      rconfig = silc_server_config_find_router_conn(server, sock->hostname, 
+      rconfig = silc_server_config_find_router_conn(server, sock->hostname,
                                                    sock->port);
   }
   if (!cconfig && !sconfig && !rconfig) {
-    SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname, 
+    SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
                   sock->ip));
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  "Server closed connection: "
                                  "Connection refused");
     server->stat.conn_failures++;
@@ -1089,12 +1168,12 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   proto_ctx->sock = sock;
   proto_ctx->rng = server->rng;
   proto_ctx->responder = TRUE;
-  proto_ctx->cconfig = cconfig;
-  proto_ctx->sconfig = sconfig;
-  proto_ctx->rconfig = rconfig;
+  silc_server_config_ref(&proto_ctx->cconfig, server->config, cconfig);
+  silc_server_config_ref(&proto_ctx->sconfig, server->config, sconfig);
+  silc_server_config_ref(&proto_ctx->rconfig, server->config, rconfig);
 
   /* Take flags for key exchange. Since we do not know what type of connection
-     this is, we go through all found configuratios and use the global ones
+     this is, we go through all found configurations and use the global ones
      as well. This will result always into strictest key exchange flags. */
   SILC_GET_SKE_FLAGS(cconfig, proto_ctx);
   SILC_GET_SKE_FLAGS(sconfig, proto_ctx);
@@ -1104,18 +1183,18 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
 
   /* Prepare the connection for key exchange protocol. We allocate the
      protocol but will not start it yet. The connector will be the
-     initiator of the protocol thus we will wait for initiation from 
+     initiator of the protocol thus we will wait for initiation from
      there before we start the protocol. */
   server->stat.auth_attempts++;
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
-                     &sock->protocol, proto_ctx, 
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+                     &sock->protocol, proto_ctx,
                      silc_server_accept_new_connection_second);
 
   /* Register a timeout task that will be executed if the connector
      will not start the key exchange protocol within specified timeout
      and the connection will be closed. */
-  proto_ctx->timeout_task = 
-    silc_schedule_task_add(server->schedule, sock->sock, 
+  proto_ctx->timeout_task =
+    silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_timeout_remote,
                           context, server->config->key_exchange_timeout, 0,
                           SILC_TASK_TIMEOUT,
@@ -1144,10 +1223,11 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
 
   /* Check for maximum allowed connections */
   if (sock > server->config->param.connections_max) {
-    SILC_LOG_ERROR(("Refusing connection, server is full, try again later"));
+    SILC_LOG_ERROR(("Refusing connection, server is full"));
     server->stat.conn_failures++;
+    silc_net_close_connection(sock);
     return;
-  }  
+  }
 
   /* Set socket options */
   silc_net_set_socket_nonblock(sock);
@@ -1161,8 +1241,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   /* Perform asynchronous host lookup. This will lookup the IP and the
      FQDN of the remote connection. After the lookup is done the connection
      is accepted further. */
-  silc_socket_host_lookup(newsocket, TRUE, 
-                         silc_server_accept_new_connection_lookup, context, 
+  silc_socket_host_lookup(newsocket, TRUE,
+                         silc_server_accept_new_connection_lookup, context,
                          server->schedule);
 }
 
@@ -1175,7 +1255,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
 SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx = 
+  SilcServerKEInternalContext *ctx =
     (SilcServerKEInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
@@ -1183,8 +1263,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+  if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
+      (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
     /* Error occured during protocol */
     silc_protocol_free(protocol);
     sock->protocol = NULL;
@@ -1194,6 +1274,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->ske)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
+    silc_server_config_unref(&ctx->cconfig);
+    silc_server_config_unref(&ctx->sconfig);
+    silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
@@ -1206,7 +1289,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   /* We now have the key material as the result of the key exchange
      protocol. Take the key material into use. Free the raw key material
      as soon as we've set them into use. */
-  if (!silc_server_protocol_ke_set_keys(server, ctx->ske, 
+  if (!silc_server_protocol_ke_set_keys(server, ctx->ske,
                                        ctx->sock, ctx->keymat,
                                        ctx->ske->prop->cipher,
                                        ctx->ske->prop->pkcs,
@@ -1222,6 +1305,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->ske)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
+    silc_server_config_unref(&ctx->cconfig);
+    silc_server_config_unref(&ctx->sconfig);
+    silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
@@ -1229,7 +1315,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                                  "Key exchange failed");
     server->stat.auth_failures++;
     return;
-  }    
+  }
   silc_ske_free_key_material(ctx->keymat);
 
   /* Allocate internal context for the authentication protocol. This
@@ -1256,17 +1342,17 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
      but we won't start it yet. We will be receiving party of this
      protocol thus we will wait that connecting party will make
      their first move. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH, 
-                     &sock->protocol, proto_ctx, 
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+                     &sock->protocol, proto_ctx,
                      silc_server_accept_new_connection_final);
 
   /* Register timeout task. If the protocol is not executed inside
      this timelimit the connection will be terminated. */
-  proto_ctx->timeout_task = 
-    silc_schedule_task_add(server->schedule, sock->sock, 
+  proto_ctx->timeout_task =
+    silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_timeout_remote,
-                          (void *)server, 
-                          server->config->conn_auth_timeout, 0, 
+                          (void *)server,
+                          server->config->conn_auth_timeout, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1278,7 +1364,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
 SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerConnAuthInternalContext *ctx = 
+  SilcServerConnAuthInternalContext *ctx =
     (SilcServerConnAuthInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
@@ -1286,7 +1372,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
   SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
-  SilcUInt32 num_sockets;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1300,6 +1385,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     if (ctx->ske)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
+    silc_server_config_unref(&ctx->cconfig);
+    silc_server_config_unref(&ctx->sconfig);
+    silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
@@ -1311,37 +1399,16 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
   entry->data.last_receive = time(NULL);
 
-  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip);
-
   switch (ctx->conn_type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
-      SilcServerConfigClient *conn = ctx->cconfig;
-      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
-
-      /* Check for maximum connections limit */
-      if (conn->param) {
-       if (conn->param->connections_max &&
-           server->stat.my_clients >= conn->param->connections_max) {
-         SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                        sock->hostname, sock->ip));
-         silc_server_disconnect_remote(server, sock, 
-                                       "Server closed connection: "
-                                       "Server is full, try again later");
-         server->stat.auth_failures++;
-         goto out;
-       }
+      SilcServerConfigClient *conn = ctx->cconfig.ref_ptr;
 
-       max_per_host = conn->param->connections_max_per_host;
-      }
-
-      if (num_sockets > max_per_host) {
-       SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                      sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Too many connections from your host");
+      /* Verify whether this connection is after all allowed to connect */
+      if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                         &server->config->param,
+                                         conn->param, ctx->ske)) {
        server->stat.auth_failures++;
        goto out;
       }
@@ -1353,12 +1420,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* Add the client to the client ID cache. The nickname and Client ID
         and other information is created after we have received NEW_CLIENT
         packet from client. */
-      client = silc_idlist_add_client(server->local_list, 
+      client = silc_idlist_add_client(server->local_list,
                                      NULL, NULL, NULL, NULL, NULL, sock, 0);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
-       silc_server_disconnect_remote(server, sock, 
+       silc_server_disconnect_remote(server, sock,
                                      "Server closed connection: "
                                      "Authentication failed");
        server->stat.auth_failures++;
@@ -1368,8 +1435,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* Statistics */
       server->stat.my_clients++;
       server->stat.clients++;
-      if (server->server_type == SILC_ROUTER)
-       server->stat.cell_clients++;
+      server->stat.cell_clients++;
 
       /* Get connection parameters */
       if (conn->param) {
@@ -1389,96 +1455,82 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       bool backup_router = FALSE;
       char *backup_replace_ip = NULL;
       SilcUInt16 backup_replace_port = 0;
-      SilcServerConfigServer *sconn = ctx->sconfig;
-      SilcServerConfigRouter *rconn = ctx->rconfig;
-      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
-
-      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && rconn) {
-       if (rconn->param) {
-         /* Check for maximum connections limit */
-         if (rconn->param->connections_max &&
-             server->stat.my_routers >= rconn->param->connections_max) {
-           silc_server_disconnect_remote(server, sock, 
-                                         "Server closed connection: "
-                                         "Server is full, try again later");
-           server->stat.auth_failures++;
-           goto out;
+      SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr;
+      SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr;
+
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                           &server->config->param,
+                                           rconn ? rconn->param : NULL,
+                                           ctx->ske)) {
+         server->stat.auth_failures++;
+         goto out;
+       }
+
+       if (rconn) {
+         if (rconn->param) {
+           if (rconn->param->keepalive_secs)
+             hearbeat_timeout = rconn->param->keepalive_secs;
          }
-         max_per_host = rconn->param->connections_max_per_host;
 
-         if (rconn->param->keepalive_secs)
-           hearbeat_timeout = rconn->param->keepalive_secs;
+         initiator = rconn->initiator;
+         backup_local = rconn->backup_local;
+         backup_router = rconn->backup_router;
+         backup_replace_ip = rconn->backup_replace_ip;
+         backup_replace_port = rconn->backup_replace_port;
        }
-
-       initiator = rconn->initiator;
-       backup_local = rconn->backup_local;
-       backup_router = rconn->backup_router;
-       backup_replace_ip = rconn->backup_replace_ip;
-       backup_replace_port = rconn->backup_replace_port;
       }
 
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && sconn) {
-       if (sconn->param) {
-         /* Check for maximum connections limit */
-         if (sconn->param->connections_max &&
-             server->stat.my_servers >= sconn->param->connections_max) {
-           SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                          sock->hostname, sock->ip));
-           silc_server_disconnect_remote(server, sock, 
-                                         "Server closed connection: "
-                                         "Server is full, try again later");
-           server->stat.auth_failures++;
-           goto out;
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                           &server->config->param,
+                                           sconn ? sconn->param : NULL,
+                                           ctx->ske)) {
+         server->stat.auth_failures++;
+         goto out;
+       }
+       if (sconn) {
+         if (sconn->param) {
+           if (sconn->param->keepalive_secs)
+             hearbeat_timeout = sconn->param->keepalive_secs;
          }
-         max_per_host = sconn->param->connections_max_per_host;
 
-         if (sconn->param->keepalive_secs)
-           hearbeat_timeout = sconn->param->keepalive_secs;
+         backup_router = sconn->backup_router;
        }
-
-       backup_router = sconn->backup_router;
       }
 
-      if (num_sockets > max_per_host) {
-       SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                      sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Too many connections from your host");
-       server->stat.auth_failures++;
-       goto out;
-      }
-
-      SILC_LOG_DEBUG(("Remote host is %s", 
-                     ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-                     "server" : (backup_router ? 
+      SILC_LOG_DEBUG(("Remote host is %s",
+                     ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+                     "server" : (backup_router ?
                                  "backup router" : "router")));
-      SILC_LOG_INFO(("Connection s (%s) is %s", sock->hostname,
-                    sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-                    "server" : (backup_router ? 
+      SILC_LOG_INFO(("Connection %s (%s) is %s", sock->hostname,
+                    sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+                    "server" : (backup_router ?
                                 "backup router" : "router")));
 
       /* Add the server into server cache. The server name and Server ID
         is updated after we have received NEW_SERVER packet from the
         server. We mark ourselves as router for this server if we really
         are router. */
-      new_server = 
+      new_server =
        silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
                                server->local_list : (backup_router ?
                                                      server->local_list :
                                                      server->global_list)),
                               NULL,
                               (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               SILC_SERVER : SILC_ROUTER), 
-                              NULL, 
+                               SILC_SERVER : SILC_ROUTER),
+                              NULL,
                               (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->id_entry : (backup_router ? 
+                               server->id_entry : (backup_router ?
                                                    server->id_entry : NULL)),
                               sock);
       if (!new_server) {
        SILC_LOG_ERROR(("Could not add new server to cache"));
        silc_free(sock->user_data);
-       silc_server_disconnect_remote(server, sock, 
+       silc_server_disconnect_remote(server, sock,
                                      "Server closed connection: "
                                      "Authentication failed");
        server->stat.auth_failures++;
@@ -1557,6 +1609,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   if (ctx->ske)
     silc_ske_free(ctx->ske);
   silc_free(ctx->dest_id);
+  silc_server_config_unref(&ctx->cconfig);
+  silc_server_config_unref(&ctx->sconfig);
+  silc_server_config_unref(&ctx->rconfig);
   silc_free(ctx);
   sock->protocol = NULL;
 }
@@ -1588,9 +1643,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     server->stat.packets_sent++;
 
-    if (sock->outbuf->data - sock->outbuf->head)
-     silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
     /* Send the packet */
     ret = silc_packet_send(sock, TRUE);
 
@@ -1601,17 +1653,17 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     if (ret == -1) {
       SILC_LOG_ERROR(("Error sending packet to connection "
-                     "%s:%d [%s]", sock->hostname, sock->port,  
+                     "%s:%d [%s]", sock->hostname, sock->port,
                      (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                       sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router")));
       return;
     }
-    
+
     /* The packet has been sent and now it is time to set the connection
-       back to only for input. When there is again some outgoing data 
-       available for this connection it will be set for output as well. 
+       back to only for input. When there is again some outgoing data
+       available for this connection it will be set for output as well.
        This call clears the output setting and sets it only for input. */
     SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
     SILC_UNSET_OUTBUF_PENDING(sock);
@@ -1628,18 +1680,18 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     if (ret == -1)
       SILC_LOG_ERROR(("Error receiving packet from connection "
-                     "%s:%d [%s] %s", sock->hostname, sock->port,  
+                     "%s:%d [%s] %s", sock->hostname, sock->port,
                      (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                       sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router"), strerror(errno)));
     return;
-  }    
+  }
 
   /* EOF */
   if (ret == 0) {
     SILC_LOG_DEBUG(("Read EOF"));
-      
+
     /* If connection is disconnecting already we will finally
        close the connection */
     if (SILC_IS_DISCONNECTING(sock)) {
@@ -1648,7 +1700,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
       silc_server_close_connection(server, sock);
       return;
     }
-      
+
     SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
     SILC_SET_DISCONNECTING(sock);
 
@@ -1660,8 +1712,8 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
        silc_server_free_sock_user_data(server, sock, NULL);
     } else if (server->router_conn && server->router_conn->sock == sock &&
             !server->router && server->standalone)
-      silc_schedule_task_add(server->schedule, 0, 
-                            silc_server_connect_to_router, 
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router,
                             server, 1, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
@@ -1686,11 +1738,11 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     hmac = idata->hmac_receive;
     sequence = idata->psn_receive;
   }
+
   /* Process the packet. This will call the parser that will then
      decrypt and parse the packet. */
-  ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
-                                   TRUE : FALSE, cipher, hmac, sequence, 
+  ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+                                   TRUE : FALSE, cipher, hmac, sequence,
                                    silc_server_packet_parse, server);
 
   /* If this socket connection is not authenticated yet and the packet
@@ -1707,7 +1759,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     silc_server_close_connection(server, sock);
   }
 }
-  
+
 /* Parses whole packet, received earlier. */
 
 SILC_TASK_CALLBACK(silc_server_packet_parse_real)
@@ -1755,12 +1807,12 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     /* Route the packet if it is not destined to us. Other ID types but
        server are handled separately after processing them. */
     if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
-       packet->dst_id_type == SILC_ID_SERVER && 
+       packet->dst_id_type == SILC_ID_SERVER &&
        sock->type != SILC_SOCKET_TYPE_CLIENT &&
        memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
-      
+
       /* Route the packet to fastest route for the destination ID */
-      void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len, 
+      void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                packet->dst_id_type);
       if (!id)
        goto out;
@@ -1815,7 +1867,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
      packets before them. */
   if ((parser_context->packet->type == SILC_PACKET_REKEY ||
        parser_context->packet->type == SILC_PACKET_REKEY_DONE) ||
-      (sock->protocol && sock->protocol->protocol && 
+      (sock->protocol && sock->protocol->protocol &&
        (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
        sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY))) {
     silc_server_packet_parse_real(server->schedule, 0, sock->sock,
@@ -1825,13 +1877,13 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
        the idata->receive_key might have become valid in the last packet
        and we want to call this processor with valid cipher. */
     if (idata)
-      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
-                                 TRUE : FALSE, idata->receive_key, 
-                                 idata->hmac_receive, idata->psn_receive, 
+      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+                                 TRUE : FALSE, idata->receive_key,
+                                 idata->hmac_receive, idata->psn_receive,
                                  silc_server_packet_parse, server);
     else
-      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
-                                 TRUE : FALSE, NULL, NULL, 0, 
+      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+                                 TRUE : FALSE, NULL, NULL, 0,
                                  silc_server_packet_parse, server);
     return FALSE;
   }
@@ -1862,7 +1914,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
 /* Parses the packet type and calls what ever routines the packet type
    requires. This is done for all incoming packets. */
 
-void silc_server_packet_parse_type(SilcServer server, 
+void silc_server_packet_parse_type(SilcServer server,
                                   SilcSocketConnection sock,
                                   SilcPacketContext *packet)
 {
@@ -1877,6 +1929,12 @@ void silc_server_packet_parse_type(SilcServer server,
     SILC_LOG_DEBUG(("Disconnect packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+    if (silc_string_is_ascii(packet->buffer->data, packet->buffer->len)) {
+      /* Duplicate to null terminate the string. */
+      char *message = silc_memdup(packet->buffer->data, packet->buffer->len);
+      SILC_LOG_ERROR(("%s", message));
+      silc_free(message);
+    }
     break;
 
   case SILC_PACKET_SUCCESS:
@@ -1906,7 +1964,7 @@ void silc_server_packet_parse_type(SilcServer server,
       f = silc_calloc(1, sizeof(*f));
       f->server = server;
       f->sock = sock;
-      
+
       /* We will wait 5 seconds to process this failure packet */
       silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_failure_callback, (void *)f, 5, 0,
@@ -1933,7 +1991,7 @@ void silc_server_packet_parse_type(SilcServer server,
       silc_server_notify(server, sock, packet);
     break;
 
-    /* 
+    /*
      * Channel packets
      */
   case SILC_PACKET_CHANNEL_MESSAGE:
@@ -2022,8 +2080,7 @@ void silc_server_packet_parse_type(SilcServer server,
 
     if (sock->protocol && sock->protocol->protocol &&
        sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
-
-      SilcServerKEInternalContext *proto_ctx = 
+      SilcServerKEInternalContext *proto_ctx =
        (SilcServerKEInternalContext *)sock->protocol->context;
 
       proto_ctx->packet = silc_packet_context_dup(packet);
@@ -2046,23 +2103,23 @@ void silc_server_packet_parse_type(SilcServer server,
         sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
 
       if (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
-       SilcServerRekeyInternalContext *proto_ctx = 
+       SilcServerRekeyInternalContext *proto_ctx =
          (SilcServerRekeyInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
        silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
       } else {
-       SilcServerKEInternalContext *proto_ctx = 
+       SilcServerKEInternalContext *proto_ctx =
          (SilcServerKEInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
        proto_ctx->dest_id_type = packet->src_id_type;
        proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
@@ -2071,7 +2128,7 @@ void silc_server_packet_parse_type(SilcServer server,
          break;
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->schedule, 
+       silc_protocol_execute(sock->protocol, server->schedule,
                              0, 100000);
       }
     } else {
@@ -2090,23 +2147,23 @@ void silc_server_packet_parse_type(SilcServer server,
         sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
 
       if (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
-       SilcServerRekeyInternalContext *proto_ctx = 
+       SilcServerRekeyInternalContext *proto_ctx =
          (SilcServerRekeyInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
        silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
       } else {
-       SilcServerKEInternalContext *proto_ctx = 
+       SilcServerKEInternalContext *proto_ctx =
          (SilcServerKEInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
        proto_ctx->dest_id_type = packet->src_id_type;
        proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
@@ -2115,7 +2172,7 @@ void silc_server_packet_parse_type(SilcServer server,
          break;
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->schedule, 
+       silc_protocol_execute(sock->protocol, server->schedule,
                              0, 100000);
       }
     } else {
@@ -2129,7 +2186,7 @@ void silc_server_packet_parse_type(SilcServer server,
      * Connection authentication request packet. When we receive this packet
      * we will send to the other end information about our mandatory
      * authentication method for the connection. This packet maybe received
-     * at any time. 
+     * at any time.
      */
     SILC_LOG_DEBUG(("Connection authentication request packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
@@ -2141,16 +2198,16 @@ void silc_server_packet_parse_type(SilcServer server,
      * Connection Authentication protocol packets
      */
   case SILC_PACKET_CONNECTION_AUTH:
-    /* Start of the authentication protocol. We receive here the 
+    /* Start of the authentication protocol. We receive here the
        authentication data and will verify it. */
     SILC_LOG_DEBUG(("Connection auth packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
-    if (sock->protocol && sock->protocol->protocol->type 
+    if (sock->protocol && sock->protocol->protocol->type
        == SILC_PROTOCOL_SERVER_CONNECTION_AUTH) {
 
-      SilcServerConnAuthInternalContext *proto_ctx = 
+      SilcServerConnAuthInternalContext *proto_ctx =
        (SilcServerConnAuthInternalContext *)sock->protocol->context;
 
       proto_ctx->packet = silc_packet_context_dup(packet);
@@ -2192,7 +2249,7 @@ void silc_server_packet_parse_type(SilcServer server,
   case SILC_PACKET_NEW_SERVER:
     /*
      * Received new server packet. This includes Server ID and some other
-     * information that we may save. This is received after server has 
+     * information that we may save. This is received after server has
      * connected to us.
      */
     SILC_LOG_DEBUG(("New Server packet"));
@@ -2254,7 +2311,7 @@ void silc_server_packet_parse_type(SilcServer server,
     if (sock->protocol && sock->protocol->protocol &&
        sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
 
-      SilcServerRekeyInternalContext *proto_ctx = 
+      SilcServerRekeyInternalContext *proto_ctx =
        (SilcServerRekeyInternalContext *)sock->protocol->context;
 
       if (proto_ctx->packet)
@@ -2278,6 +2335,14 @@ void silc_server_packet_parse_type(SilcServer server,
     silc_server_ftp(server, sock, packet);
     break;
 
+  case SILC_PACKET_RESUME_CLIENT:
+    /* Resume client */
+    SILC_LOG_DEBUG(("Resume Client packet"));
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_resume_client(server, sock, packet);
+    break;
+
   case SILC_PACKET_RESUME_ROUTER:
     /* Resume router packet received. This packet is received for backup
        router resuming protocol. */
@@ -2291,7 +2356,7 @@ void silc_server_packet_parse_type(SilcServer server,
     SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
     break;
   }
-  
+
 }
 
 /* Creates connection to a remote router. */
@@ -2307,11 +2372,10 @@ void silc_server_create_connection(SilcServer server,
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
   sconn->no_reconnect = TRUE;
-  sconn->param = &server->config->param;
 
-  silc_schedule_task_add(server->schedule, 0, 
+  silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_router,
-                        (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
+                        (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
 }
 
@@ -2360,13 +2424,13 @@ void silc_server_close_connection(SilcServer server,
     }
   }
 
-  silc_schedule_task_add(server->schedule, 0, 
+  silc_schedule_task_add(server->schedule, 0,
                         silc_server_close_connection_final,
-                        (void *)sock, 0, 1, SILC_TASK_TIMEOUT, 
+                        (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
 }
 
-/* Sends disconnect message to remote connection and disconnects the 
+/* Sends disconnect message to remote connection and disconnects the
    connection. */
 
 void silc_server_disconnect_remote(SilcServer server,
@@ -2388,8 +2452,9 @@ void silc_server_disconnect_remote(SilcServer server,
 
   /* Notify remote end that the conversation is over. The notify message
      is tried to be sent immediately. */
-  silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,  
+  silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,
                          buf, strlen(buf), TRUE);
+  silc_server_packet_queue_purge(server, sock);
 
   /* Mark the connection to be disconnected */
   SILC_SET_DISCONNECTED(sock);
@@ -2412,9 +2477,9 @@ SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
 
 /* Frees client data and notifies about client's signoff. */
 
-void silc_server_free_client_data(SilcServer server, 
+void silc_server_free_client_data(SilcServer server,
                                  SilcSocketConnection sock,
-                                 SilcClientEntry client, 
+                                 SilcClientEntry client,
                                  int notify,
                                  const char *signoff)
 {
@@ -2432,19 +2497,19 @@ void silc_server_free_client_data(SilcServer server,
     silc_server_send_notify_signoff(server, server->router->connection,
                                    server->server_type == SILC_SERVER ?
                                    FALSE : TRUE, client->id, signoff);
-    
+
   /* Remove client from all channels */
   if (notify)
-    silc_server_remove_from_channels(server, NULL, client, 
+    silc_server_remove_from_channels(server, NULL, client,
                                     TRUE, (char *)signoff, TRUE);
   else
-    silc_server_remove_from_channels(server, NULL, client, 
+    silc_server_remove_from_channels(server, NULL, client,
                                     FALSE, NULL, FALSE);
-    
+
   /* Update statistics */
   server->stat.my_clients--;
   server->stat.clients--;
-  if (server->server_type == SILC_ROUTER)
+  if (server->stat.cell_clients)
     server->stat.cell_clients--;
   SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
   SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -2453,21 +2518,21 @@ void silc_server_free_client_data(SilcServer server,
      into history (for WHOWAS command) for 5 minutes */
   i->server = server;
   i->client = client;
-  silc_schedule_task_add(server->schedule, 0, 
+  silc_schedule_task_add(server->schedule, 0,
                         silc_server_free_client_data_timeout,
                         (void *)i, 300, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
   client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+  client->mode = 0;
   client->router = NULL;
   client->connection = NULL;
-  client->mode = 0;
 }
 
 /* Frees user_data pointer from socket connection object. This also sends
    appropriate notify packets to the network to inform about leaving
    entities. */
 
-void silc_server_free_sock_user_data(SilcServer server, 
+void silc_server_free_sock_user_data(SilcServer server,
                                     SilcSocketConnection sock,
                                     const char *signoff_message)
 {
@@ -2477,7 +2542,7 @@ void silc_server_free_sock_user_data(SilcServer server,
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
-      silc_server_free_client_data(server, sock, user_data, TRUE, 
+      silc_server_free_client_data(server, sock, user_data, TRUE,
                                   signoff_message);
       break;
     }
@@ -2495,8 +2560,8 @@ void silc_server_free_sock_user_data(SilcServer server,
       if (server->router == user_data) {
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
-         silc_schedule_task_add(server->schedule, 0, 
-                                silc_server_connect_to_router, 
+         silc_schedule_task_add(server->schedule, 0,
+                                silc_server_connect_to_router,
                                 server, 1, 0,
                                 SILC_TASK_TIMEOUT,
                                 SILC_TASK_PRI_NORMAL);
@@ -2525,7 +2590,7 @@ void silc_server_free_sock_user_data(SilcServer server,
          }
 
          /* Mark this connection as replaced */
-         silc_server_backup_replaced_add(server, user_data->id, 
+         silc_server_backup_replaced_add(server, user_data->id,
                                          backup_router);
        }
       } else if (backup_router) {
@@ -2535,7 +2600,7 @@ void silc_server_free_sock_user_data(SilcServer server,
                        backup_router->server_name));
 
        /* Mark this connection as replaced */
-       silc_server_backup_replaced_add(server, user_data->id, 
+       silc_server_backup_replaced_add(server, user_data->id,
                                        backup_router);
       }
 
@@ -2554,7 +2619,7 @@ void silc_server_free_sock_user_data(SilcServer server,
                                             TRUE, TRUE);
        silc_server_update_servers_by_server(server, user_data, backup_router);
        if (server->server_type == SILC_SERVER)
-         silc_server_update_channels_by_server(server, user_data, 
+         silc_server_update_channels_by_server(server, user_data,
                                                backup_router);
       }
 
@@ -2609,7 +2674,7 @@ void silc_server_free_sock_user_data(SilcServer server,
    connection is disconnected. If the client on a channel is last, the
    channel is removed as well. This sends the SIGNOFF notify types. */
 
-void silc_server_remove_from_channels(SilcServer server, 
+void silc_server_remove_from_channels(SilcServer server,
                                      SilcSocketConnection sock,
                                      SilcClientEntry client,
                                      int notify,
@@ -2644,7 +2709,7 @@ void silc_server_remove_from_channels(SilcServer server,
        silc_schedule_task_del_by_context(server->schedule, channel->rekey);
       if (silc_idlist_del_channel(server->local_list, channel))
        server->stat.my_channels--;
-      else 
+      else
         silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
@@ -2655,7 +2720,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* If there is no global users on the channel anymore mark the channel
        as local channel. Do not check if the removed client is local client. */
-    if (server->server_type != SILC_ROUTER && channel->global_users && 
+    if (server->server_type != SILC_ROUTER && channel->global_users &&
        chl->client->router && !silc_server_channel_has_global(channel))
       channel->global_users = FALSE;
 
@@ -2669,7 +2734,7 @@ void silc_server_remove_from_channels(SilcServer server,
       /* Notify about leaving client if this channel has global users. */
       if (notify && channel->global_users)
        silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                          SILC_NOTIFY_TYPE_SIGNOFF, 
+                                          SILC_NOTIFY_TYPE_SIGNOFF,
                                           signoff_message ? 2 : 1,
                                           clidp->data, clidp->len,
                                           signoff_message, signoff_message ?
@@ -2699,7 +2764,7 @@ void silc_server_remove_from_channels(SilcServer server,
       /* Remove the channel entry */
       if (silc_idlist_del_channel(server->local_list, channel))
        server->stat.my_channels--;
-      else 
+      else
         silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
@@ -2708,7 +2773,7 @@ void silc_server_remove_from_channels(SilcServer server,
        the entire channel. */
     if (notify)
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                        SILC_NOTIFY_TYPE_SIGNOFF, 
+                                        SILC_NOTIFY_TYPE_SIGNOFF,
                                         signoff_message ? 2 : 1,
                                         clidp->data, clidp->len,
                                         signoff_message, signoff_message ?
@@ -2718,11 +2783,11 @@ void silc_server_remove_from_channels(SilcServer server,
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
        goto out;
-      
+
       /* Send the channel key to the channel. The key of course is not sent
         to the client who was removed from the channel. */
-      silc_server_send_channel_key(server, client->connection, channel, 
-                                  server->server_type == SILC_ROUTER ? 
+      silc_server_send_channel_key(server, client->connection, channel,
+                                  server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
     }
   }
@@ -2738,7 +2803,7 @@ void silc_server_remove_from_channels(SilcServer server,
    last client leaves the channel. If `notify' is FALSE notify messages
    are not sent. */
 
-int silc_server_remove_from_one_channel(SilcServer server, 
+int silc_server_remove_from_one_channel(SilcServer server,
                                        SilcSocketConnection sock,
                                        SilcChannelEntry channel,
                                        SilcClientEntry client,
@@ -2769,7 +2834,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
     if (silc_idlist_del_channel(server->local_list, channel))
       server->stat.my_channels--;
-    else 
+    else
       silc_idlist_del_channel(server->global_list, channel);
     silc_buffer_free(clidp);
     return FALSE;
@@ -2778,7 +2843,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
   /* Remove client from channel's client list */
   silc_hash_table_del(channel->user_list, chl->client);
   channel->user_count--;
-  
+
   /* If there is no global users on the channel anymore mark the channel
      as local channel. Do not check if the client is local client. */
   if (server->server_type != SILC_ROUTER && channel->global_users &&
@@ -2797,9 +2862,9 @@ int silc_server_remove_from_one_channel(SilcServer server,
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                         SILC_NOTIFY_TYPE_LEAVE, 1,
                                         clidp->data, clidp->len);
-    
+
     silc_buffer_free(clidp);
-    
+
     if (channel->rekey)
       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
@@ -2807,9 +2872,9 @@ int silc_server_remove_from_one_channel(SilcServer server,
       /* The founder auth data exists, do not remove the channel entry */
       SilcChannelClientEntry chl2;
       SilcHashTableList htl2;
-      
+
       channel->disabled = TRUE;
-      
+
       silc_hash_table_list(channel->user_list, &htl2);
       while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
        silc_hash_table_del(chl2->client->channels, channel);
@@ -2824,7 +2889,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
     /* Remove the channel entry */
     if (silc_idlist_del_channel(server->local_list, channel))
       server->stat.my_channels--;
-    else 
+    else
       silc_idlist_del_channel(server->global_list, channel);
     return FALSE;
   }
@@ -2840,7 +2905,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
 }
 
 /* Timeout callback. This is called if connection is idle or for some
-   other reason is not responding within some period of time. This 
+   other reason is not responding within some period of time. This
    disconnects the remote end. */
 
 SILC_TASK_CALLBACK(silc_server_timeout_remote)
@@ -2878,9 +2943,9 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
    are created by routers thus this function is never used by normal
    server. */
 
-SilcChannelEntry silc_server_create_new_channel(SilcServer server, 
+SilcChannelEntry silc_server_create_new_channel(SilcServer server,
                                                SilcServerID *router_id,
-                                               char *cipher, 
+                                               char *cipher,
                                                char *hmac,
                                                char *channel_name,
                                                int broadcast)
@@ -2910,7 +2975,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   channel_name = strdup(channel_name);
 
   /* Create the channel ID */
-  if (!silc_id_create_channel_id(server, router_id, server->rng, 
+  if (!silc_id_create_channel_id(server, router_id, server->rng,
                                 &channel_id)) {
     silc_free(channel_name);
     silc_cipher_free(key);
@@ -2919,8 +2984,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   }
 
   /* Create the channel */
-  entry = silc_idlist_add_channel(server->local_list, channel_name, 
-                                 SILC_CHANNEL_MODE_NONE, channel_id, 
+  entry = silc_idlist_add_channel(server->local_list, channel_name,
+                                 SILC_CHANNEL_MODE_NONE, channel_id,
                                  NULL, key, newhmac, 0);
   if (!entry) {
     silc_free(channel_name);
@@ -2934,7 +2999,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   entry->hmac_name = strdup(hmac);
 
   /* Now create the actual key material */
-  if (!silc_server_create_channel_key(server, entry, 
+  if (!silc_server_create_channel_key(server, entry,
                                      silc_cipher_get_key_len(key) / 8)) {
     silc_idlist_del_channel(server->local_list, entry);
     return NULL;
@@ -2943,8 +3008,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   /* Notify other routers about the new channel. We send the packet
      to our primary route. */
   if (broadcast && server->standalone == FALSE)
-    silc_server_send_new_channel(server, server->router->connection, TRUE, 
-                                channel_name, entry->id, 
+    silc_server_send_new_channel(server, server->router->connection, TRUE,
+                                channel_name, entry->id,
                                 silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
 
@@ -2955,9 +3020,9 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
 
 /* Same as above but creates the channel with Channel ID `channel_id. */
 
-SilcChannelEntry 
-silc_server_create_new_channel_with_id(SilcServer server, 
-                                      char *cipher, 
+SilcChannelEntry
+silc_server_create_new_channel_with_id(SilcServer server,
+                                      char *cipher,
                                       char *hmac,
                                       char *channel_name,
                                       SilcChannelID *channel_id,
@@ -2987,8 +3052,8 @@ silc_server_create_new_channel_with_id(SilcServer server,
   channel_name = strdup(channel_name);
 
   /* Create the channel */
-  entry = silc_idlist_add_channel(server->local_list, channel_name, 
-                                 SILC_CHANNEL_MODE_NONE, channel_id, 
+  entry = silc_idlist_add_channel(server->local_list, channel_name,
+                                 SILC_CHANNEL_MODE_NONE, channel_id,
                                  NULL, key, newhmac, 0);
   if (!entry) {
     silc_cipher_free(key);
@@ -2998,7 +3063,7 @@ silc_server_create_new_channel_with_id(SilcServer server,
   }
 
   /* Now create the actual key material */
-  if (!silc_server_create_channel_key(server, entry, 
+  if (!silc_server_create_channel_key(server, entry,
                                      silc_cipher_get_key_len(key) / 8)) {
     silc_idlist_del_channel(server->local_list, entry);
     return NULL;
@@ -3007,8 +3072,8 @@ silc_server_create_new_channel_with_id(SilcServer server,
   /* Notify other routers about the new channel. We send the packet
      to our primary route. */
   if (broadcast && server->standalone == FALSE)
-    silc_server_send_new_channel(server, server->router->connection, TRUE, 
-                                channel_name, entry->id, 
+    silc_server_send_new_channel(server, server->router->connection, TRUE,
+                                channel_name, entry->id,
                                 silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
 
@@ -3036,7 +3101,7 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
    but also to re-generate new key for channel. If `key_len' is provided
    it is the bytes of the key length. */
 
-bool silc_server_create_channel_key(SilcServer server, 
+bool silc_server_create_channel_key(SilcServer server,
                                    SilcChannelEntry channel,
                                    SilcUInt32 key_len)
 {
@@ -3066,7 +3131,7 @@ bool silc_server_create_channel_key(SilcServer server,
 
   /* Create channel key */
   for (i = 0; i < len; i++) channel_key[i] = silc_rng_get_byte(server->rng);
-  
+
   /* Set the key */
   silc_cipher_set_key(channel->channel_key, channel_key, len * 8);
 
@@ -3085,7 +3150,7 @@ bool silc_server_create_channel_key(SilcServer server,
   if (!channel->hmac)
     silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
   silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, len, hash);
-  silc_hmac_set_key(channel->hmac, hash, 
+  silc_hmac_set_key(channel->hmac, hash,
                    silc_hash_len(silc_hmac_get_hash(channel->hmac)));
   memset(hash, 0, sizeof(hash));
 
@@ -3098,10 +3163,10 @@ bool silc_server_create_channel_key(SilcServer server,
     if (channel->rekey->task)
       silc_schedule_task_del(server->schedule, channel->rekey->task);
 
-    channel->rekey->task = 
-      silc_schedule_task_add(server->schedule, 0, 
+    channel->rekey->task =
+      silc_schedule_task_add(server->schedule, 0,
                             silc_server_channel_key_rekey,
-                            (void *)channel->rekey, 
+                            (void *)channel->rekey,
                             server->config->channel_rekey_secs, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
@@ -3110,7 +3175,7 @@ bool silc_server_create_channel_key(SilcServer server,
   return TRUE;
 }
 
-/* Saves the channel key found in the encoded `key_payload' buffer. This 
+/* Saves the channel key found in the encoded `key_payload' buffer. This
    function is used when we receive Channel Key Payload and also when we're
    processing JOIN command reply. Returns entry to the channel. */
 
@@ -3127,7 +3192,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Decode channel key payload */
-  payload = silc_channel_key_payload_parse(key_payload->data, 
+  payload = silc_channel_key_payload_parse(key_payload->data,
                                           key_payload->len);
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
@@ -3196,7 +3261,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   if (!channel->hmac)
     silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
   silc_hash_make(silc_hmac_get_hash(channel->hmac), tmp, tmp_len, hash);
-  silc_hmac_set_key(channel->hmac, hash, 
+  silc_hmac_set_key(channel->hmac, hash,
                    silc_hash_len(silc_hmac_get_hash(channel->hmac)));
 
   memset(hash, 0, sizeof(hash));
@@ -3210,10 +3275,10 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     if (channel->rekey->task)
       silc_schedule_task_del(server->schedule, channel->rekey->task);
 
-    channel->rekey->task = 
-      silc_schedule_task_add(server->schedule, 0, 
+    channel->rekey->task =
+      silc_schedule_task_add(server->schedule, 0,
                             silc_server_channel_key_rekey,
-                            (void *)channel->rekey, 
+                            (void *)channel->rekey,
                             server->config->channel_rekey_secs, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
@@ -3274,9 +3339,9 @@ static void silc_server_announce_get_servers(SilcServer server,
 
        idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
 
-       *servers = silc_buffer_realloc(*servers, 
-                                      (*servers ? 
-                                       (*servers)->truelen + idp->len : 
+       *servers = silc_buffer_realloc(*servers,
+                                      (*servers ?
+                                       (*servers)->truelen + idp->len :
                                        idp->len));
        silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
        silc_buffer_put(*servers, idp->data, idp->len);
@@ -3292,7 +3357,7 @@ static void silc_server_announce_get_servers(SilcServer server,
   }
 }
 
-static SilcBuffer 
+static SilcBuffer
 silc_server_announce_encode_notify(SilcNotifyType notify, SilcUInt32 argc, ...)
 {
   va_list ap;
@@ -3301,7 +3366,7 @@ silc_server_announce_encode_notify(SilcNotifyType notify, SilcUInt32 argc, ...)
   va_start(ap, argc);
   p = silc_notify_payload_encode(notify, argc, ap);
   va_end(ap);
+
   return p;
 }
 
@@ -3372,9 +3437,9 @@ static void silc_server_announce_get_clients(SilcServer server,
 
        idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
-       *clients = silc_buffer_realloc(*clients, 
-                                      (*clients ? 
-                                       (*clients)->truelen + idp->len : 
+       *clients = silc_buffer_realloc(*clients,
+                                      (*clients ?
+                                       (*clients)->truelen + idp->len :
                                        idp->len));
        silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
        silc_buffer_put(*clients, idp->data, idp->len);
@@ -3384,9 +3449,9 @@ static void silc_server_announce_get_clients(SilcServer server,
        tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
                                                 2, idp->data, idp->len,
                                                 mode, 4);
-       *umodes = silc_buffer_realloc(*umodes, 
-                                     (*umodes ? 
-                                      (*umodes)->truelen + tmp->len :  
+       *umodes = silc_buffer_realloc(*umodes,
+                                     (*umodes ?
+                                      (*umodes)->truelen + tmp->len :
                                       tmp->len));
        silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
        silc_buffer_put(*umodes, tmp->data, tmp->len);
@@ -3464,7 +3529,7 @@ void silc_server_announce_get_channel_topic(SilcServer server,
     chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
     *topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                                chidp->data, chidp->len,
-                                               channel->topic, 
+                                               channel->topic,
                                                strlen(channel->topic));
     silc_buffer_free(chidp);
   }
@@ -3493,37 +3558,37 @@ void silc_server_announce_get_channel_users(SilcServer server,
     clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
 
     /* JOIN Notify */
-    tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2, 
+    tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2,
                                             clidp->data, clidp->len,
                                             chidp->data, chidp->len);
     len = tmp->len;
-    *channel_users = 
-      silc_buffer_realloc(*channel_users, 
-                         (*channel_users ? 
+    *channel_users =
+      silc_buffer_realloc(*channel_users,
+                         (*channel_users ?
                           (*channel_users)->truelen + len : len));
-    silc_buffer_pull_tail(*channel_users, 
-                         ((*channel_users)->end - 
+    silc_buffer_pull_tail(*channel_users,
+                         ((*channel_users)->end -
                           (*channel_users)->data));
-    
+
     silc_buffer_put(*channel_users, tmp->data, tmp->len);
     silc_buffer_pull(*channel_users, len);
     silc_buffer_free(tmp);
 
     /* CUMODE notify for mode change on the channel */
     SILC_PUT32_MSB(chl->mode, mode);
-    tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE, 
+    tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
                                             3, clidp->data, clidp->len,
                                             mode, 4,
                                             clidp->data, clidp->len);
     len = tmp->len;
-    *channel_users_modes = 
-      silc_buffer_realloc(*channel_users_modes, 
-                         (*channel_users_modes ? 
+    *channel_users_modes =
+      silc_buffer_realloc(*channel_users_modes,
+                         (*channel_users_modes ?
                           (*channel_users_modes)->truelen + len : len));
-    silc_buffer_pull_tail(*channel_users_modes, 
-                         ((*channel_users_modes)->end - 
+    silc_buffer_pull_tail(*channel_users_modes,
+                         ((*channel_users_modes)->end -
                           (*channel_users_modes)->data));
-    
+
     silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
     silc_buffer_pull(*channel_users_modes, len);
     silc_buffer_free(tmp);
@@ -3577,15 +3642,15 @@ void silc_server_announce_get_channels(SilcServer server,
 
        if (announce) {
          len = 4 + name_len + id_len + 4;
-         *channels = 
-           silc_buffer_realloc(*channels, 
-                               (*channels ? (*channels)->truelen + 
+         *channels =
+           silc_buffer_realloc(*channels,
+                               (*channels ? (*channels)->truelen +
                                 len : len));
-         silc_buffer_pull_tail(*channels, 
+         silc_buffer_pull_tail(*channels,
                                ((*channels)->end - (*channels)->data));
          silc_buffer_format(*channels,
                             SILC_STR_UI_SHORT(name_len),
-                            SILC_STR_UI_XNSTRING(channel->channel_name, 
+                            SILC_STR_UI_XNSTRING(channel->channel_name,
                                                  name_len),
                             SILC_STR_UI_SHORT(id_len),
                             SILC_STR_UI_XNSTRING(cid, id_len),
@@ -3596,10 +3661,10 @@ void silc_server_announce_get_channels(SilcServer server,
 
        /* Channel user modes */
        *channel_users_modes = silc_realloc(*channel_users_modes,
-                                           sizeof(**channel_users_modes) * 
+                                           sizeof(**channel_users_modes) *
                                            (i + 1));
        (*channel_users_modes)[i] = NULL;
-       *channel_ids = silc_realloc(*channel_ids, 
+       *channel_ids = silc_realloc(*channel_ids,
                                    sizeof(**channel_ids) * (i + 1));
        (*channel_ids)[i] = NULL;
        silc_server_announce_get_channel_users(server, channel,
@@ -3677,7 +3742,7 @@ void silc_server_announce_channels(SilcServer server,
 
   if (channel_users) {
     silc_buffer_push(channel_users, channel_users->data - channel_users->head);
-    SILC_LOG_HEXDUMP(("channel users"), channel_users->data, 
+    SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
                     channel_users->len);
 
     /* Send the packet */
@@ -3695,15 +3760,15 @@ void silc_server_announce_channels(SilcServer server,
     for (i = 0; i < channel_users_modes_c; i++) {
       if (!channel_users_modes[i])
         continue;
-      silc_buffer_push(channel_users_modes[i], 
-                      channel_users_modes[i]->data - 
+      silc_buffer_push(channel_users_modes[i],
+                      channel_users_modes[i]->data -
                       channel_users_modes[i]->head);
-      SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes[i]->data, 
+      SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes[i]->data,
                       channel_users_modes[i]->len);
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
-                                  channel_users_modes[i]->data, 
+                                  channel_users_modes[i]->data,
                                   channel_users_modes[i]->len,
                                   FALSE);
       silc_buffer_free(channel_users_modes[i]);
@@ -3718,15 +3783,15 @@ void silc_server_announce_channels(SilcServer server,
       if (!channel_topics[i])
        continue;
 
-      silc_buffer_push(channel_topics[i], 
-                      channel_topics[i]->data - 
+      silc_buffer_push(channel_topics[i],
+                      channel_topics[i]->data -
                       channel_topics[i]->head);
-      SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data, 
+      SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data,
                       channel_topics[i]->len);
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
-                                  channel_topics[i]->data, 
+                                  channel_topics[i]->data,
                                   channel_topics[i]->len,
                                   FALSE);
       silc_buffer_free(channel_topics[i]);
@@ -3739,7 +3804,7 @@ void silc_server_announce_channels(SilcServer server,
 
 /* Failure timeout callback. If this is called then we will immediately
    process the received failure. We always process the failure with timeout
-   since we do not want to blindly trust to received failure packets. 
+   since we do not want to blindly trust to received failure packets.
    This won't be called (the timeout is cancelled) if the failure was
    bogus (it is bogus if remote does not close the connection after sending
    the failure). */
@@ -3777,7 +3842,7 @@ void silc_server_get_users_on_channel(SilcServer server,
   silc_hash_table_list_reset(&htl);
 
   client_id_list = silc_buffer_alloc(len);
-  client_mode_list = 
+  client_mode_list =
     silc_buffer_alloc(4 * silc_hash_table_count(channel->user_list));
   silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
   silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
@@ -3797,9 +3862,9 @@ void silc_server_get_users_on_channel(SilcServer server,
     list_count++;
   }
   silc_hash_table_list_reset(&htl);
-  silc_buffer_push(client_id_list, 
+  silc_buffer_push(client_id_list,
                   client_id_list->data - client_id_list->head);
-  silc_buffer_push(client_mode_list, 
+  silc_buffer_push(client_mode_list,
                   client_mode_list->data - client_mode_list->head);
 
   *user_list = client_id_list;
@@ -3831,7 +3896,7 @@ void silc_server_save_users_on_channel(SilcServer server,
     /* Client ID */
     SILC_GET16_MSB(idp_len, user_list->data + 2);
     idp_len += 4;
-    client_id = silc_id_payload_parse_id(user_list->data, idp_len);
+    client_id = silc_id_payload_parse_id(user_list->data, idp_len, NULL);
     silc_buffer_pull(user_list, idp_len);
     if (!client_id)
       continue;
@@ -3846,12 +3911,12 @@ void silc_server_save_users_on_channel(SilcServer server,
     }
 
     global = FALSE;
-    
+
     /* Check if we have this client cached already. */
     client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                           server->server_type, &cache);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->global_list, 
+      client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, server->server_type,
                                             &cache);
       global = TRUE;
@@ -3865,10 +3930,10 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       /* We don't have that client anywhere, add it. The client is added
-        to global list since server didn't have it in the lists so it must be 
+        to global list since server didn't have it in the lists so it must be
         global. */
       client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
-                                     silc_id_dup(client_id, SILC_ID_CLIENT), 
+                                     silc_id_dup(client_id, SILC_ID_CLIENT),
                                      sock->user_data, NULL, 0);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
@@ -3886,7 +3951,7 @@ void silc_server_save_users_on_channel(SilcServer server,
 
     silc_free(client_id);
 
-    if (!silc_server_client_on_channel(client, channel)) {
+    if (!silc_server_client_on_channel(client, channel, NULL)) {
       /* Client was not on the channel, add it. */
       SilcChannelClientEntry chl = silc_calloc(1, sizeof(*chl));
       chl->client = client;
@@ -3904,17 +3969,22 @@ void silc_server_save_users_on_channel(SilcServer server,
    could not be found to the client. If the `client_id' is specified then
    it is used and the `id_data' is ignored. */
 
-SilcSocketConnection silc_server_get_client_route(SilcServer server,
-                                                 unsigned char *id_data,
-                                                 SilcUInt32 id_len,
-                                                 SilcClientID *client_id,
-                                                 SilcIDListData *idata)
+SilcSocketConnection
+silc_server_get_client_route(SilcServer server,
+                            unsigned char *id_data,
+                            SilcUInt32 id_len,
+                            SilcClientID *client_id,
+                            SilcIDListData *idata,
+                            SilcClientEntry *client_entry)
 {
   SilcClientID *id;
   SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
+  if (client_entry)
+    *client_entry = NULL;
+
   /* Decode destination Client ID */
   if (!client_id) {
     id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
@@ -3946,6 +4016,8 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
     /* Seems that client really is directly connected to us */
     if (idata)
       *idata = (SilcIDListData)client;
+    if (client_entry)
+      *client_entry = client;
     return client->connection;
   }
 
@@ -3958,11 +4030,11 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
     return server->router->connection;
   }
 
-  /* We are router and we will perform route lookup for the destination 
+  /* We are router and we will perform route lookup for the destination
      and send the packet to fastest route. */
   if (server->server_type == SILC_ROUTER && !server->standalone) {
     /* Check first that the ID is valid */
-    client = silc_idlist_find_client_by_id(server->global_list, id, 
+    client = silc_idlist_find_client_by_id(server->global_list, id,
                                           TRUE, NULL);
     if (client) {
       SilcSocketConnection dst_sock;
@@ -4006,14 +4078,14 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
     cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
     id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
     name_len = strlen(channel->channel_name);
-    
+
     len = 4 + name_len + id_len + 4;
-    buffer = silc_buffer_realloc(buffer, 
+    buffer = silc_buffer_realloc(buffer,
                                 (buffer ? (buffer)->truelen + len : len));
     silc_buffer_pull_tail(buffer, ((buffer)->end - (buffer)->data));
     silc_buffer_format(buffer,
                       SILC_STR_UI_SHORT(name_len),
-                      SILC_STR_UI_XNSTRING(channel->channel_name, 
+                      SILC_STR_UI_XNSTRING(channel->channel_name,
                                            name_len),
                       SILC_STR_UI_SHORT(id_len),
                       SILC_STR_UI_XNSTRING(cid, id_len),
@@ -4045,7 +4117,7 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, TRUE, NULL);
     if (!client && server->server_type == SILC_ROUTER)
       return NULL;
@@ -4101,18 +4173,18 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   proto_ctx->sock = sock;
   proto_ctx->responder = FALSE;
   proto_ctx->pfs = idata->rekey->pfs;
-      
+
   /* Perform rekey protocol. Will call the final callback after the
      protocol is over. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY, 
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
                      &protocol, proto_ctx, silc_server_rekey_final);
   sock->protocol = protocol;
-      
+
   /* Run the protocol */
   silc_protocol_execute(protocol, server->schedule, 0, 0);
 
   /* Re-register re-key timeout */
-  silc_schedule_task_add(server->schedule, sock->sock, 
+  silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_rekey_callback,
                         context, idata->rekey->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -4159,3 +4231,30 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     silc_ske_free(ctx->ske);
   silc_free(ctx);
 }
+
+/* Task callback used to retrieve network statistical information from
+   router server once in a while. */
+
+SILC_TASK_CALLBACK(silc_server_get_stats)
+{
+  SilcServer server = (SilcServer)context;
+  SilcBuffer idp, packet;
+
+  SILC_LOG_DEBUG(("Retrieving stats from router"));
+
+  if (!server->standalone) {
+    idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
+                                           ++server->cmd_ident, 1,
+                                           1, idp->data, idp->len);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, 0, packet->data,
+                           packet->len, FALSE);
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
+  }
+
+  silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
+                        server, 120, 0, SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_LOW);
+}