Fixed notify sending to backup routers, and fixed channel
[silc.git] / apps / silcd / server.c
index 6aaf3e553dd4a1495c45adf27b601641657a3d6a..cc772361c46533c3036059ae928ac873495bdbfd 100644 (file)
@@ -28,6 +28,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,62 +78,130 @@ int silc_server_alloc(SilcServer *new_server)
 
 void silc_server_free(SilcServer server)
 {
-  if (server) {
+  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_free(server->sockets);
-    silc_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);
+
+  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, int *sock)
+static bool silc_server_listen(SilcServer server, const char *server_ip,
+                              SilcUInt16 port, int *sock)
 {
-
-  *sock = silc_net_create_server(server->config->server_info->port,
-                               server->config->server_info->server_ip);
+  *sock = silc_net_create_server(port, 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));
+                       server_ip, port));
     return FALSE;
   }
   return TRUE;
 }
 
+/* Adds a secondary listener. */
+
+bool silc_server_init_secondary(SilcServer server)
+{
+  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;
+
+    /* Set socket to non-blocking mode */
+    silc_net_set_socket_nonblock(sock_list[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_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. */
+    if (!silc_net_check_local_by_sock(sock_list[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);
+
+    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:
+  do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
+  return FALSE;
+}
+
 /* 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
@@ -218,7 +287,12 @@ bool silc_server_init(SilcServer server)
     goto err;
 
   /* Create a listening server */
-  if (!silc_server_listen(server, &sock))
+  if (!silc_server_listen(server,
+               server->config->server_info->primary == NULL ? NULL :
+                       server->config->server_info->primary->server_ip,
+               server->config->server_info->primary == NULL ? 0 :
+                       server->config->server_info->primary->port,
+               &sock))
     goto err;
 
   /* Set socket to non-blocking mode */
@@ -238,6 +312,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. */
@@ -264,7 +339,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;
 
@@ -308,6 +382,10 @@ bool silc_server_init(SilcServer server)
                         (void *)server, 0, 0,
                         SILC_TASK_FD,
                         SILC_TASK_PRI_NORMAL);
+
+  if (silc_server_init_secondary(server) == FALSE)
+    goto err;
+  
   server->listenning = TRUE;
 
   /* If server connections has been configured then we must be router as
@@ -331,7 +409,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;
@@ -341,7 +419,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;
@@ -357,6 +435,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 */
@@ -368,6 +449,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(("Closing connection %s:%d [%s]: connection 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.
@@ -436,6 +542,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,
@@ -496,9 +666,40 @@ void silc_server_stop(SilcServer server)
   SILC_LOG_DEBUG(("Stopping server"));
 
   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])) {
+       SilcIDListData idata = server->sockets[i]->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");
+      } 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();
@@ -523,7 +724,7 @@ void silc_server_start_key_exchange(SilcServer server,
 
   /* Cancel any possible retry timeouts */
   silc_schedule_task_del_by_callback(server->schedule,
-                                    silc_server_connect_router);
+                                    silc_server_connect_to_router_retry);
 
   /* Set socket options */
   silc_net_set_socket_nonblock(sock);
@@ -622,6 +823,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);
 
@@ -659,9 +863,10 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   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_host);
+  sock = silc_net_create_connection(
+                (!server->config->server_info->primary ? NULL :
+                 server->config->server_info->primary->server_ip),
+                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));
@@ -690,20 +895,15 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
   SilcServerConnection sconn;
   SilcServerConfigRouter *ptr;
 
-  SILC_LOG_DEBUG(("Connecting to router(s)"));
-
-  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;
   }
@@ -722,6 +922,10 @@ 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)
+      server->wait_backup = TRUE;
+
     if (ptr->initiator) {
       /* Check whether we are connected to this host already */
       if (silc_server_num_sockets_by_remote(server, 
@@ -784,14 +988,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;
   }
 
@@ -815,14 +1033,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);
@@ -924,7 +1156,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;
@@ -941,6 +1173,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;
   }
 
@@ -992,7 +1234,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);
@@ -1009,7 +1252,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;
@@ -1039,14 +1283,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));
+
+      /* 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);
     }
   } else {
     /* Add this server to be our backup router */
@@ -1056,12 +1307,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)
     (*sconn->callback)(server, id_entry, sconn->callback_context);
 
- out:
   /* Free the temporary connection data context */
   if (sconn) {
     silc_server_config_unref(&sconn->conn);
@@ -1072,6 +1323,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;
@@ -1094,15 +1346,16 @@ static void
 silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
                                         void *context)
 {
-  SilcServer server = (SilcServer)context;
-  SilcServerKEInternalContext *proto_ctx;
+  SilcServerKEInternalContext *proto_ctx =
+    (SilcServerKEInternalContext *)context;
+  SilcServer server = (SilcServer)proto_ctx->server;
   SilcServerConfigClient *cconfig = NULL;
   SilcServerConfigServer *sconfig = NULL;
   SilcServerConfigRouter *rconfig = NULL;
   SilcServerConfigDeny *deny;
   int port;
 
-  SILC_LOG_DEBUG(("Start"));
+  context = (void *)server;
 
   /* Check whether we could resolve both IP and FQDN. */
   if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
@@ -1114,6 +1367,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  "Unknown host or IP");
+    silc_free(proto_ctx);
     return;
   }
 
@@ -1128,7 +1382,16 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
                 sock->ip));
 
-  port = server->sockets[server->sock]->port; /* Listenning port */
+  /* 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. */
   deny = silc_server_config_find_denied(server, sock->ip);
@@ -1138,10 +1401,11 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     /* The connection is denied */
     SILC_LOG_INFO(("Connection %s (%s) is denied",
                   sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BANNED_FROM_SERVER,
                                  deny->reason);
     server->stat.conn_failures++;
+    silc_free(proto_ctx);
     return;
   }
 
@@ -1154,7 +1418,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     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,
-                                                       sock->ip, port)))
+                                                       sock->ip, sock->port)))
       rconfig = silc_server_config_find_router_conn(server, sock->hostname,
                                                    sock->port);
   }
@@ -1162,17 +1426,16 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
                   sock->ip));
     silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_BANNED_FROM_SERVER);
+                                 SILC_STATUS_ERR_BANNED_FROM_SERVER, NULL);
     server->stat.conn_failures++;
+    silc_free(proto_ctx);
     return;
   }
 
   /* The connection is allowed */
 
-  /* Allocate internal context for key exchange protocol. This is
+  /* Set internal context for key exchange protocol. This is
      sent as context for the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = context;
   proto_ctx->sock = sock;
   proto_ctx->rng = server->rng;
   proto_ctx->responder = TRUE;
@@ -1194,6 +1457,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);
@@ -1204,7 +1468,8 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   proto_ctx->timeout_task =
     silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_timeout_remote,
-                          context, server->config->key_exchange_timeout, 0,
+                          (void *)server,
+                          server->config->key_exchange_timeout, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1216,13 +1481,14 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
 {
   SilcServer server = (SilcServer)context;
   SilcSocketConnection newsocket;
+  SilcServerKEInternalContext *proto_ctx;
   int sock;
 
   SILC_LOG_DEBUG(("Accepting new connection"));
 
   server->stat.conn_attempts++;
 
-  sock = silc_net_accept_connection(server->sock);
+  sock = silc_net_accept_connection(fd);
   if (sock < 0) {
     SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
     server->stat.conn_failures++;
@@ -1249,9 +1515,12 @@ 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. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->server = server;
+  proto_ctx->context = (void *)fd;
   silc_socket_host_lookup(newsocket, TRUE,
-                         silc_server_accept_new_connection_lookup, context,
-                         server->schedule);
+                         silc_server_accept_new_connection_lookup,
+                         (void *)proto_ctx, server->schedule);
 }
 
 /* Second part of accepting new connection. Key exchange protocol has been
@@ -1274,6 +1543,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);
@@ -1306,6 +1576,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);
@@ -1351,6 +1622,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);
@@ -1366,6 +1638,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. */
@@ -1382,11 +1664,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)
@@ -1422,6 +1703,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));
@@ -1439,6 +1750,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++;
@@ -1466,12 +1778,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;
        }
@@ -1496,6 +1826,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;
        }
@@ -1509,6 +1840,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 ?
@@ -1543,32 +1904,32 @@ 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;
       }
 
+      /* 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 (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
+      if (!backup_router &&
+         server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
        if (silc_server_config_is_primary_route(server) && !initiator)
          break;
 
@@ -1636,17 +1997,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++;
 
@@ -1736,8 +2099,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) {
@@ -1778,7 +2139,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)
@@ -1793,17 +2154,20 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     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);
@@ -1813,7 +2177,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)) {
@@ -1835,19 +2199,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:
@@ -1928,7 +2290,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) {
@@ -1937,8 +2300,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)
@@ -1947,13 +2308,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;
 
@@ -1963,7 +2330,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)
@@ -1976,7 +2342,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) {
@@ -1993,7 +2358,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;
@@ -2004,7 +2368,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
@@ -2020,7 +2383,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);
@@ -2034,7 +2396,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);
@@ -2048,7 +2409,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);
@@ -2060,7 +2420,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);
@@ -2074,7 +2433,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);
@@ -2094,7 +2452,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;
 
@@ -2114,7 +2471,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;
 
@@ -2158,7 +2514,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;
 
@@ -2208,7 +2563,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);
@@ -2220,7 +2574,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;
 
@@ -2247,7 +2600,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
@@ -2260,7 +2612,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);
@@ -2272,7 +2623,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);
@@ -2283,7 +2633,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
@@ -2294,7 +2643,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;
@@ -2303,7 +2651,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);
@@ -2314,7 +2661,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);
@@ -2324,7 +2670,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;
 
@@ -2349,7 +2694,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);
@@ -2357,7 +2701,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);
@@ -2366,7 +2709,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);
@@ -2376,7 +2718,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. */
@@ -2401,7 +2742,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 */
@@ -2409,8 +2750,13 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock)
 {
-  if (!server->sockets[sock->sock])
+  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,
                   sock->port,
@@ -2436,6 +2782,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);
@@ -2528,18 +2875,34 @@ void silc_server_free_client_data(SilcServer server,
 {
   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. */
   silc_server_packet_queue_purge(server, sock);
 
-  if (!client->id)
-    return;
+  if (client->id) {
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    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);
+    /* Send SIGNOFF notify to routers. */
+    if (notify)
+      silc_server_send_notify_signoff(server, SILC_PRIMARY_ROUTE(server),
+                                     SILC_BROADCAST(server), client->id,
+                                     signoff);
+  }
 
   /* Remove client from all channels */
   if (notify)
@@ -2549,11 +2912,6 @@ void silc_server_free_client_data(SilcServer server,
     silc_server_remove_from_channels(server, NULL, client,
                                     FALSE, NULL, FALSE);
 
-  /* Check if anyone is watching this nickname */
-  if (server->server_type == SILC_ROUTER)
-    silc_server_check_watcher_list(server, client, NULL,
-                                  SILC_NOTIFY_TYPE_SIGNOFF);
-
   /* Remove this client from watcher list if it is */
   silc_server_del_from_watcher_list(server, client);
 
@@ -2588,8 +2946,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:
     {
@@ -2604,6 +2960,8 @@ 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);
 
@@ -2623,14 +2981,23 @@ 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));
-         server->id_entry->router = backup_router;
-         server->router = backup_router;
-         server->router_connect = time(0);
-         server->backup_primary = TRUE;
+         if (server->id_entry != backup_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;
+         } 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);
+         }
+
          if (server->server_type == SILC_BACKUP_ROUTER) {
            server->server_type = SILC_ROUTER;
 
@@ -2657,22 +3024,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
+         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 */
@@ -2681,12 +3087,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);
-      server->stat.my_servers--;
+      if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+       server->stat.my_servers--;
+      } 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)
@@ -2705,6 +3116,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;
@@ -2713,6 +3126,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);
@@ -2729,21 +3143,28 @@ void silc_server_free_sock_user_data(SilcServer server,
 void silc_server_remove_from_channels(SilcServer server,
                                      SilcSocketConnection sock,
                                      SilcClientEntry client,
-                                     int notify,
-                                     char *signoff_message,
-                                     int keygen)
+                                     bool notify,
+                                     const char *signoff_message,
+                                     bool keygen)
 {
   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);
+  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. */
@@ -2751,37 +3172,38 @@ void silc_server_remove_from_channels(SilcServer server,
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     channel = chl->channel;
 
-    /* Remove channel from client's channel list */
-    silc_hash_table_del(client->channels, channel);
-
-    /* Remove channel if there is no users anymore */
-    if (server->server_type == SILC_ROUTER &&
+    /* Remove channel if this is last client leaving the channel, unless
+       the channel is permanent. */
+    if (server->server_type != SILC_SERVER &&
        silc_hash_table_count(channel->user_list) < 2) {
-      if (channel->rekey)
-       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-      if (silc_idlist_del_channel(server->local_list, channel))
-       server->stat.my_channels--;
-      else
-        silc_idlist_del_channel(server->global_list, channel);
+      silc_server_channel_delete(server, channel);
       continue;
     }
 
-    /* Remove client from channel's client list */
+    silc_hash_table_del(client->channels, channel);
     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 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. */
-    if (server->server_type != SILC_ROUTER &&
+       need the channel entry anymore, we can remove it safely, unless the
+       channel is permanent channel */
+    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)
@@ -2792,37 +3214,12 @@ void silc_server_remove_from_channels(SilcServer server,
                                           signoff_message, signoff_message ?
                                           strlen(signoff_message) : 0);
 
-      if (channel->rekey)
-       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
-      if (channel->founder_key) {
-       /* 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);
-         silc_hash_table_del(channel->user_list, chl2->client);
-         channel->user_count--;
-         silc_free(chl2);
-       }
-       silc_hash_table_list_reset(&htl2);
-       continue;
-      }
-
-      /* Remove the channel entry */
-      if (silc_idlist_del_channel(server->local_list, channel))
-       server->stat.my_channels--;
-      else
-        silc_idlist_del_channel(server->global_list, channel);
+      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+      silc_server_channel_delete(server, channel);
       continue;
     }
 
-    /* Send notify to channel about client leaving SILC and thus
-       the entire channel. */
+    /* Send notify to channel about client leaving SILC and channel too */
     if (notify)
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                         SILC_NOTIFY_TYPE_SIGNOFF,
@@ -2831,10 +3228,14 @@ 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)) {
-      /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
-       goto out;
+       continue;
 
       /* Send the channel key to the channel. The key of course is not sent
         to the client who was removed from the channel. */
@@ -2844,9 +3245,9 @@ void silc_server_remove_from_channels(SilcServer server,
     }
   }
 
- out:
   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
@@ -2855,59 +3256,60 @@ 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,
-                                       SilcSocketConnection sock,
-                                       SilcChannelEntry channel,
-                                       SilcClientEntry client,
-                                       int notify)
+bool silc_server_remove_from_one_channel(SilcServer server,
+                                        SilcSocketConnection sock,
+                                        SilcChannelEntry channel,
+                                        SilcClientEntry client,
+                                        bool notify)
 {
   SilcChannelClientEntry chl;
   SilcBuffer clidp;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Removing %s from channel %s",
+                 silc_id_render(client->id, SILC_ID_CLIENT), 
+                 channel->channel_name));
 
   /* Get the entry to the channel, if this client is not on the channel
      then return Ok. */
   if (!silc_hash_table_find(client->channels, channel, NULL, (void *)&chl))
     return TRUE;
 
-  /* Remove the client from the channel. The client is removed from
-     the channel's user list. */
-
-  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
-  /* Remove channel from client's channel list */
-  silc_hash_table_del(client->channels, chl->channel);
-
-  /* Remove channel if there is no users anymore */
-  if (server->server_type == SILC_ROUTER &&
+  /* Remove channel if this is last client leaving the channel, unless
+     the channel is permanent. */
+  if (server->server_type != SILC_SERVER &&
       silc_hash_table_count(channel->user_list) < 2) {
-    if (channel->rekey)
-      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-    if (silc_idlist_del_channel(server->local_list, channel))
-      server->stat.my_channels--;
-    else
-      silc_idlist_del_channel(server->global_list, channel);
-    silc_buffer_free(clidp);
+    silc_server_channel_delete(server, channel);
     return FALSE;
   }
 
-  /* Remove client from channel's client list */
+  silc_hash_table_del(client->channels, chl->channel);
   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 &&
+  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)
+    notify = FALSE;
 
   /* 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. */
-  if (server->server_type != SILC_ROUTER &&
+     need the channel entry anymore, we can remove it safely, unless the
+     channel is permanent channel */
+  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)
@@ -2915,34 +3317,9 @@ int silc_server_remove_from_one_channel(SilcServer server,
                                         SILC_NOTIFY_TYPE_LEAVE, 1,
                                         clidp->data, clidp->len);
 
+    silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+    silc_server_channel_delete(server, channel);
     silc_buffer_free(clidp);
-
-    if (channel->rekey)
-      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
-    if (channel->founder_key) {
-      /* 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);
-       silc_hash_table_del(channel->user_list, chl2->client);
-       channel->user_count--;
-       silc_free(chl2);
-      }
-      silc_hash_table_list_reset(&htl2);
-      return FALSE;
-    }
-
-    /* Remove the channel entry */
-    if (silc_idlist_del_channel(server->local_list, channel))
-      server->stat.my_channels--;
-    else
-      silc_idlist_del_channel(server->global_list, channel);
     return FALSE;
   }
 
@@ -3013,7 +3390,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;
@@ -3065,16 +3442,34 @@ 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);
 
-  server->stat.my_channels++;
+  /* Distribute to backup routers */
+  if (broadcast && server->server_type == SILC_ROUTER) {
+    SilcBuffer packet;
+    unsigned char *cid;
+    SilcUInt32 name_len = strlen(channel_name);
+    SilcUInt32 channel_id_len = silc_id_get_len(entry->id, SILC_ID_CHANNEL);
+    cid = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+
+    packet = silc_channel_payload_encode(channel_name, name_len,
+                                        cid, channel_id_len, entry->mode);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+    silc_free(cid);
+    silc_buffer_free(packet);
+  }
 
-  if (server->server_type == SILC_ROUTER)
+  server->stat.my_channels++;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.channels++;
+    server->stat.cell_channels++;
     entry->users_resolved = TRUE;
+  }
 
   return entry;
 }
@@ -3093,7 +3488,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;
@@ -3132,16 +3527,34 @@ 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);
 
-  server->stat.my_channels++;
+  /* Distribute to backup routers */
+  if (broadcast && server->server_type == SILC_ROUTER) {
+    SilcBuffer packet;
+    unsigned char *cid;
+    SilcUInt32 name_len = strlen(channel_name);
+    SilcUInt32 channel_id_len = silc_id_get_len(entry->id, SILC_ID_CHANNEL);
+    cid = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+
+    packet = silc_channel_payload_encode(channel_name, name_len,
+                                        cid, channel_id_len, entry->mode);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+    silc_free(cid);
+    silc_buffer_free(packet);
+  }
 
-  if (server->server_type == SILC_ROUTER)
+  server->stat.my_channels++;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.channels++;
+    server->stat.cell_channels++;
     entry->users_resolved = TRUE;
+  }
 
   return entry;
 }
@@ -3155,6 +3568,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;
 
@@ -3173,13 +3590,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;
@@ -3253,8 +3670,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);
@@ -3281,11 +3696,14 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
       if (!channel) {
        SILC_LOG_ERROR(("Received key for non-existent channel %s",
                        silc_id_render(id, SILC_ID_CHANNEL)));
+       assert(FALSE);
        goto out;
       }
     }
   }
 
+  SILC_LOG_DEBUG(("Saving new channel %s key", channel->channel_name));
+
   tmp = silc_channel_key_get_key(payload, &tmp_len);
   if (!tmp) {
     channel = NULL;
@@ -3510,9 +3928,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 :
@@ -3603,20 +4022,55 @@ void silc_server_announce_get_channel_topic(SilcServer server,
 
 void silc_server_announce_get_channel_users(SilcServer server,
                                            SilcChannelEntry channel,
+                                           SilcBuffer *channel_modes,
                                            SilcBuffer *channel_users,
                                            SilcBuffer *channel_users_modes)
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
-  SilcBuffer chidp, clidp;
+  SilcBuffer chidp, clidp, csidp;
   SilcBuffer tmp;
   int len;
-  unsigned char mode[4];
+  unsigned char mode[4], *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
+  char *hmac;
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* Now find all users on the channel */
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  csidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+
+  /* CMODE notify */
+  SILC_PUT32_MSB(channel->mode, mode);
+  hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
+  if (channel->founder_key)
+    fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+  tmp = 
+    silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
+                                      6, csidp->data, csidp->len,
+                                      mode, sizeof(mode),
+                                      NULL, 0,
+                                      hmac, hmac ? strlen(hmac) : 0,
+                                      channel->passphrase,
+                                      channel->passphrase ?
+                                      strlen(channel->passphrase) : 0,
+                                      fkey, fkey_len);
+  len = tmp->len;
+  *channel_modes =
+    silc_buffer_realloc(*channel_modes,
+                       (*channel_modes ?
+                        (*channel_modes)->truelen + len : len));
+  silc_buffer_pull_tail(*channel_modes,
+                       ((*channel_modes)->end -
+                        (*channel_modes)->data));
+  silc_buffer_put(*channel_modes, tmp->data, tmp->len);
+  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);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
@@ -3640,10 +4094,13 @@ void silc_server_announce_get_channel_users(SilcServer server,
 
     /* CUMODE notify for mode change on the channel */
     SILC_PUT32_MSB(chl->mode, mode);
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key)
+      fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
     tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
-                                            3, clidp->data, clidp->len,
-                                            mode, 4,
-                                            clidp->data, clidp->len);
+                                            4, csidp->data, csidp->len,
+                                            mode, sizeof(mode),
+                                            clidp->data, clidp->len,
+                                            fkey, fkey_len);
     len = tmp->len;
     *channel_users_modes =
       silc_buffer_realloc(*channel_users_modes,
@@ -3656,11 +4113,14 @@ void silc_server_announce_get_channel_users(SilcServer server,
     silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
     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);
   silc_buffer_free(chidp);
+  silc_buffer_free(csidp);
 }
 
 /* Returns assembled packets for all channels and users on those channels
@@ -3670,6 +4130,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
 void silc_server_announce_get_channels(SilcServer server,
                                       SilcIDList id_list,
                                       SilcBuffer *channels,
+                                      SilcBuffer **channel_modes,
                                       SilcBuffer *channel_users,
                                       SilcBuffer **channel_users_modes,
                                       SilcUInt32 *channel_users_modes_c,
@@ -3723,32 +4184,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_ids = silc_realloc(*channel_ids,
-                                   sizeof(**channel_ids) * (i + 1));
-       (*channel_ids)[i] = NULL;
-       silc_server_announce_get_channel_users(server, channel,
-                                              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);
@@ -3766,7 +4237,7 @@ void silc_server_announce_channels(SilcServer server,
                                   unsigned long creation_time,
                                   SilcSocketConnection remote)
 {
-  SilcBuffer channels = NULL, channel_users = NULL;
+  SilcBuffer channels = NULL, *channel_modes = NULL, channel_users = NULL;
   SilcBuffer *channel_users_modes = NULL;
   SilcBuffer *channel_topics = NULL;
   SilcUInt32 channel_users_modes_c = 0;
@@ -3776,7 +4247,8 @@ void silc_server_announce_channels(SilcServer server,
 
   /* Get channels and channel users in local list */
   silc_server_announce_get_channels(server, server->local_list,
-                                   &channels, &channel_users,
+                                   &channels, &channel_modes,
+                                   &channel_users,
                                    &channel_users_modes,
                                    &channel_users_modes_c,
                                    &channel_topics,
@@ -3785,7 +4257,8 @@ void silc_server_announce_channels(SilcServer server,
   /* Get channels and channel users in global list */
   if (server->server_type != SILC_SERVER)
     silc_server_announce_get_channels(server, server->global_list,
-                                     &channels, &channel_users,
+                                     &channels, &channel_modes,
+                                     &channel_users,
                                      &channel_users_modes,
                                      &channel_users_modes_c,
                                      &channel_topics,
@@ -3818,6 +4291,28 @@ void silc_server_announce_channels(SilcServer server,
     silc_buffer_free(channel_users);
   }
 
+  if (channel_modes) {
+    int i;
+
+    for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_modes[i])
+        continue;
+      silc_buffer_push(channel_modes[i],
+                      channel_modes[i]->data -
+                      channel_modes[i]->head);
+      SILC_LOG_HEXDUMP(("channel modes"), channel_modes[i]->data,
+                      channel_modes[i]->len);
+      silc_server_packet_send_dest(server, remote,
+                                  SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                  channel_ids[i], SILC_ID_CHANNEL,
+                                  channel_modes[i]->data,
+                                  channel_modes[i]->len,
+                                  FALSE);
+      silc_buffer_free(channel_modes[i]);
+    }
+    silc_free(channel_modes);
+  }
+
   if (channel_users_modes) {
     int i;
 
@@ -3887,7 +4382,7 @@ SILC_TASK_CALLBACK(silc_server_failure_callback)
 
 /* Assembles user list and users mode list from the `channel'. */
 
-void silc_server_get_users_on_channel(SilcServer server,
+bool silc_server_get_users_on_channel(SilcServer server,
                                      SilcChannelEntry channel,
                                      SilcBuffer *user_list,
                                      SilcBuffer *mode_list,
@@ -3900,6 +4395,9 @@ void silc_server_get_users_on_channel(SilcServer server,
   SilcBuffer idp;
   SilcUInt32 list_count = 0, len = 0;
 
+  if (!silc_hash_table_count(channel->user_list))
+    return FALSE;
+
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl))
     len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4);
@@ -3934,6 +4432,7 @@ void silc_server_get_users_on_channel(SilcServer server,
   *user_list = client_id_list;
   *mode_list = client_mode_list;
   *user_count = list_count;
+  return TRUE;
 }
 
 /* Saves users and their modes to the `channel'. */
@@ -4202,7 +4701,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
@@ -4336,9 +4835,9 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
                                            server->cmd_ident, 1,
-                                           3, idp->data, idp->len);
+                                           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);
@@ -4364,8 +4863,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));
@@ -4383,6 +4880,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,
@@ -4447,7 +4946,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);