Fixed SERVER_SIGNOFF handling on server to remove the client from
authorPekka Riikonen <priikone@silcnet.org>
Sun, 12 Oct 2003 17:52:50 +0000 (17:52 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 12 Oct 2003 17:52:50 +0000 (17:52 +0000)
correct list.  It caused clients to remain network after
SERVER_SIGNOFF.

Added timeout callback handling to rekey protocol.  Do not
execute rekey to disabled connections.

Backup router fixes (tests continue).

apps/silcd/idlist.c
apps/silcd/packet_receive.c
apps/silcd/protocol.h
apps/silcd/server.c
apps/silcd/server_backup.c
apps/silcd/server_internal.h
apps/silcd/server_util.c

index 7e5e99b9d3643e3f55380f8595ec3400b58ab8d0..2562c0f03d39ec1db2f4c252dd78a0fc9d0c0e38 100644 (file)
@@ -292,8 +292,10 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
 {
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->servers, entry))
+    if (!silc_idcache_del_by_context(id_list->servers, entry)) {
+      SILC_LOG_DEBUG(("Unknown server, did not delete"));
       return FALSE;
+    }
 
     SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
                    entry->server_name : "",
@@ -367,8 +369,10 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
 
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->clients, entry))
+    if (!silc_idcache_del_by_context(id_list->clients, entry)) {
+      SILC_LOG_DEBUG(("Unknown client, did not delete"));
       return FALSE;
+    }
 
     assert(!silc_hash_table_count(entry->channels));
 
@@ -657,8 +661,10 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
 {
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->channels, entry))
+    if (!silc_idcache_del_by_context(id_list->channels, entry)) {
+      SILC_LOG_DEBUG(("Unknown channel, did not delete"));
       return FALSE;
+    }
 
     SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
 
index 1e60853d0c86017522f7bed04cb70e0c6defb384..6d12cefa4491ef1258206118f435f06bd03e502a 100644 (file)
@@ -1322,11 +1322,11 @@ void silc_server_notify(SilcServer server,
            /* Get client entry */
            client = silc_idlist_find_client_by_id(server->global_list,
                                                   client_id, TRUE, &cache);
-           local = TRUE;
+           local = FALSE;
            if (!client) {
              client = silc_idlist_find_client_by_id(server->local_list,
                                                     client_id, TRUE, &cache);
-             local = FALSE;
+             local = TRUE;
              if (!client) {
                silc_free(client_id);
                continue;
@@ -2565,11 +2565,12 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                               server_id, TRUE, NULL);
   if (server_entry) {
     if (SILC_IS_LOCAL(server_entry)) {
-      silc_server_disconnect_remote(server, server_entry->connection,
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_OPERATION_ALLOWED,
                                    "Too many registrations");
-      if (((SilcSocketConnection)server_entry->connection)->user_data)
+      if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      return NULL;
     } else {
       silc_idcache_del_by_context(server->local_list->servers, server_entry);
     }
@@ -2578,12 +2579,12 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                                 server_id, TRUE, NULL);
     if (server_entry) {
       if (SILC_IS_LOCAL(server_entry)) {
-       silc_server_disconnect_remote(server, server_entry->connection,
+       silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_OPERATION_ALLOWED,
                                      "Too many registrations");
-       if (((SilcSocketConnection)server_entry->connection)->user_data)
-         silc_server_free_sock_user_data(server, server_entry->connection,
-                                         NULL);
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       return NULL;
       } else {
        silc_idcache_del_by_context(server->global_list->servers,
                                    server_entry);
@@ -3415,7 +3416,7 @@ void silc_server_rekey(SilcServer server,
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = (void *)server;
-  proto_ctx->sock = sock;
+  proto_ctx->sock = silc_socket_dup(sock);
   proto_ctx->responder = TRUE;
   proto_ctx->pfs = idata->rekey->pfs;
 
index 75e58c7d007a987f2448ab07c7449c10aef97a4d..3c184abce2ae2363f1193d1f1dd38ee316037258 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -98,6 +97,7 @@ typedef struct {
   bool pfs;                        /* TRUE if PFS is to be used */
   SilcSKE ske;                     /* Defined if PFS is used */
   SilcPacketContext *packet;
+  SilcTask timeout_task;
 } SilcServerRekeyInternalContext;
 
 /* Prototypes */
index d9e756d85fada9502925322a4a7bb08d8dbf908c..291b09227aed0f5d7c0f361a28e762dd6fcc423a 100644 (file)
@@ -1441,6 +1441,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       server->router = id_entry;
       server->router->server_type = SILC_ROUTER;
       server->standalone = FALSE;
+      server->backup_primary = FALSE;
 
       /* If we are router then announce our possible servers.  Backup
         router announces also global servers. */
@@ -3316,7 +3317,8 @@ void silc_server_free_sock_user_data(SilcServer server,
       if (server->router == user_data) {
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
-         silc_server_create_connections(server);
+         if (!server->no_reconnect)
+           silc_server_create_connections(server);
          server->id_entry->router = NULL;
          server->router = NULL;
          server->standalone = TRUE;
@@ -3370,7 +3372,8 @@ void silc_server_free_sock_user_data(SilcServer server,
       } else if (server->server_type == SILC_SERVER &&
                 sock->type == SILC_SOCKET_TYPE_ROUTER) {
        /* Reconnect to the router (backup) */
-       silc_server_create_connections(server);
+       if (!server->no_reconnect)
+         silc_server_create_connections(server);
       }
 
       if (user_data->server_name)
@@ -3511,11 +3514,12 @@ void silc_server_remove_from_channels(SilcServer server,
   if (!client)
     return;
 
-  SILC_LOG_DEBUG(("Removing client from joined channels"));
-
   if (notify && !client->id)
     notify = FALSE;
 
+  SILC_LOG_DEBUG(("Removing client %s from joined channels",
+                 notify ? silc_id_render(client->id, SILC_ID_CLIENT) : ""));
+
   if (notify) {
     clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
     if (!clidp)
@@ -5299,6 +5303,42 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   return buffer;
 }
 
+/* Timeout callback for unsuccessful rekey.  The rekey did not go through
+   for some reason. */
+
+SILC_TASK_CALLBACK(silc_server_rekey_timeout)
+{
+  SilcServerRekeyInternalContext *ctx = context;
+  SilcServer server = app_context;
+  SilcSocketConnection sock = ctx->sock;
+
+  SILC_LOG_DEBUG(("Timeout occurred in rekey protocol with %s:%d [%s]",
+                 sock->hostname, sock->port,
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
+
+  SILC_LOG_WARNING(("Timeout occurred in rekey protocol with %s:%d [%s]",
+                   sock->hostname, sock->port,
+                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                    "Router")));
+
+  if (sock->protocol) {
+    silc_protocol_cancel(sock->protocol, server->schedule);
+    silc_protocol_free(sock->protocol);
+    sock->protocol = NULL;
+  }
+  if (ctx->packet)
+    silc_packet_context_free(ctx->packet);
+  if (ctx->ske)
+    silc_ske_free(ctx->ske);
+  silc_socket_free(sock);
+  silc_free(ctx);
+}
+
 /* A timeout callback for the re-key. We will be the initiator of the
    re-key protocol. */
 
@@ -5310,6 +5350,11 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
   SilcProtocol protocol;
   SilcServerRekeyInternalContext *proto_ctx;
 
+  /* Do not execute rekey with disabled connections, as it would not
+     go through anyway. */
+  if (idata->status & SILC_IDLIST_STATUS_DISABLED)
+    return;
+
   /* If rekey protocol is active already wait for it to finish */
   if (sock->protocol && sock->protocol->protocol &&
       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
@@ -5325,13 +5370,18 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
     return;
   }
 
-  SILC_LOG_DEBUG(("Executing rekey protocol"));
+  SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
+                 sock->hostname, sock->port,
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
 
   /* Allocate internal protocol context. This is sent as context
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = (void *)server;
-  proto_ctx->sock = sock;
+  proto_ctx->sock = silc_socket_dup(sock);
   proto_ctx->responder = FALSE;
   proto_ctx->pfs = idata->rekey->pfs;
 
@@ -5341,6 +5391,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
                      &protocol, proto_ctx, silc_server_rekey_final);
   sock->protocol = protocol;
 
+  /* Register timeout callback in case the rekey does not go through. */
+  proto_ctx->timeout_task =
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_rekey_timeout,
+                          proto_ctx,
+                          server->config->key_exchange_timeout, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
   /* Run the protocol */
   silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
@@ -5357,6 +5416,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
   SilcSocketConnection sock = ctx->sock;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
 
+  if (ctx->timeout_task)
+    silc_schedule_task_del(server->schedule, ctx->timeout_task);
+
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
@@ -5369,6 +5431,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
       silc_packet_context_free(ctx->packet);
     if (ctx->ske)
       silc_ske_free(ctx->ske);
+    silc_socket_free(sock);
     silc_free(ctx);
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
@@ -5379,7 +5442,12 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     return;
   }
 
-  SILC_LOG_DEBUG(("Rekey protocol completed"));
+  SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]",
+                 sock->hostname, sock->port,
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
 
   /* Purge the outgoing data queue to assure that all rekey packets really
      go to the network before we quit the protocol. */
@@ -5399,6 +5467,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     silc_packet_context_free(ctx->packet);
   if (ctx->ske)
     silc_ske_free(ctx->ske);
+  silc_socket_free(sock);
   silc_free(ctx);
 }
 
index 7bf72544c6c4d1fdbd5d8dc90b37fdbce57fd982..876eba20217f62d0b8ded91f46b69f3e3a5bba42 100644 (file)
@@ -63,12 +63,14 @@ typedef struct {
 typedef struct {
   SilcServer server;
   SilcSocketConnection sock;
-  bool responder;
   SilcUInt8 type;
   SilcUInt8 session;
   SilcServerBackupProtocolSession *sessions;
   SilcUInt32 sessions_count;
   long start;
+  unsigned int responder        : 1;
+  unsigned int received_failure : 1;
+  unsigned int timeout          : 1;
 } *SilcServerBackupProtocolContext;
 
 
@@ -494,9 +496,11 @@ void silc_server_backup_send_replaced(SilcServer server,
 SILC_TASK_CALLBACK(silc_server_backup_timeout)
 {
   SilcProtocol protocol = context;
+  SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = app_context;
 
   SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
+  ctx->timeout = TRUE;
   silc_protocol_cancel(protocol, server->schedule);
   protocol->state = SILC_PROTOCOL_STATE_ERROR;
   silc_protocol_execute_final(protocol, server->schedule);
@@ -512,6 +516,7 @@ SILC_TASK_CALLBACK(silc_server_backup_responder_start)
 
   /* If other protocol is executing at the same time, start with timeout. */
   if (sock->protocol) {
+    SILC_LOG_DEBUG(("Other protocol is executing, wait for it to finish"));
     silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_backup_responder_start,
                           proto_ctx, 2, 0,
@@ -530,6 +535,22 @@ SILC_TASK_CALLBACK(silc_server_backup_responder_start)
                         SILC_TASK_PRI_NORMAL);
 }
 
+/* Callback to send START_USE to backup to check whether using backup
+   is ok. */
+
+SILC_TASK_CALLBACK(silc_server_backup_check_status)
+{
+  SilcSocketConnection sock = context;
+  SilcServer server = app_context;
+
+  /* Check whether we are still using backup */
+  if (!server->backup_primary)
+    return;
+
+  silc_server_backup_send_start_use(server, sock, FALSE);
+  silc_socket_free(sock);      /* unref */
+}
+
 typedef struct {
   SilcServer server;
   SilcSocketConnection sock;
@@ -832,6 +853,7 @@ SILC_TASK_CALLBACK(silc_server_backup_connected_later)
 
   /* If running other protocol already run this one a bit later. */
   if (sock->protocol) {
+    SILC_LOG_DEBUG(("Other protocol is running, wait for it to finish"));
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_backup_connected_later,
                           proto_ctx, 10, 0,
@@ -1295,14 +1317,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, backup_router, router);
        silc_server_backup_replaced_del(server, backup_router);
-
-       /* Announce all of our information to the router. */
-       if (server->server_type == SILC_ROUTER)
-         silc_server_announce_servers(server, FALSE, ctx->start, sock);
-
-       /* Announce our clients and channels to the router */
-       silc_server_announce_clients(server, ctx->start, sock);
-       silc_server_announce_channels(server, ctx->start, sock);
       }
 
       /* Send notify about primary router going down to local operators */
@@ -1331,6 +1345,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   case SILC_PROTOCOL_STATE_FAILURE:
     /* Protocol has ended, call the final callback */
     SILC_LOG_ERROR(("Error during backup resume: received Failure"));
+    ctx->received_failure = TRUE;
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
     else
@@ -1385,42 +1400,52 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
       sock->protocol = NULL;
 
       if (error) {
-       /* If we are server close all router connections except backup,
-          send confirmation to backup that using it is still ok and continue
-          sending traffic there.  The backup will reply with error if
-          it's not ok. */
+
        if (server->server_type == SILC_SERVER &&
-           server_entry->server_type == SILC_ROUTER) {
-         server->backup_noswitch = TRUE;
-         if (sock->user_data)
-           silc_server_free_sock_user_data(server, sock, NULL);
-         silc_server_disconnect_remote(server, sock, 0, NULL);
-         server->backup_noswitch = FALSE;
-
-         /* Send START_USE just in case using backup wouldn't be ok. */
-         silc_server_backup_send_start_use(server, server->router->connection,
-                                           FALSE);
-
-         silc_server_create_connections(server);
+           server_entry->server_type == SILC_ROUTER)
          continue;
-       }
 
-       /* If error occurred and we are backup router, we close connections. */
+       /* Backup router */
        if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
-         server->backup_noswitch = TRUE;
-         server->server_type = SILC_BACKUP_ROUTER;
          if (ctx->sock == sock) {
            silc_socket_free(sock); /* unref */
            ctx->sock = NULL;
          }
 
-         server->backup_noswitch = TRUE;
-         if (sock->user_data)
-           silc_server_free_sock_user_data(server, sock, NULL);
-         silc_server_disconnect_remote(server, sock, 0, NULL);
-         server->backup_noswitch = FALSE;
+         if (!ctx->received_failure) {
+           /* Protocol error, probably timeout. Just restart the protocol. */
+           SilcServerBackupProtocolContext proto_ctx;
+
+           /* Restart the protocol. */
+           proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+           proto_ctx->server = server;
+           proto_ctx->sock = silc_socket_dup(sock);
+           proto_ctx->responder = FALSE;
+           proto_ctx->type = SILC_SERVER_BACKUP_START;
+           proto_ctx->start = time(0);
+
+           /* Start through scheduler */
+           silc_schedule_task_add(server->schedule, 0,
+                                  silc_server_backup_connected_later,
+                                  proto_ctx, 2, 0,
+                                  SILC_TASK_TIMEOUT,
+                                  SILC_TASK_PRI_NORMAL);
+         } else {
+           /* If failure was received, switch back to normal backup router.
+              For some reason primary wouldn't accept that we were supposed
+              to perfom resuming protocol. */
+           server->server_type = SILC_BACKUP_ROUTER;
+           silc_server_local_servers_toggle_enabled(server, FALSE);
+           silc_server_update_servers_by_server(server, server->id_entry,
+                                                sock->user_data);
+           silc_server_update_clients_by_server(server, NULL,
+                                                sock->user_data, FALSE);
+
+           /* Announce our clients and channels to the router */
+           silc_server_announce_clients(server, ctx->start, sock);
+           silc_server_announce_channels(server, ctx->start, sock);
+         }
 
-         silc_server_create_connections(server);
          continue;
        }
       }
@@ -1429,9 +1454,53 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
     }
   }
 
-  if (!error)
+  if (!error) {
     SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
 
+    if (ctx->type == SILC_SERVER_BACKUP_RESUMED && server->router) {
+      /* Announce all of our information to the router. */
+      if (server->server_type == SILC_ROUTER)
+       silc_server_announce_servers(server, FALSE, ctx->start,
+                                    server->router->connection);
+
+      /* Announce our clients and channels to the router */
+      silc_server_announce_clients(server, ctx->start,
+                                  server->router->connection);
+      silc_server_announce_channels(server, ctx->start,
+                                   server->router->connection);
+    }
+  } else {
+    /* Error */
+
+    if (server->server_type == SILC_SERVER) {
+      /* If we are still using backup router Send confirmation to backup
+        that using it is still ok and continue sending traffic there.
+        The backup will reply with error if it's not ok. */
+      if (server->router && server->backup_primary) {
+       /* Send START_USE just in case using backup wouldn't be ok. */
+       silc_server_backup_send_start_use(server, server->router->connection,
+                                         FALSE);
+
+       /* Check couple of times same START_USE just in case. */
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_check_status,
+                              silc_socket_dup(server->router->connection),
+                              5, 1, SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_check_status,
+                              silc_socket_dup(server->router->connection),
+                              20, 1, SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_check_status,
+                              silc_socket_dup(server->router->connection),
+                              60, 1, SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
   if (ctx->sock && ctx->sock->protocol)
     ctx->sock->protocol = NULL;
   if (ctx->sock)
index bd601f9e1de758c2bbf5913e4af3918993fe4a06..7cf42a8ed8964553455acac8f70a10e81438c231 100644 (file)
@@ -92,6 +92,8 @@ struct SilcServerStruct {
   unsigned int wait_backup    : 1;   /* Set if we are waiting for backup
                                        router to connect to us. */
   unsigned int server_shutdown: 1;   /* Set when shutting down */
+  unsigned int no_reconnect   : 1;   /* If set, server won't reconnect to
+                                       router after disconnection. */
 
   SilcServerEntry router;           /* Pointer to the primary router */
   unsigned long router_connect;             /* Time when router was connected */
index 1bc86f7c769bc8b1a00729e8ac19e4154c67ed29..8405f7e992cae9f6191dc266b463188a93c1bbfd 100644 (file)
@@ -650,7 +650,16 @@ void silc_server_update_servers_by_server(SilcServer server,
             whether this server is in our cell, but not connected to
             us (in which case we must remove it). */
 
-         if (server_entry->router == from) {
+         if (from) {
+           if (server_entry->router == from) {
+             SILC_LOG_DEBUG(("Updating server (local) %s",
+                             server_entry->server_name ?
+                             server_entry->server_name : ""));
+             server_entry->router = to;
+             server_entry->connection = to->connection;
+           }
+         } else {
+           /* Update all */
            SILC_LOG_DEBUG(("Updating server (local) %s",
                            server_entry->server_name ?
                            server_entry->server_name : ""));
@@ -696,7 +705,16 @@ void silc_server_update_servers_by_server(SilcServer server,
             whether this server is in our cell, but not connected to
             us (in which case we must remove it). */
 
-         if (server_entry->router == from) {
+         if (from) {
+           if (server_entry->router == from) {
+             SILC_LOG_DEBUG(("Updating server (global) %s",
+                             server_entry->server_name ?
+                             server_entry->server_name : ""));
+             server_entry->router = to;
+             server_entry->connection = to->connection;
+           }
+         } else {
+           /* Update all */
            SILC_LOG_DEBUG(("Updating server (global) %s",
                            server_entry->server_name ?
                            server_entry->server_name : ""));
@@ -885,8 +903,13 @@ void silc_server_update_channels_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        channel = (SilcChannelEntry)id_cache->context;
-       if (channel->router == from)
+       if (from) {
+         if (channel->router == from)
+           channel->router = to;
+       } else {
+         /* Update all */
          channel->router = to;
+       }
        if (!silc_idcache_list_next(list, &id_cache))
          break;
       }
@@ -1837,7 +1860,7 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list,
       if (type == 1) {
        /* Invite string.  Get the old invite string from hash table
           and append this at the end of the existing one. */
-       if (!silc_hash_table_find(list, (void *)1, NULL, (void **)&tmp2)) {
+       if (!silc_hash_table_find(list, (void *)1, NULL, (void *)&tmp2)) {
          tmp2 = silc_calloc(1, sizeof(*tmp2));
          silc_hash_table_add(list, (void *)1, tmp2);
        }