Merged from silc_1_0_branch.
[silc.git] / apps / silcd / server.c
index 10c72d22b511a8148d188dd76fe7aecce0b385b6..c3359196fe887f7dfc30da1aeed9c6a8b751f15c 100644 (file)
@@ -30,7 +30,6 @@
 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);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_final);
 SILC_TASK_CALLBACK(silc_server_accept_new_connection);
@@ -42,8 +41,6 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final);
 SILC_TASK_CALLBACK(silc_server_free_client_data_timeout);
 SILC_TASK_CALLBACK(silc_server_timeout_remote);
 SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
-SILC_TASK_CALLBACK(silc_server_failure_callback);
-SILC_TASK_CALLBACK(silc_server_rekey_callback);
 SILC_TASK_CALLBACK(silc_server_get_stats);
 
 /* Allocates a new SILC server object. This has to be done before the server
@@ -86,9 +83,10 @@ void silc_server_free(SilcServer server)
 #ifdef SILC_SIM
   {
     SilcSim sim;
-    
+    silc_dlist_start(server->sim);
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
+      silc_sim_close(sim);
       silc_sim_free(sim);
     }
     silc_dlist_uninit(server->sim);
@@ -201,7 +199,7 @@ static bool silc_server_listen(SilcServer server, const char *server_ip,
 {
   *sock = silc_net_create_server(port, server_ip);
   if (*sock < 0) {
-    SILC_LOG_ERROR(("Could not create server listener: %s on %hu",
+    SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu",
                        server_ip, port));
     return FALSE;
   }
@@ -252,10 +250,10 @@ bool silc_server_init_secondary(SilcServer server)
 
     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);
+                          silc_server_accept_new_connection,
+                          (void *)server, 0, 0,
+                          SILC_TASK_FD,
+                          SILC_TASK_PRI_NORMAL);
   }
 
   return TRUE;
@@ -285,7 +283,7 @@ bool silc_server_init(SilcServer server)
   server->starttime = time(NULL);
 
   /* Take config object for us */
-  silc_server_config_ref(&server->config_ref, server->config, 
+  silc_server_config_ref(&server->config_ref, server->config,
                         server->config);
 
   /* Steal public and private key from the config object */
@@ -320,7 +318,8 @@ bool silc_server_init(SilcServer server)
   silc_pkcs_private_key_set(server->pkcs, server->private_key);
 
   /* Initialize the scheduler */
-  server->schedule = silc_schedule_init(server->config->param.connections_max);
+  server->schedule = silc_schedule_init(server->config->param.connections_max,
+                                       server);
   if (!server->schedule)
     goto err;
 
@@ -342,7 +341,7 @@ bool silc_server_init(SilcServer server)
   server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
   /* Init watcher list */
-  server->watcher_list = 
+  server->watcher_list =
     silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
                          silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
                          NULL, NULL, TRUE);
@@ -474,27 +473,23 @@ bool silc_server_init(SilcServer server)
   /* Clients local list */
   server->purge_i = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
-  purge->schedule = server->schedule;
   purge->timeout = 600;
-  silc_schedule_task_add(purge->schedule, 0,
-                        silc_idlist_purge,
+  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
                         (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
   server->purge_g = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
-  purge->schedule = server->schedule;
   purge->timeout = 300;
-  silc_schedule_task_add(purge->schedule, 0,
-                        silc_idlist_purge,
+  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
                         (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* If we are normal server we'll retrieve network statisticial information
      once in a while from the router. */
-  if (server->server_type == SILC_SERVER)
-    silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats,
+  if (server->server_type != SILC_ROUTER)
+    silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
                           server, 10, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
@@ -618,14 +613,15 @@ bool silc_server_rehash(SilcServer server)
 
       /* 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 &&
+       if (silc_string_compare(newptr->host, ptr->host) && 
+           newptr->port == ptr->port &&
            newptr->initiator == ptr->initiator) {
          found = TRUE;
          break;
        }
       }
 
-      if (!found) {
+      if (!found && ptr->host) {
        /* Remove this connection */
        SilcSocketConnection sock;
        sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
@@ -649,13 +645,13 @@ bool silc_server_rehash(SilcServer server)
 
       /* Check whether new config has this one too */
       for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
-       if (!strcmp(newptr->host, ptr->host)) {
+       if (silc_string_compare(newptr->host, ptr->host)) {
          found = TRUE;
          break;
        }
       }
 
-      if (!found) {
+      if (!found && ptr->host) {
        /* Remove this connection */
        SilcSocketConnection sock;
        sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
@@ -669,6 +665,36 @@ bool silc_server_rehash(SilcServer server)
     }
   }
 
+  if (server->config->clients) {
+    SilcServerConfigClient *ptr;
+    SilcServerConfigClient *newptr;
+    bool found;
+
+    for (ptr = server->config->clients; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
+       if (silc_string_compare(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found && ptr->host) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_CLIENT,
+                                              ptr->host, 0);
+       if (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,
@@ -860,8 +886,8 @@ void silc_server_start_key_exchange(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 {
+  SilcServer server = app_context;
   SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServer server = sconn->server;
   SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
   SilcServerConfigConnParams *param =
                (conn->param ? conn->param : &server->config->param);
@@ -916,8 +942,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 
 SILC_TASK_CALLBACK(silc_server_connect_router)
 {
+  SilcServer server = app_context;
   SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServer server = sconn->server;
   SilcServerConfigRouter *rconn;
   int sock;
 
@@ -960,8 +986,12 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
                             silc_server_connect_to_router_retry,
                             context, 0, 1, SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
-    else
+    else {
       silc_server_config_unref(&sconn->conn);
+      silc_free(sconn->remote_host);
+      silc_free(sconn->backup_replace_ip);
+      silc_free(sconn);
+    }
     return;
   }
 
@@ -974,7 +1004,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
    server to do authentication and key exchange with our router - called
    from schedule. */
 
-SILC_TASK_CALLBACK(silc_server_connect_to_router)
+SILC_TASK_CALLBACK_GLOBAL(silc_server_connect_to_router)
 {
   SilcServer server = (SilcServer)context;
   SilcServerConnection sconn;
@@ -1030,7 +1060,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
 
       /* Allocate connection object for hold connection specific stuff. */
       sconn = silc_calloc(1, sizeof(*sconn));
-      sconn->server = server;
       sconn->remote_host = strdup(ptr->host);
       sconn->remote_port = ptr->port;
       sconn->backup = ptr->backup_router;
@@ -1078,8 +1107,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    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);
 
@@ -1123,8 +1150,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    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);
 
@@ -1199,8 +1224,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     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);
     return;
@@ -1248,7 +1271,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SilcSocketConnection sock = ctx->sock;
   SilcServerEntry id_entry = NULL;
   SilcBuffer packet;
-  SilcServerHBContext hb_context;
   unsigned char *id_string;
   SilcUInt32 id_len;
   SilcIDListData idata;
@@ -1350,17 +1372,13 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   if (conn && conn->param)
     param = conn->param;
 
-  /* Perform keepalive. The `hb_context' will be freed automatically
-     when finally calling the silc_socket_free function. */
-  hb_context = silc_calloc(1, sizeof(*hb_context));
-  hb_context->server = server;
-  silc_socket_set_heartbeat(sock, param->keepalive_secs, hb_context,
+  /* Perform keepalive. */
+  silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
   /* Register re-key timeout */
   idata->rekey->timeout = param->key_exchange_rekey;
-  idata->rekey->context = (void *)server;
   silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_rekey_callback,
                         (void *)sock, idata->rekey->timeout, 0,
@@ -1388,7 +1406,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       /* 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);
+       silc_server_backup_add(server, server->id_entry, sock->ip,
+                              sconn->remote_port, TRUE);
     }
   } else {
     /* Add this server to be our backup router */
@@ -1446,8 +1465,6 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   SilcServerConfigDeny *deny;
   int port;
 
-  context = (void *)server;
-
   /* Check whether we could resolve both IP and FQDN. */
   if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
                    server->config->require_reverse_lookup)) {
@@ -1468,6 +1485,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
      However, this doesn't set the scheduler for outgoing traffic, it
      will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
      later when outgoing data is available. */
+  context = (void *)server;
   SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
 
   SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
@@ -1647,8 +1665,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     silc_server_config_unref(&ctx->sconfig);
     silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
-    silc_schedule_task_del_by_callback(server->schedule,
-                                      silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
                                  NULL);
@@ -1680,8 +1696,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     silc_server_config_unref(&ctx->sconfig);
     silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
-    silc_schedule_task_del_by_callback(server->schedule,
-                                      silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
     server->stat.auth_failures++;
@@ -1750,10 +1764,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     (SilcServerConnAuthInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
-  SilcServerHBContext hb_context;
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
-  SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
+  SilcServerConfigConnParams *param = &server->config->param;
 
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
@@ -1770,8 +1783,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     silc_server_config_unref(&ctx->sconfig);
     silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
-    silc_schedule_task_del_by_callback(server->schedule,
-                                      silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
     server->stat.auth_failures++;
@@ -1850,11 +1861,21 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
       /* Get connection parameters */
       if (conn->param) {
-       if (conn->param->keepalive_secs)
-         hearbeat_timeout = conn->param->keepalive_secs;
+       param = conn->param;
+
+       if (!param->keepalive_secs)
+         param->keepalive_secs = server->config->param.keepalive_secs;
+
+       if (!param->qos && server->config->param.qos) {
+         param->qos = server->config->param.qos;
+         param->qos_rate_limit = server->config->param.qos_rate_limit;
+         param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+         param->qos_limit_sec = server->config->param.qos_limit_sec;
+         param->qos_limit_usec = server->config->param.qos_limit_usec;
+       }
 
        /* Check if to be anonymous connection */
-       if (conn->param->anonymous)
+       if (param->anonymous)
          client->mode |= SILC_UMODE_ANONYMOUS;
       }
 
@@ -1903,8 +1924,18 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
        if (rconn) {
          if (rconn->param) {
-           if (rconn->param->keepalive_secs)
-             hearbeat_timeout = rconn->param->keepalive_secs;
+           param = rconn->param;
+
+           if (!param->keepalive_secs)
+             param->keepalive_secs = server->config->param.keepalive_secs;
+
+           if (!param->qos && server->config->param.qos) {
+             param->qos = server->config->param.qos;
+             param->qos_rate_limit = server->config->param.qos_rate_limit;
+             param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+             param->qos_limit_sec = server->config->param.qos_limit_sec;
+             param->qos_limit_usec = server->config->param.qos_limit_usec;
+           }
          }
 
          initiator = rconn->initiator;
@@ -1927,8 +1958,18 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
        }
        if (sconn) {
          if (sconn->param) {
-           if (sconn->param->keepalive_secs)
-             hearbeat_timeout = sconn->param->keepalive_secs;
+           param = sconn->param;
+
+           if (!param->keepalive_secs)
+             param->keepalive_secs = server->config->param.keepalive_secs;
+
+           if (!param->qos && server->config->param.qos) {
+             param->qos = server->config->param.qos;
+             param->qos_rate_limit = server->config->param.qos_rate_limit;
+             param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+             param->qos_limit_sec = server->config->param.qos_limit_sec;
+             param->qos_limit_usec = server->config->param.qos_limit_usec;
+           }
          }
 
          backup_router = sconn->backup_router;
@@ -2011,6 +2052,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
          ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
        new_server->server_type = SILC_BACKUP_ROUTER;
 
+       SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
+                              ("Backup router %s is now online",
+                               sock->hostname));
+
        /* Remove the backup waiting with timeout */
        silc_schedule_task_add(server->schedule, 0,
                               silc_server_backup_router_wait,
@@ -2061,17 +2106,19 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   /* Connection has been fully established now. Everything is ok. */
   SILC_LOG_DEBUG(("New connection authenticated"));
 
-  /* Perform keepalive. The `hb_context' will be freed automatically
-     when finally calling the silc_socket_free function. */
-  hb_context = silc_calloc(1, sizeof(*hb_context));
-  hb_context->server = server;
-  silc_socket_set_heartbeat(sock, hearbeat_timeout, hb_context,
-                           silc_server_perform_heartbeat,
-                           server->schedule);
+  /* Perform keepalive. */
+  if (param->keepalive_secs)
+    silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
+                             silc_server_perform_heartbeat,
+                             server->schedule);
+
+  /* Perform Quality of Service */
+  if (param->qos)
+    silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
+                       param->qos_limit_sec, param->qos_limit_usec,
+                       server->schedule);
 
  out:
-  silc_schedule_task_del_by_callback(server->schedule,
-                                    silc_server_failure_callback);
   silc_protocol_free(protocol);
   if (ctx->packet)
     silc_packet_context_free(ctx->packet);
@@ -2096,6 +2143,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
   SilcUInt32 sequence = 0;
+  bool local_is_router;
   int ret;
 
   if (!sock) {
@@ -2122,6 +2170,14 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     if (ret == -2)
       return;
 
+    /* The packet has been sent and now it is time to set the connection
+       back to only for input. When there is again some outgoing data
+       available for this connection it will be set for output as well.
+       This call clears the output setting and sets it only for input. */
+    SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
+    SILC_UNSET_OUTBUF_PENDING(sock);
+    silc_buffer_clear(sock->outbuf);
+
     if (ret == -1) {
       SILC_LOG_ERROR(("Error sending packet to connection "
                      "%s:%d [%s]", sock->hostname, sock->port,
@@ -2129,17 +2185,12 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
                       sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router")));
-      return;
-    }
-
-    /* The packet has been sent and now it is time to set the connection
-       back to only for input. When there is again some outgoing data
-       available for this connection it will be set for output as well.
-       This call clears the output setting and sets it only for input. */
-    SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
-    SILC_UNSET_OUTBUF_PENDING(sock);
 
-    silc_buffer_clear(sock->outbuf);
+      SILC_SET_DISCONNECTING(sock);
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_close_connection(server, sock);
+    }
     return;
   }
 
@@ -2149,13 +2200,19 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   ret = silc_packet_receive(sock);
   if (ret < 0) {
 
-    if (ret == -1)
+    if (ret == -1) {
       SILC_LOG_ERROR(("Error receiving packet from connection "
                      "%s:%d [%s] %s", sock->hostname, sock->port,
                      (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                       sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router"), strerror(errno)));
+
+      SILC_SET_DISCONNECTING(sock);
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_close_connection(server, sock);
+    }
     return;
   }
 
@@ -2182,7 +2239,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
       else
        silc_server_free_sock_user_data(server, sock, NULL);
     } else if (server->router_conn && server->router_conn->sock == sock &&
-            !server->router && server->standalone)
+              !server->router && server->standalone)
       silc_schedule_task_add(server->schedule, 0,
                             silc_server_connect_to_router,
                             server, 1, 0,
@@ -2208,20 +2265,29 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     sequence = idata->psn_receive;
   }
 
-  /* Process the packet. This will call the parser that will then
+  /* Then, process the packet. This will call the parser that will then
      decrypt and parse the packet. */
-  ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
-                                   TRUE : FALSE, cipher, hmac, sequence,
+
+  local_is_router = (server->server_type == SILC_ROUTER);
+
+  /* If socket connection is our primary, we are backup and we are doing
+     backup resuming, we won't process the packet as being a router 
+     (affects channel message decryption). */
+  if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) &&
+      SILC_PRIMARY_ROUTE(server) == sock)
+    local_is_router = FALSE;
+
+  ret = silc_packet_receive_process(sock, local_is_router,
+                                   cipher, hmac, sequence,
                                    silc_server_packet_parse, server);
 
-  /* If this socket connection is not authenticated yet and the packet
-     processing failed we will drop the connection since it can be
-     a malicious flooder. */
-  if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE &&
-      (!sock->protocol || sock->protocol->protocol->type ==
-       SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) {
-    SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock));
-    SILC_SET_DISCONNECTING(sock);
+  /* If processing failed the connection is closed. */
+  if (!ret) {
+    /* On packet processing errors we may close our primary router 
+       connection but won't become primary router if we are the backup
+       since this is local error condition. */
+    if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
+      server->backup_noswitch = TRUE;
 
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock, NULL);
@@ -2328,6 +2394,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
   SilcServer server = (SilcServer)context;
   SilcSocketConnection sock = parser_context->sock;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
+  bool ret;
 
   if (idata)
     idata->psn_receive = parser_context->packet->sequence + 1;
@@ -2341,21 +2408,36 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
       (sock->protocol && sock->protocol->protocol &&
        (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
        sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY))) {
-    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+    silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
                                  parser_context);
 
     /* Reprocess data since we'll return FALSE here.  This is because
        the idata->receive_key might have become valid in the last packet
        and we want to call this processor with valid cipher. */
     if (idata)
-      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
-                                 TRUE : FALSE, idata->receive_key,
+      ret = silc_packet_receive_process(
+                                 sock, server->server_type == SILC_ROUTER,
+                                 idata->receive_key,
                                  idata->hmac_receive, idata->psn_receive,
                                  silc_server_packet_parse, server);
     else
-      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
-                                 TRUE : FALSE, NULL, NULL, 0,
+      ret = silc_packet_receive_process(
+                                 sock, server->server_type == SILC_ROUTER,
+                                 NULL, NULL, 0,
                                  silc_server_packet_parse, server);
+
+    if (!ret) {
+      /* On packet processing errors we may close our primary router 
+         connection but won't become primary router if we are the backup
+         since this is local error condition. */
+      if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
+       server->backup_noswitch = TRUE;
+
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_close_connection(server, sock);
+    }
+
     return FALSE;
   }
 
@@ -2372,7 +2454,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     /* Packets from servers are parsed immediately */
-    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+    silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
                                  parser_context);
     break;
   default:
@@ -2447,15 +2529,8 @@ void silc_server_packet_parse_type(SilcServer server,
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     if (sock->protocol) {
-      SilcServerFailureContext f;
-      f = silc_calloc(1, sizeof(*f));
-      f->server = server;
-      f->sock = sock;
-
-      /* We will wait 5 seconds to process this failure packet */
-      silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_failure_callback, (void *)f, 5, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     }
     break;
 
@@ -2831,7 +2906,6 @@ void silc_server_create_connection(SilcServer server,
 
   /* Allocate connection object for hold connection specific stuff. */
   sconn = silc_calloc(1, sizeof(*sconn));
-  sconn->server = server;
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
   sconn->no_reconnect = TRUE;
@@ -2855,7 +2929,9 @@ void silc_server_close_connection(SilcServer server,
   char tmp[128];
 
   if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
-    silc_schedule_task_add(server->schedule, 0,
+    silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+    silc_schedule_task_del_by_fd(server->schedule, sock->sock);
+    silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_close_connection_final,
                           (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_NORMAL);
@@ -2871,9 +2947,6 @@ void silc_server_close_connection(SilcServer server,
                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                    "Router"), tmp[0] ? tmp : ""));
 
-  /* We won't listen for this connection anymore */
-  silc_schedule_unset_listen_fd(server->schedule, sock->sock);
-
   /* Unregister all tasks */
   silc_schedule_task_del_by_fd(server->schedule, sock->sock);
 
@@ -2887,7 +2960,8 @@ void silc_server_close_connection(SilcServer server,
   if (!sock->user_data) {
     /* If any protocol is active cancel its execution. It will call
        the final callback which will finalize the disconnection. */
-    if (sock->protocol) {
+    if (sock->protocol && sock->protocol->protocol &&
+       sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
       SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
       silc_protocol_cancel(sock->protocol, server->schedule);
       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
@@ -2897,7 +2971,10 @@ void silc_server_close_connection(SilcServer server,
     }
   }
 
-  silc_schedule_task_add(server->schedule, 0,
+  /* We won't listen for this connection anymore */
+  silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+
+  silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_close_connection_final,
                         (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
@@ -2916,7 +2993,7 @@ void silc_server_disconnect_remote(SilcServer server,
   char *cp;
   int len;
 
-  if (!sock)
+  if (!sock || SILC_IS_DISCONNECTED(sock))
     return;
 
   memset(buf, 0, sizeof(buf));
@@ -2957,20 +3034,15 @@ void silc_server_disconnect_remote(SilcServer server,
   silc_server_close_connection(server, sock);
 }
 
-typedef struct {
-  SilcServer server;
-  SilcClientEntry client;
-} *FreeClientInternal;
-
 SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
 {
-  FreeClientInternal i = (FreeClientInternal)context;
+  SilcServer server = app_context;
+  SilcClientEntry client = context;
 
-  assert(!silc_hash_table_count(i->client->channels));
+  assert(!silc_hash_table_count(client->channels));
 
-  silc_idlist_del_data(i->client);
-  silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
-  silc_free(i);
+  silc_idlist_del_data(client);
+  silc_idcache_purge_by_context(server->local_list->clients, client);
 }
 
 /* Frees client data and notifies about client's signoff. */
@@ -2983,16 +3055,6 @@ void silc_server_free_client_data(SilcServer server,
 {
   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);
@@ -3013,10 +3075,10 @@ void silc_server_free_client_data(SilcServer server,
   /* Remove client from all channels */
   if (notify)
     silc_server_remove_from_channels(server, NULL, client,
-                                    TRUE, (char *)signoff, TRUE);
+                                    TRUE, (char *)signoff, TRUE, FALSE);
   else
     silc_server_remove_from_channels(server, NULL, client,
-                                    FALSE, NULL, FALSE);
+                                    FALSE, NULL, FALSE, FALSE);
 
   /* Remove this client from watcher list if it is */
   silc_server_del_from_watcher_list(server, client);
@@ -3034,12 +3096,9 @@ void silc_server_free_client_data(SilcServer server,
      into history (for WHOWAS command) for 5 minutes, unless we're
      shutting down server. */
   if (!server->server_shutdown) {
-    FreeClientInternal i = silc_calloc(1, sizeof(*i));
-    i->server = server;
-    i->client = client;
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_free_client_data_timeout,
-                          (void *)i, 300, 0,
+                          client, 300, 0,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
@@ -3085,7 +3144,7 @@ void silc_server_free_sock_user_data(SilcServer server,
          sock->type != SILC_SOCKET_TYPE_ROUTER)
        backup_router = NULL;
 
-      if (server->server_shutdown)
+      if (server->server_shutdown || server->backup_noswitch)
        backup_router = NULL;
 
       /* If this was our primary router connection then we're lost to
@@ -3102,6 +3161,7 @@ void silc_server_free_sock_user_data(SilcServer server,
          server->id_entry->router = NULL;
          server->router = NULL;
          server->standalone = TRUE;
+         server->backup_primary = FALSE;
          backup_router = NULL;
        } else {
          if (server->id_entry != backup_router) {
@@ -3138,23 +3198,41 @@ void silc_server_free_sock_user_data(SilcServer server,
       } else if (backup_router) {
        SILC_LOG_INFO(("Enabling the use of backup router %s",
                       backup_router->server_name));
-       SILC_LOG_DEBUG(("Enabling the use of backup router %s",
-                       backup_router->server_name));
 
        /* Mark this connection as replaced */
        silc_server_backup_replaced_add(server, user_data->id,
                                        backup_router);
+      } else if (server->server_type == SILC_SERVER &&
+                sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       /* Reconnect to the router (backup) */
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_connect_to_router,
+                              server, 1, 0,
+                              SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
       }
 
+      SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
+                            ("Server %s signoff", user_data->server_name));
+
       if (!backup_router) {
        /* 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);
 
+#if 0
        /* 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);
+          invalid now too.  For backup router the server is actually
+          coming from the primary router, so mark that as the owner
+          of this entry. */
+       if (server->server_type == SILC_BACKUP_ROUTER &&
+           sock->type == SILC_SOCKET_TYPE_SERVER)
+         silc_server_remove_clients_by_server(server, server->router,
+                                              user_data, TRUE);
+       else
+#endif
+         silc_server_remove_clients_by_server(server, user_data,
+                                              user_data, TRUE);
 
        /* Remove channels owned by this server */
        if (server->server_type == SILC_SERVER)
@@ -3203,6 +3281,7 @@ void silc_server_free_sock_user_data(SilcServer server,
                                  server->server_name,
                                  server->router->server_name));
       }
+      server->backup_noswitch = FALSE;
 
       /* Free the server entry */
       silc_server_backup_del(server, user_data);
@@ -3248,7 +3327,8 @@ void silc_server_free_sock_user_data(SilcServer server,
   }
 
   /* If any protocol is active cancel its execution */
-  if (sock->protocol) {
+  if (sock->protocol && sock->protocol->protocol &&
+      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
     SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
     silc_protocol_cancel(sock->protocol, server->schedule);
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
@@ -3268,7 +3348,8 @@ void silc_server_remove_from_channels(SilcServer server,
                                      SilcClientEntry client,
                                      bool notify,
                                      const char *signoff_message,
-                                     bool keygen)
+                                     bool keygen,
+                                     bool killed)
 {
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
@@ -3304,7 +3385,7 @@ void silc_server_remove_from_channels(SilcServer server,
     }
 
     silc_hash_table_del(client->channels, channel);
-    silc_hash_table_del(channel->user_list, chl->client);
+    silc_hash_table_del(channel->user_list, client);
     channel->user_count--;
 
     /* If there is no global users on the channel anymore mark the channel
@@ -3313,6 +3394,7 @@ void silc_server_remove_from_channels(SilcServer server,
        chl->client->router && !silc_server_channel_has_global(channel))
       channel->global_users = FALSE;
 
+    memset(chl, 'A', sizeof(*chl));
     silc_free(chl);
 
     /* Update statistics */
@@ -3351,6 +3433,21 @@ void silc_server_remove_from_channels(SilcServer server,
                                         signoff_message, signoff_message ?
                                         strlen(signoff_message) : 0);
 
+    if (killed && clidp) {
+      /* Remove the client from channel's invite list */
+      if (channel->invite_list &&
+         silc_hash_table_count(channel->invite_list)) {
+       SilcBuffer ab;
+       SilcArgumentPayload iargs;
+       ab = silc_argument_payload_encode_one(NULL, clidp->data,
+                                             clidp->len, 3);
+       iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+       silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
+       silc_buffer_free(ab);
+       silc_argument_payload_free(iargs);
+      }
+    }
+
     /* Don't create keys if we are shutting down */
     if (server->server_shutdown)
       continue;
@@ -3405,8 +3502,8 @@ bool silc_server_remove_from_one_channel(SilcServer server,
     return FALSE;
   }
 
-  silc_hash_table_del(client->channels, chl->channel);
-  silc_hash_table_del(channel->user_list, chl->client);
+  silc_hash_table_del(client->channels, channel);
+  silc_hash_table_del(channel->user_list, client);
   channel->user_count--;
 
   /* If there is no global users on the channel anymore mark the channel
@@ -3415,6 +3512,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
       chl->client->router && !silc_server_channel_has_global(channel))
     channel->global_users = FALSE;
 
+  memset(chl, 'O', sizeof(*chl));
   silc_free(chl);
 
   /* Update statistics */
@@ -3476,7 +3574,8 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
 
   /* If we have protocol active we must assure that we call the protocol's
      final callback so that all the memory is freed. */
-  if (sock->protocol) {
+  if (sock->protocol && sock->protocol->protocol &&
+      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
     protocol = sock->protocol->protocol->type;
     silc_protocol_cancel(sock->protocol, server->schedule);
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
@@ -3485,15 +3584,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
     return;
   }
 
-  if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock, NULL);
-
   silc_server_disconnect_remote(server, sock, 
                                protocol == 
                                SILC_PROTOCOL_SERVER_CONNECTION_AUTH ?
                                SILC_STATUS_ERR_AUTH_FAILED :
                                SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
                                "Connection timeout");
+
+  if (sock->user_data)
+    silc_server_free_sock_user_data(server, sock, NULL);
 }
 
 /* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
@@ -3686,8 +3785,8 @@ silc_server_create_new_channel_with_id(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
 {
+  SilcServer server = app_context;
   SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
-  SilcServer server = (SilcServer)rekey->context;
 
   rekey->task = NULL;
 
@@ -3761,7 +3860,6 @@ bool silc_server_create_channel_key(SilcServer server,
   if (server->server_type == SILC_ROUTER) {
     if (!channel->rekey)
       channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
-    channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
     channel->rekey->key_len = key_len;
     if (channel->rekey->task)
@@ -3817,8 +3915,9 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
       if (!channel) {
-       SILC_LOG_ERROR(("Received key for non-existent channel %s",
-                       silc_id_render(id, SILC_ID_CHANNEL)));
+       if (server->server_type == SILC_ROUTER)
+         SILC_LOG_ERROR(("Received key for non-existent channel %s",
+                         silc_id_render(id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -3874,7 +3973,6 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   if (server->server_type == SILC_ROUTER) {
     if (!channel->rekey)
       channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
-    channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
     if (channel->rekey->task)
       silc_schedule_task_del(server->schedule, channel->rekey->task);
@@ -3903,13 +4001,13 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 void silc_server_perform_heartbeat(SilcSocketConnection sock,
                                   void *hb_context)
 {
-  SilcServerHBContext hb = (SilcServerHBContext)hb_context;
+  SilcServer server = hb_context;
 
   SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname, 
                 sock->port, sock->ip));
 
   /* Send the heartbeat */
-  silc_server_send_heartbeat(hb->server, sock);
+  silc_server_send_heartbeat(server, sock);
 }
 
 /* Returns assembled of all servers in the given ID list. The packet's
@@ -4158,10 +4256,9 @@ void silc_server_announce_get_channel_users(SilcServer server,
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   SilcBuffer chidp, clidp, csidp;
-  SilcBuffer tmp;
+  SilcBuffer tmp, fkey = NULL;
   int len;
-  unsigned char mode[4], *fkey = NULL;
-  SilcUInt32 fkey_len = 0;
+  unsigned char mode[4];
   char *hmac;
 
   SILC_LOG_DEBUG(("Start"));
@@ -4173,7 +4270,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
   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);
+    fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
   tmp = 
     silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
                                       6, csidp->data, csidp->len,
@@ -4183,7 +4280,8 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                       channel->passphrase,
                                       channel->passphrase ?
                                       strlen(channel->passphrase) : 0,
-                                      fkey, fkey_len);
+                                      fkey ? fkey->data : NULL,
+                                      fkey ? fkey->len : 0);
   len = tmp->len;
   *channel_modes =
     silc_buffer_realloc(*channel_modes,
@@ -4195,9 +4293,8 @@ void silc_server_announce_get_channel_users(SilcServer server,
   silc_buffer_put(*channel_modes, tmp->data, tmp->len);
   silc_buffer_pull(*channel_modes, len);
   silc_buffer_free(tmp);
-  silc_free(fkey);
+  silc_buffer_free(fkey);
   fkey = NULL;
-  fkey_len = 0;
 
   /* Now find all users on the channel */
   silc_hash_table_list(channel->user_list, &htl);
@@ -4224,12 +4321,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);
+      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
     tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
                                             4, csidp->data, csidp->len,
                                             mode, sizeof(mode),
                                             clidp->data, clidp->len,
-                                            fkey, fkey_len);
+                                            fkey ? fkey->data : NULL,
+                                            fkey ? fkey->len : 0);
     len = tmp->len;
     *channel_users_modes =
       silc_buffer_realloc(*channel_users_modes,
@@ -4242,9 +4340,8 @@ 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);
+    silc_buffer_free(fkey);
     fkey = NULL;
-    fkey_len = 0;
     silc_buffer_free(clidp);
   }
   silc_hash_table_list_reset(&htl);
@@ -4343,6 +4440,9 @@ void silc_server_announce_get_channels(SilcServer server,
          silc_server_announce_get_channel_topic(server, channel,
                                                 &(*channel_topics)[i]);
          (*channel_users_modes_c)++;
+
+         silc_free(cid);
+
          i++;
        }
 
@@ -4490,25 +4590,6 @@ void silc_server_announce_channels(SilcServer server,
   silc_free(channel_ids);
 }
 
-/* Failure timeout callback. If this is called then we will immediately
-   process the received failure. We always process the failure with timeout
-   since we do not want to blindly trust to received failure packets.
-   This won't be called (the timeout is cancelled) if the failure was
-   bogus (it is bogus if remote does not close the connection after sending
-   the failure). */
-
-SILC_TASK_CALLBACK(silc_server_failure_callback)
-{
-  SilcServerFailureContext f = (SilcServerFailureContext)context;
-
-  if (f->sock->protocol) {
-    f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
-    silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0);
-  }
-
-  silc_free(f);
-}
-
 /* Assembles user list and users mode list from the `channel'. */
 
 bool silc_server_get_users_on_channel(SilcServer server,
@@ -4928,69 +5009,14 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   return buffer;
 }
 
-/* Finds client entry by Client ID and if it is not found then resolves
-   it using WHOIS command. */
-
-SilcClientEntry silc_server_get_client_resolve(SilcServer server,
-                                              SilcClientID *client_id,
-                                              bool always_resolve,
-                                              bool *resolved)
-{
-  SilcClientEntry client;
-
-  if (resolved)
-    *resolved = FALSE;
-
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                        TRUE, NULL);
-  if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, NULL);
-    if (!client && server->server_type == SILC_ROUTER)
-      return NULL;
-  }
-
-  if (!client && server->standalone)
-    return NULL;
-
-  if (!client || !client->nickname || !client->username ||
-      always_resolve) {
-    SilcBuffer buffer, idp;
-
-    if (client) {
-      client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
-      client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
-      client->resolve_cmd_ident = ++server->cmd_ident;
-    }
-
-    idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
-                                           server->cmd_ident, 1,
-                                           4, idp->data, idp->len);
-    silc_server_packet_send(server, client ? client->router->connection :
-                           SILC_PRIMARY_ROUTE(server),
-                           SILC_PACKET_COMMAND, 0,
-                           buffer->data, buffer->len, FALSE);
-    silc_buffer_free(idp);
-    silc_buffer_free(buffer);
-
-    if (resolved)
-      *resolved = TRUE;
-
-    return NULL;
-  }
-
-  return client;
-}
-
 /* A timeout callback for the re-key. We will be the initiator of the
    re-key protocol. */
 
-SILC_TASK_CALLBACK(silc_server_rekey_callback)
+SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
 {
+  SilcServer server = app_context;
   SilcSocketConnection sock = (SilcSocketConnection)context;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
-  SilcServer server = (SilcServer)idata->rekey->context;
   SilcProtocol protocol;
   SilcServerRekeyInternalContext *proto_ctx;
 
@@ -5036,7 +5062,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
-    SILC_LOG_ERROR(("Error occurred during rekey protocol"));
+    SILC_LOG_ERROR(("Error occurred during rekey protocol with
+                  %s (%s)", sock->hostname, sock->ip));
     silc_protocol_cancel(protocol, server->schedule);
     silc_protocol_free(protocol);
     sock->protocol = NULL;