* Added global variable silc_log_timestamp that tells silclog
[silc.git] / apps / silcd / server.c
index 969682ff5f168ca3809fabb7f6ecf18ea5e1f6b7..2d739f8a11e84870bed2edd40298efe1ec797a79 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  server.c
+  server.c 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
@@ -8,8 +8,7 @@
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
+  the Free Software Foundation; version 2 of the License.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,6 +27,7 @@
 #include "server_internal.h"
 
 /* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router);
@@ -77,50 +77,127 @@ int silc_server_alloc(SilcServer *new_server)
 
 void silc_server_free(SilcServer server)
 {
-  if (server) {
+  SilcIDCacheList list;
+  SilcIDCacheEntry cache;
+
+  if (!server)
+    return;
+
 #ifdef SILC_SIM
+  {
     SilcSim sim;
-
+    
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
       silc_sim_free(sim);
     }
     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_hash_table_free(server->watcher_list);
+  silc_server_backup_free(server);
+  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);
+
+  /* Delete all channels */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->channels, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_channel(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_channel(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->channels, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_channel(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_channel(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
 
-    silc_free(server->sockets);
-    silc_free(server);
+  /* Delete all clients */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->clients, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_client(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_client(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->clients, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_client(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_client(server->global_list, cache->context);
   }
+  if (list)
+    silc_idcache_list_free(list);
+
+  /* Delete all servers */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->servers, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_server(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_server(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->servers, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_server(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_server(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
+  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_hash_table_free(server->watcher_list);
+
+  silc_hash_free(server->md5hash);
+  silc_hash_free(server->sha1hash);
+  silc_hmac_unregister_all();
+  silc_hash_unregister_all();
+  silc_cipher_unregister_all();
+  silc_pkcs_unregister_all();
+
+  silc_free(server->local_list);
+  silc_free(server->global_list);
+  silc_free(server->server_name);
+  silc_free(server->id_string);
+  silc_free(server->purge_i);
+  silc_free(server->purge_g);
+  silc_free(server);
 }
 
-/* Opens a listening port.
-   XXX This function will become more general and will support multiple
-   listening ports */
+/* Creates a new server listener. */
 
 static bool silc_server_listen(SilcServer server, const char *server_ip,
-                               SilcUInt16 port, int *sock)
+                              SilcUInt16 port, int *sock)
 {
   *sock = silc_net_create_server(port, server_ip);
   if (*sock < 0) {
@@ -132,15 +209,16 @@ static bool silc_server_listen(SilcServer server, const char *server_ip,
 }
 
 /* Adds a secondary listener. */
+
 bool silc_server_init_secondary(SilcServer server)
 {
-  int sock=0, sock_list[server->config->param.connections_max];
+  int sock = 0, sock_list[server->config->param.connections_max];
   SilcSocketConnection newsocket = NULL;
   SilcServerConfigServerInfoInterface *interface;
 
   for (interface = server->config->server_info->secondary; interface; 
        interface = interface->next, sock++) {
-         
+
     if (!silc_server_listen(server,
        interface->server_ip, interface->port, &sock_list[sock]))
       goto err;
@@ -150,9 +228,10 @@ bool silc_server_init_secondary(SilcServer server)
 
     /* 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_list[sock], 
-               SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    silc_socket_alloc(sock_list[sock],
+                     SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
     server->sockets[sock_list[sock]] = newsocket;
+    SILC_SET_LISTENER(newsocket);
 
     /* Perform name and address lookups to resolve the listenning address
        and port. */
@@ -170,23 +249,20 @@ bool silc_server_init_secondary(SilcServer server)
         newsocket->hostname = strdup(newsocket->ip);
     }
     newsocket->port = silc_net_get_local_port(sock);
-    
+
     newsocket->user_data = (void *)server->id_entry;
     silc_schedule_task_add(server->schedule, sock_list[sock],
                         silc_server_accept_new_connection,
                         (void *)server, 0, 0,
                         SILC_TASK_FD,
                         SILC_TASK_PRI_NORMAL);
-
   }
 
   return TRUE;
-  
-err:
 
+ err:
   do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
   return FALSE;
-
 }
 
 /* Initializes the entire SILC server. This is called always before running
@@ -299,6 +375,7 @@ bool silc_server_init(SilcServer server)
      is sent as argument for fast referencing in the future. */
   silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
   server->sockets[sock] = newsocket;
+  SILC_SET_LISTENER(newsocket);
 
   /* Perform name and address lookups to resolve the listenning address
      and port. */
@@ -325,7 +402,6 @@ bool silc_server_init(SilcServer server)
   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;
 
@@ -396,7 +472,7 @@ bool silc_server_init(SilcServer server)
      and removes the expired cache entries. */
 
   /* Clients local list */
-  purge = silc_calloc(1, sizeof(*purge));
+  server->purge_i = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
   purge->schedule = server->schedule;
   purge->timeout = 600;
@@ -406,7 +482,7 @@ bool silc_server_init(SilcServer server)
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
-  purge = silc_calloc(1, sizeof(*purge));
+  server->purge_g = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
   purge->schedule = server->schedule;
   purge->timeout = 300;
@@ -422,6 +498,9 @@ bool silc_server_init(SilcServer server)
                           server, 10, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
+  if (server->server_type == SILC_ROUTER)
+    server->stat.routers++;
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
@@ -433,6 +512,31 @@ bool silc_server_init(SilcServer server)
   return FALSE;
 }
 
+/* Task callback to close a socket connection after rehash */
+
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+{
+  SilcServer server = context;
+  SilcSocketConnection sock = server->sockets[fd];
+
+  if (!sock)
+    return;
+
+  SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
+                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")));
+  silc_schedule_task_del_by_context(server->schedule, sock);
+  silc_server_disconnect_remote(server, sock,
+                               SILC_STATUS_ERR_BANNED_FROM_SERVER,
+                               "This connection is removed from "
+                               "configuration");
+  if (sock->user_data)
+    silc_server_free_sock_user_data(server, sock, NULL);
+}
+
 /* 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.
@@ -501,6 +605,70 @@ bool silc_server_rehash(SilcServer server)
     silc_pkcs_private_key_set(server->pkcs, server->private_key);
   }
 
+  /* Check for unconfigured server and router connections and close
+     connections that were unconfigured. */
+
+  if (server->config->routers) {
+    SilcServerConfigRouter *ptr;
+    SilcServerConfigRouter *newptr;
+    bool found;
+
+    for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
+       if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port &&
+           newptr->initiator == ptr->initiator) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+                                              ptr->host, ptr->port);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
+  if (server->config->servers) {
+    SilcServerConfigServer *ptr;
+    SilcServerConfigServer *newptr;
+    bool found;
+
+    for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+       if (!strcmp(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
+                                              ptr->host, 0);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
   /* Go through all configured routers after rehash */
   silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_to_router,
@@ -558,12 +726,48 @@ void silc_server_run(SilcServer server)
 
 void silc_server_stop(SilcServer server)
 {
-  SILC_LOG_DEBUG(("Stopping server"));
+  SILC_LOG_INFO(("SILC Server shutting down"));
 
   if (server->schedule) {
+    int i;
+
+    server->server_shutdown = TRUE;
+
+    /* Close all connections */
+    for (i = 0; i < server->config->param.connections_max; i++) {
+      if (!server->sockets[i])
+       continue;
+      if (!SILC_IS_LISTENER(server->sockets[i])) {
+       SilcSocketConnection sock = server->sockets[i];
+       SilcIDListData idata = sock->user_data;
+
+       if (idata)
+         idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+       silc_schedule_task_del_by_context(server->schedule,
+                                         server->sockets[i]);
+       silc_server_disconnect_remote(server, server->sockets[i], 
+                                     SILC_STATUS_OK, 
+                                     "Server is shutting down");
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock,
+                                         "Server is shutting down");
+       silc_socket_free(sock);
+      } else {
+       silc_socket_free(server->sockets[i]);
+       server->sockets[i] = NULL;
+      }
+    }
+
+    /* We are not connected to network anymore */
+    server->standalone = TRUE;
+
     silc_schedule_stop(server->schedule);
     silc_schedule_uninit(server->schedule);
     server->schedule = NULL;
+
+    silc_free(server->sockets);
+    server->sockets = NULL;
   }
 
   silc_server_protocols_unregister();
@@ -662,6 +866,15 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
   SilcServerConfigConnParams *param =
                (conn->param ? conn->param : &server->config->param);
 
+  /* Don't retry if we are shutting down. */
+  if (server->server_shutdown) {
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
+    return;
+  }
+
   SILC_LOG_INFO(("Retrying connecting to a router"));
 
   /* Calculate next timeout */
@@ -687,6 +900,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
     return;
   }
 
+  SILC_LOG_DEBUG(("Retrying connecting to a router in %d seconds",
+                 sconn->retry_timeout));
+
   /* We will lookup a fresh pointer later */
   silc_server_config_unref(&sconn->conn);
 
@@ -705,6 +921,14 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   SilcServerConfigRouter *rconn;
   int sock;
 
+  /* Don't connect if we are shutting down. */
+  if (server->server_shutdown) {
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
+    return;
+  }
+
   SILC_LOG_INFO(("Connecting to the %s %s on port %d",
                 (sconn->backup ? "backup router" : "router"),
                 sconn->remote_host, sconn->remote_port));
@@ -756,20 +980,19 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
   SilcServerConnection sconn;
   SilcServerConfigRouter *ptr;
 
-  SILC_LOG_DEBUG(("Connecting to router(s)"));
+  /* Don't connect if we are shutting down. */
+  if (server->server_shutdown)
+    return;
 
-  if (server->server_type == SILC_SERVER) {
-    SILC_LOG_DEBUG(("We are normal server"));
-  } else if (server->server_type == SILC_ROUTER) {
-    SILC_LOG_DEBUG(("We are router"));
-  } else {
-    SILC_LOG_DEBUG(("We are backup router/normal server"));
-  }
+  SILC_LOG_DEBUG(("We are %s",
+                 (server->server_type == SILC_SERVER ?
+                  "normal server" : server->server_type == SILC_ROUTER ?
+                  "router" : "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"));
+    SILC_LOG_DEBUG(("No router(s), we are standalone"));
     server->standalone = TRUE;
     return;
   }
@@ -788,6 +1011,11 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
                    ptr->initiator ? "Initiator" : "Responder",
                    ptr->host, ptr->port));
 
+    if (server->server_type == SILC_ROUTER && ptr->backup_router &&
+       ptr->initiator == FALSE && !server->backup_router &&
+       !silc_server_config_get_backup_router(server))
+      server->wait_backup = TRUE;
+
     if (ptr->initiator) {
       /* Check whether we are connected to this host already */
       if (silc_server_num_sockets_by_remote(server, 
@@ -850,14 +1078,28 @@ 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, 
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router_retry,
+                            sconn, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      return;
+    }
+
+    /* Call completion to indicate error */
+    if (sconn->callback)
+      (*sconn->callback)(server, NULL, sconn->callback_context);
+
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     return;
   }
 
@@ -881,14 +1123,28 @@ 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, 
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router_retry,
+                            sconn, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      return;
+    }
+
+    /* Call completion to indicate error */
+    if (sconn->callback)
+      (*sconn->callback)(server, NULL, sconn->callback_context);
+
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     return;
   }
   silc_ske_free_key_material(ctx->keymat);
@@ -990,7 +1246,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SilcServer server = (SilcServer)ctx->server;
   SilcServerConnection sconn = (SilcServerConnection)ctx->context;
   SilcSocketConnection sock = ctx->sock;
-  SilcServerEntry id_entry;
+  SilcServerEntry id_entry = NULL;
   SilcBuffer packet;
   SilcServerHBContext hb_context;
   unsigned char *id_string;
@@ -1007,6 +1263,16 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     silc_free(ctx->dest_id);
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router_retry,
+                            sconn, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      goto out2;
+    }
+
     goto out;
   }
 
@@ -1058,7 +1324,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SILC_LOG_DEBUG(("New server id(%s)",
                  silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
 
-  /* Add the connected router to global server list */
+  /* Add the connected router to global server list.  Router is sent
+     as NULL since it's local to us. */
   id_entry = silc_idlist_add_server(server->global_list,
                                    strdup(sock->hostname),
                                    SILC_ROUTER, ctx->dest_id, NULL, sock);
@@ -1075,7 +1342,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   sock->user_data = (void *)id_entry;
   sock->type = SILC_SOCKET_TYPE_ROUTER;
   idata = (SilcIDListData)sock->user_data;
-  idata->status |= SILC_IDLIST_STATUS_REGISTERED;
+  idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
+                   SILC_IDLIST_STATUS_LOCAL);
 
   conn = sconn->conn.ref_ptr;
   param = &server->config->param;
@@ -1105,21 +1373,21 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       server->router = id_entry;
       server->standalone = FALSE;
 
-      /* If we are router then announce our possible servers. */
+      /* If we are router then announce our possible servers.  Backup
+        router announces also global servers. */
       if (server->server_type == SILC_ROUTER)
-       silc_server_announce_servers(server, FALSE, 0,
-                                    server->router->connection);
+       silc_server_announce_servers(server,
+                                    server->backup_router ? TRUE : FALSE,
+                                    0, SILC_PRIMARY_ROUTE(server));
 
       /* Announce our clients and channels to the router */
-      silc_server_announce_clients(server, 0, server->router->connection);
-      silc_server_announce_channels(server, 0, server->router->connection);
+      silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
+      silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
 
-#ifdef BACKUP_SINGLE_ROUTER
       /* If we are backup router then this primary router is whom we are
         backing up. */
       if (server->server_type == SILC_BACKUP_ROUTER)
        silc_server_backup_add(server, server->id_entry, sock->ip, 0, TRUE);
-#endif /* BACKUP_SINGLE_ROUTER */
     }
   } else {
     /* Add this server to be our backup router */
@@ -1129,12 +1397,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
 
   sock->protocol = NULL;
 
+ out:
   /* Call the completion callback to indicate that we've connected to
      the router */
-  if (sconn->callback)
+  if (sconn && sconn->callback)
     (*sconn->callback)(server, id_entry, sconn->callback_context);
 
- out:
   /* Free the temporary connection data context */
   if (sconn) {
     silc_server_config_unref(&sconn->conn);
@@ -1145,6 +1413,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   if (sconn == server->router_conn)
     server->router_conn = NULL;
 
+ out2:
   /* Free the protocol object */
   if (sock->protocol == protocol)
     sock->protocol = NULL;
@@ -1178,8 +1447,6 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
 
   context = (void *)server;
 
-  SILC_LOG_DEBUG(("Start"));
-
   /* Check whether we could resolve both IP and FQDN. */
   if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
                    server->config->require_reverse_lookup)) {
@@ -1206,6 +1473,14 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
                 sock->ip));
 
   /* Listenning port */
+  if (!server->sockets[(SilcUInt32)proto_ctx->context]) {
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                 "Connection refused");
+    server->stat.conn_failures++;
+    silc_free(proto_ctx);
+    return;
+  }
   port = server->sockets[(SilcUInt32)proto_ctx->context]->port;
 
   /* Check whether this connection is denied to connect to us. */
@@ -1272,6 +1547,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
      initiator of the protocol thus we will wait for initiation from
      there before we start the protocol. */
   server->stat.auth_attempts++;
+  SILC_LOG_DEBUG(("Starting key exchange protocol"));
   silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
                      &sock->protocol, proto_ctx,
                      silc_server_accept_new_connection_second);
@@ -1357,6 +1633,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
       (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
     /* Error occured during protocol */
+    SILC_LOG_DEBUG(("Error key exchange protocol"));
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     silc_ske_free_key_material(ctx->keymat);
@@ -1389,6 +1666,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                                        ctx->ske->prop->hmac,
                                        ctx->ske->prop->group,
                                        ctx->responder)) {
+    SILC_LOG_ERROR(("Error setting key material in use"));
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     silc_ske_free_key_material(ctx->keymat);
@@ -1434,6 +1712,7 @@ 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_LOG_DEBUG(("Starting connection authentication protocol"));
   silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
                      &sock->protocol, proto_ctx,
                      silc_server_accept_new_connection_final);
@@ -1449,6 +1728,16 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                           SILC_TASK_PRI_LOW);
 }
 
+/* After this is called, server don't wait for backup router anymore.  
+   This gets called automatically even after we have backup router
+   connection established. */
+
+SILC_TASK_CALLBACK(silc_server_backup_router_wait)
+{
+  SilcServer server = context;
+  server->wait_backup = FALSE;
+}
+
 /* Final part of accepting new connection. The connection has now
    been authenticated and keys has been exchanged. We also know whether
    this is client or server connection. */
@@ -1465,11 +1754,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   void *id_entry;
   SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
 
-  SILC_LOG_DEBUG(("Start"));
-
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
+    SILC_LOG_DEBUG(("Error during authentication protocol"));
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     if (ctx->packet)
@@ -1505,6 +1793,36 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
        goto out;
       }
 
+      /* If we are primary router and we have backup router configured
+        but it has not connected to use yet, do not accept any other
+        connection. */
+      if (server->wait_backup && server->server_type == SILC_ROUTER &&
+         !server->backup_router) {
+       SilcServerConfigRouter *router;
+       router = silc_server_config_get_backup_router(server);
+       if (router && strcmp(server->config->server_info->primary->server_ip,
+                            sock->ip) &&
+           silc_server_find_socket_by_host(server,
+                                           SILC_SOCKET_TYPE_SERVER,
+                                           router->backup_replace_ip, 0)) {
+         SILC_LOG_INFO(("Will not accept connections because we do "
+                        "not have backup router connection established"));
+         silc_server_disconnect_remote(server, sock, 
+                                       SILC_STATUS_ERR_PERM_DENIED,
+                                       "We do not have connection to backup "
+                                       "router established, try later");
+         silc_free(sock->user_data);
+         server->stat.auth_failures++;
+
+         /* From here on, wait 10 seconds for the backup router to appear. */
+         silc_schedule_task_add(server->schedule, 0,
+                                silc_server_backup_router_wait,
+                                (void *)server, 10, 0,
+                                SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+         goto out;
+       }
+      }
+
       SILC_LOG_DEBUG(("Remote host is client"));
       SILC_LOG_INFO(("Connection %s (%s) is client", sock->hostname,
                     sock->ip));
@@ -1522,6 +1840,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
        server->stat.auth_failures++;
        goto out;
       }
+      entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
 
       /* Statistics */
       server->stat.my_clients++;
@@ -1549,12 +1868,30 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr;
       SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr;
 
+      /* If we are backup router and this is incoming server connection
+        and we do not have connection to primary router, do not allow
+        the connection. */
+      if (server->server_type == SILC_BACKUP_ROUTER &&
+         ctx->conn_type == SILC_SOCKET_TYPE_SERVER &&
+         !SILC_PRIMARY_ROUTE(server)) {
+       SILC_LOG_INFO(("Will not accept server connection because we do "
+                      "not have primary router connection established"));
+       silc_server_disconnect_remote(server, sock, 
+                                     SILC_STATUS_ERR_PERM_DENIED,
+                                     "We do not have connection to primary "
+                                     "router established, try later");
+       silc_free(sock->user_data);
+       server->stat.auth_failures++;
+       goto out;
+      }
+
       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)) {
+         silc_free(sock->user_data);
          server->stat.auth_failures++;
          goto out;
        }
@@ -1579,6 +1916,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                            &server->config->param,
                                            sconn ? sconn->param : NULL,
                                            ctx->ske)) {
+         silc_free(sock->user_data);
          server->stat.auth_failures++;
          goto out;
        }
@@ -1592,6 +1930,36 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
        }
       }
 
+      /* If we are primary router and we have backup router configured
+        but it has not connected to use yet, do not accept any other
+        connection. */
+      if (server->wait_backup && server->server_type == SILC_ROUTER &&
+         !server->backup_router && !backup_router) {
+       SilcServerConfigRouter *router;
+       router = silc_server_config_get_backup_router(server);
+       if (router && strcmp(server->config->server_info->primary->server_ip,
+                            sock->ip) &&
+           silc_server_find_socket_by_host(server,
+                                           SILC_SOCKET_TYPE_SERVER,
+                                           router->backup_replace_ip, 0)) {
+         SILC_LOG_INFO(("Will not accept connections because we do "
+                        "not have backup router connection established"));
+         silc_server_disconnect_remote(server, sock, 
+                                       SILC_STATUS_ERR_PERM_DENIED,
+                                       "We do not have connection to backup "
+                                       "router established, try later");
+         silc_free(sock->user_data);
+         server->stat.auth_failures++;
+
+         /* From here on, wait 10 seconds for the backup router to appear. */
+         silc_schedule_task_add(server->schedule, 0,
+                                silc_server_backup_router_wait,
+                                (void *)server, 10, 0,
+                                SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+         goto out;
+       }
+      }
+
       SILC_LOG_DEBUG(("Remote host is %s",
                      ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
                      "server" : (backup_router ?
@@ -1626,29 +1994,34 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
        server->stat.auth_failures++;
        goto out;
       }
-
-      /* Statistics */
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER)
-       server->stat.my_servers++;
-      else
-       server->stat.my_routers++;
-      server->stat.servers++;
+      entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
 
       id_entry = (void *)new_server;
 
       /* If the incoming connection is router and marked as backup router
         then add it to be one of our backups */
       if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && backup_router) {
-       silc_server_backup_add(server, new_server, backup_replace_ip,
-                              backup_replace_port, backup_local);
-
        /* Change it back to SERVER type since that's what it really is. */
        if (backup_local)
          ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
-
        new_server->server_type = SILC_BACKUP_ROUTER;
+
+       /* Remove the backup waiting with timeout */
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_router_wait,
+                              (void *)server, 5, 0,
+                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
       }
 
+      /* Statistics */
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
+       server->stat.my_servers++;
+      } else {
+       server->stat.my_routers++;
+       server->stat.routers++;
+      }
+      server->stat.servers++;
+
       /* Check whether this connection is to be our primary router connection
         if we do not already have the primary route. */
       if (!backup_router &&
@@ -1720,17 +2093,19 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   SilcUInt32 sequence = 0;
   int ret;
 
-  if (!sock)
+  if (!sock) {
+    SILC_LOG_DEBUG(("Unknown socket connection"));
     return;
-
-  SILC_LOG_DEBUG(("Processing packet"));
+  }
 
   /* Packet sending */
 
   if (type == SILC_TASK_WRITE) {
     /* Do not send data to disconnected connection */
-    if (SILC_IS_DISCONNECTED(sock))
+    if (SILC_IS_DISCONNECTED(sock)) {
+      SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
       return;
+    }
 
     server->stat.packets_sent++;
 
@@ -1820,8 +2195,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     return;
   }
 
-  server->stat.packets_received++;
-
   /* Get keys and stuff from ID entry */
   idata = (SilcIDListData)sock->user_data;
   if (idata) {
@@ -1862,7 +2235,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   SilcIDListData idata = (SilcIDListData)sock->user_data;
   int ret;
 
-  SILC_LOG_DEBUG(("Start"));
+  server->stat.packets_received++;
 
   /* Parse the packet */
   if (parse_ctx->normal)
@@ -1871,23 +2244,27 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
 
   /* If entry is disabled ignore what we got. */
-  if (ret != SILC_PACKET_RESUME_ROUTER &&
-      idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
+  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED && 
+      ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
+      ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE) {
     SILC_LOG_DEBUG(("Connection is disabled"));
     goto out;
   }
 
-  if (ret == SILC_PACKET_NONE)
+  if (ret == SILC_PACKET_NONE) {
+    SILC_LOG_DEBUG(("Error parsing packet"));
     goto out;
+  }
 
   /* Check that the the current client ID is same as in the client's packet. */
   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry client = (SilcClientEntry)sock->user_data;
-    if (client && client->id) {
+    if (client && client->id && packet->src_id) {
       void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
                                packet->src_id_type);
       if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
        silc_free(id);
+       SILC_LOG_DEBUG(("Packet source is not same as sender"));
        goto out;
       }
       silc_free(id);
@@ -1897,7 +2274,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   if (server->server_type == SILC_ROUTER) {
     /* 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) &&
+    if (packet->dst_id && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
        packet->dst_id_type == SILC_ID_SERVER &&
        sock->type != SILC_SOCKET_TYPE_CLIENT &&
        memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
@@ -1919,19 +2296,17 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   /* Parse the incoming packet type */
   silc_server_packet_parse_type(server, sock, packet);
 
-  if (server->server_type == SILC_ROUTER) {
-    /* Broadcast packet if it is marked as broadcast packet and it is
-       originated from router and we are router. */
-    if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
-       packet->flags & SILC_PACKET_FLAG_BROADCAST &&
-       !server->standalone) {
-      /* Broadcast to our primary route */
-      silc_server_packet_broadcast(server, server->router->connection, packet);
-
-      /* If we have backup routers then we need to feed all broadcast
-        data to those servers. */
-      silc_server_backup_broadcast(server, sock, packet);
-    }
+  /* Broadcast packet if it is marked as broadcast packet and it is
+     originated from router and we are router. */
+  if (server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      packet->flags & SILC_PACKET_FLAG_BROADCAST) {
+    /* Broadcast to our primary route */
+    silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
+
+    /* If we have backup routers then we need to feed all broadcast
+       data to those servers. */
+    silc_server_backup_broadcast(server, sock, packet);
   }
 
  out:
@@ -2012,7 +2387,8 @@ void silc_server_packet_parse_type(SilcServer server,
   SilcPacketType type = packet->type;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
 
-  SILC_LOG_DEBUG(("Parsing packet type %d", type));
+  SILC_LOG_DEBUG(("Received %s packet [flags %d]",
+                 silc_get_packet_name(type), packet->flags));
 
   /* Parse the packet type */
   switch (type) {
@@ -2021,8 +2397,6 @@ void silc_server_packet_parse_type(SilcServer server,
       SilcStatus status;
       char *message = NULL;
 
-      SILC_LOG_DEBUG(("Disconnect packet"));
-
       if (packet->flags & SILC_PACKET_FLAG_LIST)
        break;
       if (packet->buffer->len < 1)
@@ -2031,13 +2405,19 @@ void silc_server_packet_parse_type(SilcServer server,
       status = (SilcStatus)packet->buffer->data[0];
       if (packet->buffer->len > 1 &&
          silc_utf8_valid(packet->buffer->data + 1, packet->buffer->len - 1))
-       message = silc_memdup(packet->buffer->data, packet->buffer->len);
+       message = silc_memdup(packet->buffer->data + 1,
+                             packet->buffer->len - 1);
 
-      SILC_LOG_ERROR(("Disconnected by %s (%s): %s (%d) %s", 
-                     sock->ip, sock->hostname,
-                     silc_get_status_message(status), status,
-                     message ? message : ""));
+      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", 
+                    sock->ip, sock->hostname,
+                    silc_get_status_message(status), status,
+                    message ? message : ""));
       silc_free(message);
+
+      /* Handle the disconnection from our end too */
+      if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_close_connection(server, sock);
     }
     break;
 
@@ -2047,7 +2427,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * one protocol for connection executing at once hence this
      * success message is for whatever protocol is executing currently.
      */
-    SILC_LOG_DEBUG(("Success packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     if (sock->protocol)
@@ -2060,7 +2439,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * one protocol for connection executing at once hence this
      * failure message is for whatever protocol is executing currently.
      */
-    SILC_LOG_DEBUG(("Failure packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     if (sock->protocol) {
@@ -2077,7 +2455,6 @@ void silc_server_packet_parse_type(SilcServer server,
     break;
 
   case SILC_PACKET_REJECT:
-    SILC_LOG_DEBUG(("Reject packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     return;
@@ -2088,7 +2465,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * Received notify packet. Server can receive notify packets from
      * router. Server then relays the notify messages to clients if needed.
      */
-    SILC_LOG_DEBUG(("Notify packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       silc_server_notify_list(server, sock, packet);
     else
@@ -2104,7 +2480,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * (although probably most common ones) thus they are handled
      * specially.
      */
-    SILC_LOG_DEBUG(("Channel Message packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     idata->last_receive = time(NULL);
@@ -2118,7 +2493,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * locally connected clients on the particular channel. Router
      * never receives this channel and thus is ignored.
      */
-    SILC_LOG_DEBUG(("Channel Key packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_channel_key(server, sock, packet);
@@ -2132,7 +2506,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * Recived command. Processes the command request and allocates the
      * command context and calls the command.
      */
-    SILC_LOG_DEBUG(("Command packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_command_process(server, sock, packet);
@@ -2144,7 +2517,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * may be reply to command sent by us or reply to command sent by client
      * that we've routed further.
      */
-    SILC_LOG_DEBUG(("Command Reply packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_command_reply(server, sock, packet);
@@ -2158,7 +2530,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * Received private message packet. The packet is coming from either
      * client or server.
      */
-    SILC_LOG_DEBUG(("Private Message packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     idata->last_receive = time(NULL);
@@ -2178,7 +2549,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * Key Exchange protocol packets
      */
   case SILC_PACKET_KEY_EXCHANGE:
-    SILC_LOG_DEBUG(("KE packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
@@ -2198,7 +2568,6 @@ void silc_server_packet_parse_type(SilcServer server,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE_1:
-    SILC_LOG_DEBUG(("KE 1 packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
@@ -2242,7 +2611,6 @@ void silc_server_packet_parse_type(SilcServer server,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE_2:
-    SILC_LOG_DEBUG(("KE 2 packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
@@ -2292,7 +2660,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * authentication method for the connection. This packet maybe received
      * at any time.
      */
-    SILC_LOG_DEBUG(("Connection authentication request packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_connection_auth_request(server, sock, packet);
@@ -2304,7 +2671,6 @@ void silc_server_packet_parse_type(SilcServer server,
   case SILC_PACKET_CONNECTION_AUTH:
     /* 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;
 
@@ -2331,7 +2697,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * to distribute information about new registered entities in the
      * SILC network.
      */
-    SILC_LOG_DEBUG(("New ID packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       silc_server_new_id_list(server, sock, packet);
     else
@@ -2344,7 +2709,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * we will use to create initial client ID. After creating new
      * ID we will send it to the client.
      */
-    SILC_LOG_DEBUG(("New Client packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_new_client(server, sock, packet);
@@ -2356,7 +2720,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * information that we may save. This is received after server has
      * connected to us.
      */
-    SILC_LOG_DEBUG(("New Server packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_new_server(server, sock, packet);
@@ -2367,7 +2730,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * Received new channel packet. Information about new channel in the
      * network are distributed using this packet.
      */
-    SILC_LOG_DEBUG(("New Channel packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       silc_server_new_channel_list(server, sock, packet);
     else
@@ -2378,7 +2740,6 @@ void silc_server_packet_parse_type(SilcServer server,
     /*
      * Received heartbeat.
      */
-    SILC_LOG_DEBUG(("Heartbeat packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     break;
@@ -2387,7 +2748,6 @@ void silc_server_packet_parse_type(SilcServer server,
     /*
      * Received heartbeat.
      */
-    SILC_LOG_DEBUG(("Key agreement packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_key_agreement(server, sock, packet);
@@ -2398,7 +2758,6 @@ void silc_server_packet_parse_type(SilcServer server,
      * Received re-key packet. The sender wants to regenerate the session
      * keys.
      */
-    SILC_LOG_DEBUG(("Re-key packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_rekey(server, sock, packet);
@@ -2408,7 +2767,6 @@ void silc_server_packet_parse_type(SilcServer server,
     /*
      * The re-key is done.
      */
-    SILC_LOG_DEBUG(("Re-key done packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
@@ -2433,7 +2791,6 @@ void silc_server_packet_parse_type(SilcServer server,
 
   case SILC_PACKET_FTP:
     /* FTP packet */
-    SILC_LOG_DEBUG(("FTP packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_ftp(server, sock, packet);
@@ -2441,7 +2798,6 @@ void silc_server_packet_parse_type(SilcServer server,
 
   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);
@@ -2450,7 +2806,6 @@ void silc_server_packet_parse_type(SilcServer server,
   case SILC_PACKET_RESUME_ROUTER:
     /* Resume router packet received. This packet is received for backup
        router resuming protocol. */
-    SILC_LOG_DEBUG(("Resume router packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     silc_server_backup_resume_router(server, sock, packet);
@@ -2460,7 +2815,6 @@ 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. */
@@ -2485,7 +2839,7 @@ void silc_server_create_connection(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_close_connection_final)
 {
-  silc_socket_free((SilcSocketConnection)context);
+  silc_socket_free(context);
 }
 
 /* Closes connection to socket connection */
@@ -2493,15 +2847,24 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock)
 {
-  if (!server->sockets[sock->sock])
+  char tmp[128];
+
+  if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
+    silc_schedule_task_add(server->schedule, 0,
+                          silc_server_close_connection_final,
+                          (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
     return;
+  }
 
-  SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
+  memset(tmp, 0, sizeof(tmp));
+  silc_socket_get_error(sock, tmp, sizeof(tmp));
+  SILC_LOG_INFO(("Closing connection %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")));
+                   "Router"), tmp[0] ? tmp : ""));
 
   /* We won't listen for this connection anymore */
   silc_schedule_unset_listen_fd(server->schedule, sock->sock);
@@ -2520,6 +2883,7 @@ void silc_server_close_connection(SilcServer server,
     /* If any protocol is active cancel its execution. It will call
        the final callback which will finalize the disconnection. */
     if (sock->protocol) {
+      SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
       silc_protocol_cancel(sock->protocol, server->schedule);
       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
       silc_protocol_execute_final(sock->protocol, server->schedule);
@@ -2597,6 +2961,8 @@ SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
 {
   FreeClientInternal i = (FreeClientInternal)context;
 
+  assert(!silc_hash_table_count(i->client->channels));
+
   silc_idlist_del_data(i->client);
   silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
   silc_free(i);
@@ -2610,7 +2976,17 @@ void silc_server_free_client_data(SilcServer server,
                                  int notify,
                                  const char *signoff)
 {
-  FreeClientInternal i = silc_calloc(1, sizeof(*i));
+  SILC_LOG_DEBUG(("Freeing client data"));
+
+#if 1
+  if (!client->router && !client->connection &&
+      !(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+    SILC_LOG_ERROR(("****** freeing data for already unregistered client -s"));
+    SILC_LOG_ERROR(("****** Contact Pekka"));
+    SILC_LOG_ERROR(("****** freeing data for already unregistered client -e"));
+    return;
+  }
+#endif
 
   /* If there is pending outgoing data for the client then purge it
      to the network before removing the client entry. */
@@ -2623,23 +2999,23 @@ void silc_server_free_client_data(SilcServer server,
                                     SILC_NOTIFY_TYPE_SIGNOFF);
 
     /* Send SIGNOFF notify to routers. */
-    if (notify && !server->standalone && server->router)
-      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,
-                                      TRUE, (char *)signoff, TRUE);
-    else
-      silc_server_remove_from_channels(server, NULL, client,
-                                      FALSE, NULL, FALSE);
-
-    /* Remove this client from watcher list if it is */
-    silc_server_del_from_watcher_list(server, client);
+      silc_server_send_notify_signoff(server, SILC_PRIMARY_ROUTE(server),
+                                     SILC_BROADCAST(server), client->id,
+                                     signoff);
   }
 
+  /* Remove client from all channels */
+  if (notify)
+    silc_server_remove_from_channels(server, NULL, client,
+                                    TRUE, (char *)signoff, TRUE);
+  else
+    silc_server_remove_from_channels(server, NULL, client,
+                                    FALSE, NULL, FALSE);
+
+  /* Remove this client from watcher list if it is */
+  silc_server_del_from_watcher_list(server, client);
+
   /* Update statistics */
   server->stat.my_clients--;
   server->stat.clients--;
@@ -2650,17 +3026,26 @@ void silc_server_free_client_data(SilcServer server,
   silc_schedule_task_del_by_context(server->schedule, client);
 
   /* We will not delete the client entry right away. We will take it
-     into history (for WHOWAS command) for 5 minutes */
-  i->server = server;
-  i->client = client;
-  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;
+     into history (for WHOWAS command) for 5 minutes, unless we're
+     shutting down server. */
+  if (!server->server_shutdown) {
+    FreeClientInternal i = silc_calloc(1, sizeof(*i));
+    i->server = server;
+    i->client = client;
+    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->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+    client->mode = 0;
+    client->router = NULL;
+    client->connection = NULL;
+  } else {
+    /* Delete directly since we're shutting down server */
+    silc_idlist_del_data(client);
+    silc_idlist_del_client(server->local_list, client);
+  }
 }
 
 /* Frees user_data pointer from socket connection object. This also sends
@@ -2671,8 +3056,6 @@ void silc_server_free_sock_user_data(SilcServer server,
                                     SilcSocketConnection sock,
                                     const char *signoff_message)
 {
-  SILC_LOG_DEBUG(("Start"));
-
   switch (sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
@@ -2687,9 +3070,19 @@ void silc_server_free_sock_user_data(SilcServer server,
       SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
       SilcServerEntry backup_router = NULL;
 
+      SILC_LOG_DEBUG(("Freeing server data"));
+
       if (user_data->id)
        backup_router = silc_server_backup_get(server, user_data->id);
 
+      if (!server->backup_router && server->server_type == SILC_ROUTER &&
+         backup_router == server->id_entry &&
+         sock->type != SILC_SOCKET_TYPE_ROUTER)
+       backup_router = NULL;
+
+      if (server->server_shutdown)
+       backup_router = NULL;
+
       /* If this was our primary router connection then we're lost to
         the outside world. */
       if (server->router == user_data) {
@@ -2706,24 +3099,22 @@ void silc_server_free_sock_user_data(SilcServer server,
          server->standalone = TRUE;
          backup_router = NULL;
        } else {
-         SILC_LOG_INFO(("New primary router is backup router %s",
-                        backup_router->server_name));
-         SILC_LOG_DEBUG(("New primary router is backup router %s",
-                         backup_router->server_name));
-#ifdef BACKUP_SINGLE_ROUTER
          if (server->id_entry != backup_router) {
-#endif /* BACKUP_SINGLE_ROUTER */
+           SILC_LOG_INFO(("New primary router is backup router %s",
+                          backup_router->server_name));
            server->id_entry->router = backup_router;
            server->router = backup_router;
            server->router_connect = time(0);
            server->backup_primary = TRUE;
-#ifdef BACKUP_SINGLE_ROUTER
          } else {
+           SILC_LOG_INFO(("We are now new primary router in this cell"));
            server->id_entry->router = NULL;
            server->router = NULL;
            server->standalone = TRUE;
+
+           /* We stop here to take a breath */
+           sleep(2);
          }
-#endif /* BACKUP_SINGLE_ROUTER */
 
          if (server->server_type == SILC_BACKUP_ROUTER) {
            server->server_type = SILC_ROUTER;
@@ -2751,22 +3142,61 @@ void silc_server_free_sock_user_data(SilcServer server,
       }
 
       if (!backup_router) {
-       /* Free all client entries that this server owns as they will
-          become invalid now as well. */
-       if (user_data->id)
-         silc_server_remove_clients_by_server(server, user_data, TRUE);
+       /* Remove all servers that are originated from this server, and
+          remove the clients of those servers too. */
+       silc_server_remove_servers_by_server(server, user_data, TRUE);
+
+       /* Remove the clients that this server owns as they will become
+          invalid now too. */
+       silc_server_remove_clients_by_server(server, user_data,
+                                            user_data, TRUE);
+
+       /* Remove channels owned by this server */
        if (server->server_type == SILC_SERVER)
          silc_server_remove_channels_by_server(server, user_data);
       } else {
+       /* Enable local server connections that may be disabled */
+       silc_server_local_servers_toggle_enabled(server, TRUE);
+
        /* Update the client entries of this server to the new backup
-          router. This also removes the clients that *really* was owned
-          by the primary router and went down with the router.  */
-       silc_server_update_clients_by_server(server, user_data, backup_router,
-                                            TRUE, TRUE);
+          router.  If we are the backup router we also resolve the real
+          servers for the clients.  After updating is over this also
+          removes the clients that this server explicitly owns. */
+       silc_server_update_clients_by_server(server, user_data,
+                                            backup_router, TRUE);
+
+       /* If we are router and just lost our primary router (now standlaone)
+          we remove everything that was behind it, since we don't know
+          any better. */
+       if (server->server_type == SILC_ROUTER && server->standalone)
+         /* Remove all servers that are originated from this server, and
+            remove the clients of those servers too. */
+         silc_server_remove_servers_by_server(server, user_data, TRUE);
+
+       /* Finally remove the clients that are explicitly owned by this
+          server.  They go down with the server. */
+       silc_server_remove_clients_by_server(server, user_data,
+                                            user_data, TRUE);
+
+       /* Update our server cache to use the new backup router too. */
        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,
                                                backup_router);
+
+       /* Send notify about primary router going down to local operators */
+       if (server->backup_router)
+         SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                                SILC_NOTIFY_TYPE_NONE,
+                                ("%s switched to backup router %s "
+                                 "(we are primary router now)",
+                                 server->server_name, server->server_name));
+       else if (server->router)
+         SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                                SILC_NOTIFY_TYPE_NONE,
+                                ("%s switched to backup router %s",
+                                 server->server_name,
+                                 server->router->server_name));
       }
 
       /* Free the server entry */
@@ -2775,15 +3205,17 @@ void silc_server_free_sock_user_data(SilcServer server,
       silc_idlist_del_data(user_data);
       if (!silc_idlist_del_server(server->local_list, user_data))
        silc_idlist_del_server(server->global_list, user_data);
-      if (sock->type == SILC_SOCKET_TYPE_SERVER)
+      if (sock->type == SILC_SOCKET_TYPE_SERVER) {
        server->stat.my_servers--;
-      else
+      } else {
        server->stat.my_routers--;
+       server->stat.routers--;
+      }
       server->stat.servers--;
       if (server->server_type == SILC_ROUTER)
        server->stat.cell_servers--;
 
-      if (backup_router) {
+      if (backup_router && backup_router != server->id_entry) {
        /* Announce all of our stuff that was created about 5 minutes ago.
           The backup router knows all the other stuff already. */
        if (server->server_type == SILC_ROUTER)
@@ -2802,6 +3234,8 @@ void silc_server_free_sock_user_data(SilcServer server,
     {
       SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data;
 
+      SILC_LOG_DEBUG(("Freeing unknown connection data"));
+
       silc_idlist_del_data(user_data);
       silc_free(user_data);
       break;
@@ -2810,6 +3244,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 
   /* If any protocol is active cancel its execution */
   if (sock->protocol) {
+    SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
     silc_protocol_cancel(sock->protocol, server->schedule);
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
     silc_protocol_execute_final(sock->protocol, server->schedule);
@@ -2833,17 +3268,22 @@ void silc_server_remove_from_channels(SilcServer server,
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
-  SilcBuffer clidp;
-
-  SILC_LOG_DEBUG(("Start"));
+  SilcBuffer clidp = NULL;
 
-  if (!client || !client->id)
+  if (!client)
     return;
 
-  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-  if (!clidp)
+  SILC_LOG_DEBUG(("Removing client from joined channels"));
+
+  if (notify && !client->id)
     notify = FALSE;
 
+  if (notify) {
+    clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    if (!clidp)
+      notify = FALSE;
+  }
+
   /* Remove the client from all channels. The client is removed from
      the channels' user list. */
   silc_hash_table_list(client->channels, &htl);
@@ -2852,7 +3292,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* Remove channel if this is last client leaving the channel, unless
        the channel is permanent. */
-    if (server->server_type == SILC_ROUTER &&
+    if (server->server_type != SILC_SERVER &&
        silc_hash_table_count(channel->user_list) < 2) {
       silc_server_channel_delete(server, channel);
       continue;
@@ -2864,17 +3304,24 @@ 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_SERVER && channel->global_users &&
        chl->client->router && !silc_server_channel_has_global(channel))
       channel->global_users = FALSE;
 
     silc_free(chl);
-    server->stat.my_chanclients--;
+
+    /* Update statistics */
+    if (SILC_IS_LOCAL(client))
+      server->stat.my_chanclients--;
+    if (server->server_type == SILC_ROUTER) {
+      server->stat.cell_chanclients--;
+      server->stat.chanclients--;
+    }
 
     /* If there is not at least one local user on the channel then we don't
        need the channel entry anymore, we can remove it safely, unless the
        channel is permanent channel */
-    if (server->server_type != SILC_ROUTER &&
+    if (server->server_type == SILC_SERVER &&
        !silc_server_channel_has_local(channel)) {
       /* Notify about leaving client if this channel has global users. */
       if (notify && channel->global_users)
@@ -2899,6 +3346,10 @@ void silc_server_remove_from_channels(SilcServer server,
                                         signoff_message, signoff_message ?
                                         strlen(signoff_message) : 0);
 
+    /* Don't create keys if we are shutting down */
+    if (server->server_shutdown)
+      continue;
+
     /* Re-generate channel key if needed */
     if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
       if (!silc_server_create_channel_key(server, channel, 0))
@@ -2913,7 +3364,8 @@ void silc_server_remove_from_channels(SilcServer server,
   }
 
   silc_hash_table_list_reset(&htl);
-  silc_buffer_free(clidp);
+  if (clidp)
+    silc_buffer_free(clidp);
 }
 
 /* Removes client from one channel. This is used for example when client
@@ -2942,7 +3394,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
 
   /* Remove channel if this is last client leaving the channel, unless
      the channel is permanent. */
-  if (server->server_type == SILC_ROUTER &&
+  if (server->server_type != SILC_SERVER &&
       silc_hash_table_count(channel->user_list) < 2) {
     silc_server_channel_delete(server, channel);
     return FALSE;
@@ -2954,12 +3406,19 @@ bool silc_server_remove_from_one_channel(SilcServer server,
 
   /* 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 &&
+  if (server->server_type == SILC_SERVER && channel->global_users &&
       chl->client->router && !silc_server_channel_has_global(channel))
     channel->global_users = FALSE;
 
   silc_free(chl);
-  server->stat.my_chanclients--;
+
+  /* Update statistics */
+  if (SILC_IS_LOCAL(client))
+    server->stat.my_chanclients--;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.cell_chanclients--;
+    server->stat.chanclients--;
+  }
 
   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   if (!clidp)
@@ -2968,7 +3427,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
   /* If there is not at least one local user on the channel then we don't
      need the channel entry anymore, we can remove it safely, unless the
      channel is permanent channel */
-  if (server->server_type != SILC_ROUTER &&
+  if (server->server_type == SILC_SERVER &&
       !silc_server_channel_has_local(channel)) {
     /* Notify about leaving client if this channel has global users. */
     if (notify && channel->global_users)
@@ -3049,7 +3508,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   SilcCipher key;
   SilcHmac newhmac;
 
-  SILC_LOG_DEBUG(("Creating new channel"));
+  SILC_LOG_DEBUG(("Creating new channel %s", channel_name));
 
   if (!cipher)
     cipher = SILC_DEFAULT_CIPHER;
@@ -3101,8 +3560,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,
+  if (broadcast)
+    silc_server_send_new_channel(server, SILC_PRIMARY_ROUTE(server), TRUE,
                                 channel_name, entry->id,
                                 silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
@@ -3124,9 +3583,11 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   }
 
   server->stat.my_channels++;
-
-  if (server->server_type == SILC_ROUTER)
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.channels++;
+    server->stat.cell_channels++;
     entry->users_resolved = TRUE;
+  }
 
   return entry;
 }
@@ -3145,7 +3606,7 @@ silc_server_create_new_channel_with_id(SilcServer server,
   SilcCipher key;
   SilcHmac newhmac;
 
-  SILC_LOG_DEBUG(("Creating new channel"));
+  SILC_LOG_DEBUG(("Creating new channel %s", channel_name));
 
   if (!cipher)
     cipher = SILC_DEFAULT_CIPHER;
@@ -3184,8 +3645,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,
+  if (broadcast)
+    silc_server_send_new_channel(server, SILC_PRIMARY_ROUTE(server), TRUE,
                                 channel_name, entry->id,
                                 silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
@@ -3207,9 +3668,11 @@ silc_server_create_new_channel_with_id(SilcServer server,
   }
 
   server->stat.my_channels++;
-
-  if (server->server_type == SILC_ROUTER)
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.channels++;
+    server->stat.cell_channels++;
     entry->users_resolved = TRUE;
+  }
 
   return entry;
 }
@@ -3223,6 +3686,10 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
 
   rekey->task = NULL;
 
+  /* Return now if we are shutting down */
+  if (server->server_shutdown)
+    return;
+
   if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len))
     return;
 
@@ -3241,13 +3708,13 @@ bool silc_server_create_channel_key(SilcServer server,
   unsigned char channel_key[32], hash[32];
   SilcUInt32 len;
 
-  SILC_LOG_DEBUG(("Generating channel key"));
-
   if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
     SILC_LOG_DEBUG(("Channel has private keys, will not generate new key"));
     return TRUE;
   }
 
+  SILC_LOG_DEBUG(("Generating channel %s key", channel->channel_name));
+
   if (!channel->channel_key)
     if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
       channel->channel_key = NULL;
@@ -3321,8 +3788,6 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SilcUInt32 tmp_len;
   char *cipher;
 
-  SILC_LOG_DEBUG(("Start"));
-
   /* Decode channel key payload */
   payload = silc_channel_key_payload_parse(key_payload->data,
                                           key_payload->len);
@@ -3354,6 +3819,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     }
   }
 
+  SILC_LOG_DEBUG(("Saving new channel %s key", channel->channel_name));
+
   tmp = silc_channel_key_get_key(payload, &tmp_len);
   if (!tmp) {
     channel = NULL;
@@ -3433,7 +3900,8 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
 {
   SilcServerHBContext hb = (SilcServerHBContext)hb_context;
 
-  SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip));
+  SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname, 
+                sock->port, sock->ip));
 
   /* Send the heartbeat */
   silc_server_send_heartbeat(hb->server, sock);
@@ -3566,6 +4034,12 @@ static void silc_server_announce_get_clients(SilcServer server,
            break;
          continue;
        }
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) &&
+           !client->connection && !client->router && !SILC_IS_LOCAL(client)) {
+         if (!silc_idcache_list_next(list, &id_cache))
+           break;
+         continue;
+       }
 
        idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -3578,9 +4052,10 @@ static void silc_server_announce_get_clients(SilcServer server,
        silc_buffer_pull(*clients, idp->len);
 
        SILC_PUT32_MSB(client->mode, mode);
-       tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
-                                                2, idp->data, idp->len,
-                                                mode, 4);
+       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 :
@@ -3716,6 +4191,8 @@ void silc_server_announce_get_channel_users(SilcServer server,
   silc_buffer_pull(*channel_modes, len);
   silc_buffer_free(tmp);
   silc_free(fkey);
+  fkey = NULL;
+  fkey_len = 0;
 
   /* Now find all users on the channel */
   silc_hash_table_list(channel->user_list, &htl);
@@ -3761,6 +4238,8 @@ void silc_server_announce_get_channel_users(SilcServer server,
     silc_buffer_pull(*channel_users_modes, len);
     silc_buffer_free(tmp);
     silc_free(fkey);
+    fkey = NULL;
+    fkey_len = 0;
     silc_buffer_free(clidp);
   }
   silc_hash_table_list_reset(&htl);
@@ -3829,36 +4308,42 @@ void silc_server_announce_get_channels(SilcServer server,
          silc_buffer_pull(*channels, len);
        }
 
-       /* Channel user modes */
-       *channel_users_modes = silc_realloc(*channel_users_modes,
-                                           sizeof(**channel_users_modes) *
-                                           (i + 1));
-       (*channel_users_modes)[i] = NULL;
-       *channel_modes = silc_realloc(*channel_modes,
-                                     sizeof(**channel_modes) * (i + 1));
-       (*channel_modes)[i] = NULL;
-       *channel_ids = silc_realloc(*channel_ids,
-                                   sizeof(**channel_ids) * (i + 1));
-       (*channel_ids)[i] = NULL;
-       silc_server_announce_get_channel_users(server, channel,
-                                              &(*channel_modes)[i], 
-                                              channel_users,
-                                              &(*channel_users_modes)[i]);
-       (*channel_ids)[i] = channel->id;
-
-       /* Channel's topic */
-       *channel_topics = silc_realloc(*channel_topics,
-                                      sizeof(**channel_topics) * (i + 1));
-       (*channel_topics)[i] = NULL;
-       silc_server_announce_get_channel_topic(server, channel,
-                                              &(*channel_topics)[i]);
-       i++;
+       if (creation_time && channel->updated < creation_time)
+         announce = FALSE;
+       else
+         announce = TRUE;
+
+       if (announce) {
+         /* Channel user modes */
+         *channel_users_modes = silc_realloc(*channel_users_modes,
+                                             sizeof(**channel_users_modes) *
+                                             (i + 1));
+         (*channel_users_modes)[i] = NULL;
+         *channel_modes = silc_realloc(*channel_modes,
+                                       sizeof(**channel_modes) * (i + 1));
+         (*channel_modes)[i] = NULL;
+         *channel_ids = silc_realloc(*channel_ids,
+                                     sizeof(**channel_ids) * (i + 1));
+         (*channel_ids)[i] = NULL;
+         silc_server_announce_get_channel_users(server, channel,
+                                                &(*channel_modes)[i], 
+                                                channel_users,
+                                                &(*channel_users_modes)[i]);
+         (*channel_ids)[i] = channel->id;
+
+         /* Channel's topic */
+         *channel_topics = silc_realloc(*channel_topics,
+                                        sizeof(**channel_topics) * (i + 1));
+         (*channel_topics)[i] = NULL;
+         silc_server_announce_get_channel_topic(server, channel,
+                                                &(*channel_topics)[i]);
+         (*channel_users_modes_c)++;
+         i++;
+       }
 
        if (!silc_idcache_list_next(list, &id_cache))
          break;
       }
-
-      *channel_users_modes_c += i;
     }
 
     silc_idcache_list_free(list);
@@ -3916,6 +4401,20 @@ void silc_server_announce_channels(SilcServer server,
     silc_buffer_free(channels);
   }
 
+  if (channel_users) {
+    silc_buffer_push(channel_users, channel_users->data - channel_users->head);
+    SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
+                    channel_users->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, remote,
+                           SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                           channel_users->data, channel_users->len,
+                           FALSE);
+
+    silc_buffer_free(channel_users);
+  }
+
   if (channel_modes) {
     int i;
 
@@ -3938,20 +4437,6 @@ void silc_server_announce_channels(SilcServer server,
     silc_free(channel_modes);
   }
 
-  if (channel_users) {
-    silc_buffer_push(channel_users, channel_users->data - channel_users->head);
-    SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
-                    channel_users->len);
-
-    /* Send the packet */
-    silc_server_packet_send(server, remote,
-                           SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                           channel_users->data, channel_users->len,
-                           FALSE);
-
-    silc_buffer_free(channel_users);
-  }
-
   if (channel_users_modes) {
     int i;
 
@@ -4091,9 +4576,9 @@ void silc_server_save_users_on_channel(SilcServer server,
   SilcClientEntry client;
   SilcIDCacheEntry cache;
   SilcChannelClientEntry chl;
-  bool global;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Saving %d users on %s channel", user_count,
+                 channel->channel_name));
 
   for (i = 0; i < user_count; i++) {
     /* Client ID */
@@ -4113,21 +4598,19 @@ void silc_server_save_users_on_channel(SilcServer server,
       continue;
     }
 
-    global = FALSE;
+    cache = NULL;
 
     /* 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) {
+    if (!client)
       client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, server->server_type,
                                             &cache);
-      global = TRUE;
-    }
     if (!client) {
       /* If router did not find such Client ID in its lists then this must
         be bogus client or some router in the net is buggy. */
-      if (server->server_type == SILC_ROUTER) {
+      if (server->server_type != SILC_SERVER) {
        silc_free(client_id);
        continue;
       }
@@ -4145,15 +4628,18 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
-    } else {
-      /* Found, if it is from global list we'll assure that we won't
-        expire it now that the entry is on channel. */
-      if (global)
-       cache->expire = 0;
     }
 
+    if (cache)
+      cache->expire = 0;
     silc_free(client_id);
 
+    if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+      SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
+                     "%s", channel->channel_name));
+      continue;
+    }
+
     if (!silc_server_client_on_channel(client, channel, &chl)) {
       /* Client was not on the channel, add it. */
       chl = silc_calloc(1, sizeof(*chl));
@@ -4191,7 +4677,8 @@ void silc_server_save_user_channels(SilcServer server,
   char *name;
   int i = 0;
 
-  if (!channels ||!channels_user_modes)
+  if (!channels || !channels_user_modes ||
+      !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
     goto out;
   
   ch = silc_channel_payload_parse_list(channels->data, channels->len);
@@ -4340,7 +4827,7 @@ silc_server_get_client_route(SilcServer server,
     silc_free(id);
     if (idata)
       *idata = (SilcIDListData)server->router;
-    return server->router->connection;
+    return SILC_PRIMARY_ROUTE(server);
   }
 
   /* We are router and we will perform route lookup for the destination
@@ -4476,7 +4963,7 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
                                            server->cmd_ident, 1,
                                            4, idp->data, idp->len);
     silc_server_packet_send(server, client ? client->router->connection :
-                           server->router->connection,
+                           SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(idp);
@@ -4502,8 +4989,6 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   SilcProtocol protocol;
   SilcServerRekeyInternalContext *proto_ctx;
 
-  SILC_LOG_DEBUG(("Start"));
-
   /* Allocate internal protocol context. This is sent as context
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
@@ -4521,6 +5006,8 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   /* Run the protocol */
   silc_protocol_execute(protocol, server->schedule, 0, 0);
 
+  SILC_LOG_DEBUG(("Rekey protocol completed"));
+
   /* Re-register re-key timeout */
   silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_rekey_callback,
@@ -4585,7 +5072,7 @@ SILC_TASK_CALLBACK(silc_server_get_stats)
     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_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0, packet->data,
                            packet->len, FALSE);
     silc_buffer_free(packet);