New silcconfig library and server parser. Merged silc-newconfig-final.patch.
[silc.git] / apps / silcd / server_backup.c
index 96f9c33f702ee2650f0e6c6e9d99b7e1f8ca1808..6b3d876a8e74999f6cf0c7be9696d10614773128 100644 (file)
@@ -26,6 +26,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
 /* Backup router */
 typedef struct {
   SilcServerEntry server;
+  SilcIDIP ip;
+  uint16 port;
   bool local;
 } SilcServerBackupEntry;
 
@@ -63,16 +65,22 @@ typedef struct {
   long start;
 } *SilcServerBackupProtocolContext;
 
-/* Sets the `backup_server' to be one of our backup router. This can be
-   called multiple times to set multiple backup routers. If `local' is
-   TRUE then the `backup_server' is in the local cell, if FALSE it is
-   in some other cell. */
+/* Adds the `backup_server' to be one of our backup router. This can be
+   called multiple times to set multiple backup routers. The `ip' and `port'
+   is the IP and port that the `backup_router' will replace if the `ip'
+   will become unresponsive. If `local' is TRUE then the `backup_server' is
+   in the local cell, if FALSE it is in some other cell. */
 
 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
-                           bool local)
+                           const char *ip, int port, bool local)
 {
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!ip)
+    return;
+
   if (!server->backup)
     server->backup = silc_calloc(1, sizeof(*server->backup));
 
@@ -80,6 +88,11 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
     if (!server->backup->servers[i].server) {
       server->backup->servers[i].server = backup_server;
       server->backup->servers[i].local = local;
+      memset(server->backup->servers[i].ip.data, 0,
+            sizeof(server->backup->servers[i].ip.data));
+      silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+                       sizeof(server->backup->servers[i].ip.data));
+      //server->backup->servers[i].port = port;
       return;
     }
   }
@@ -90,38 +103,46 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
                                         (i + 1));
   server->backup->servers[i].server = backup_server;
   server->backup->servers[i].local = local;
+  memset(server->backup->servers[i].ip.data, 0,
+        sizeof(server->backup->servers[i].ip.data));
+  silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+                   sizeof(server->backup->servers[i].ip.data));
+  //server->backup->servers[i].port = server_id->port;
   server->backup->servers_count++;
 }
 
-/* Returns the first backup router context. Returns NULL if we do not have
-   any backup servers. */
+/* Returns backup router for IP and port in `replacing' or NULL if there
+   does not exist backup router. */
 
-SilcServerEntry silc_server_backup_get(SilcServer server)
+SilcServerEntry silc_server_backup_get(SilcServer server, 
+                                      SilcServerID *server_id)
 {
-  SilcServerEntry backup_router;
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!server->backup)
     return NULL;
 
   for (i = 0; i < server->backup->servers_count; i++) {
-    if (server->backup->servers[i].server) {
-      backup_router = server->backup->servers[i].server;
-      server->backup->servers[i].server = NULL;
-      return backup_router;
-    }
+    SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, 16);
+    SILC_LOG_HEXDUMP(("IP"), server->backup->servers[i].ip.data, 16);
+    if (server->backup->servers[i].server &&
+       !memcmp(&server->backup->servers[i].ip, &server_id->ip.data,
+               sizeof(server_id->ip.data)))
+      return server->backup->servers[i].server;
   }
 
   return NULL;
 }
 
-/* Deletes the backup server `server_entry. */
-
-void silc_server_backup_del(SilcServer server, 
-                           SilcServerEntry server_entry)
+/* Deletes the backup server `server_entry'. */
+void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
 {
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!server->backup)
     return ;
 
@@ -145,6 +166,8 @@ void silc_server_backup_replaced_add(SilcServer server,
   int i;
   SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!server->backup)
     server->backup = silc_calloc(1, sizeof(*server->backup));
   if (!server->backup->replaced) {
@@ -186,7 +209,9 @@ bool silc_server_backup_replaced_get(SilcServer server,
 {
   int i;
 
-  SILC_LOG_DEBUG(("***********************************************"));
+  SILC_LOG_DEBUG(("Start"));
+
+  SILC_LOG_DEBUG(("*************************************"));
 
   if (!server->backup || !server->backup->replaced)
     return FALSE;
@@ -197,8 +222,8 @@ bool silc_server_backup_replaced_get(SilcServer server,
     SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, server_id->ip.data_len);
     SILC_LOG_HEXDUMP(("IP"), server->backup->replaced[i]->ip.data, 
                     server->backup->replaced[i]->ip.data_len);
-    if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip,
-               sizeof(server_id->ip))) {
+    if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip.data,
+               sizeof(server_id->ip.data))) {
       if (server_entry)
        *server_entry = server->backup->replaced[i]->server;
       SILC_LOG_DEBUG(("REPLACED"));
@@ -217,6 +242,8 @@ void silc_server_backup_replaced_del(SilcServer server,
 {
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!server->backup || !server->backup->replaced)
     return;
 
@@ -266,7 +293,7 @@ void silc_server_backup_broadcast(SilcServer server,
 
     silc_packet_send_prepare(sock, 0, 0, buffer->len); 
     silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, 
                        sock->outbuf, sock->outbuf->len);
 
     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
@@ -374,7 +401,8 @@ void silc_server_backup_resume_router(SilcServer server,
                                      SilcPacketContext *packet)
 {
   uint8 type, session;
-  int ret;
+  SilcServerBackupProtocolContext ctx;
+  int i, ret;
 
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
       sock->type == SILC_SOCKET_TYPE_UNKNOWN)
@@ -389,13 +417,34 @@ void silc_server_backup_resume_router(SilcServer server,
   if (ret < 0)
     return;
   
+  /* Activate the protocol for this socket if necessary */
+  if ((type == SILC_SERVER_BACKUP_RESUMED || 
+      type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol && 
+      ((SilcIDListData)sock->user_data)->status & 
+      SILC_IDLIST_STATUS_DISABLED) {
+    SilcServerEntry backup_router;
+
+    if (silc_server_backup_replaced_get(server, 
+                                       ((SilcServerEntry)sock->
+                                        user_data)->id, 
+                                       &backup_router)) {
+      SilcSocketConnection bsock = 
+       (SilcSocketConnection)backup_router->connection;
+      if (bsock->protocol && bsock->protocol->protocol &&
+         bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
+       sock->protocol = bsock->protocol;
+       ctx = sock->protocol->context;
+       ctx->sock = sock;
+      }
+    }
+  }
+
   /* If the backup resuming protocol is active then process the packet
      in the protocol. */
   if (sock->protocol && sock->protocol->protocol &&
       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
-    SilcServerBackupProtocolContext ctx = sock->protocol->context;
-    int i;
-
+    ctx = sock->protocol->context;
     ctx->type = type;
 
     SILC_LOG_DEBUG(("********************************"));
@@ -432,6 +481,9 @@ void silc_server_backup_resume_router(SilcServer server,
        to use it at this moment. */
     SilcIDListData idata = (SilcIDListData)sock->user_data;
 
+    SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
+                  "wait until backup resuming protocol is executed"));
+
     SILC_LOG_DEBUG(("We are replaced by an backup router in this cell"));
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
     return;
@@ -472,13 +524,13 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
                  sconn->remote_port));
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(server->config->listen_port->local_ip,
+  sock = silc_net_create_connection(server->config->server_info->server_ip,
                                    sconn->remote_port,
                                    sconn->remote_host);
   if (sock < 0) {
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_backup_connect_to_router,
-                          context, 2, 0, SILC_TASK_TIMEOUT, 
+                          context, 5, 0, SILC_TASK_TIMEOUT, 
                           SILC_TASK_PRI_NORMAL);
     return;
   }
@@ -506,7 +558,7 @@ void silc_server_backup_reconnect(SilcServer server,
   sconn->callback_context = context;
   silc_schedule_task_add(server->schedule, 0, 
                         silc_server_backup_connect_to_router,
-                        sconn, 2, 0, SILC_TASK_TIMEOUT,
+                        sconn, 1, 0, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
 }
 
@@ -568,6 +620,8 @@ static void silc_server_backup_connect_primary(SilcServer server,
     (SilcServerBackupProtocolContext)backup_router->protocol->context;
   SilcBuffer buffer;
 
+  SILC_LOG_DEBUG(("Start"));
+
   SILC_LOG_DEBUG(("********************************"));
   SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
 
@@ -596,6 +650,34 @@ static void silc_server_backup_connect_primary(SilcServer server,
   backup_router->protocol = NULL;
 }
 
+SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServer server = ctx->server;
+  SilcBuffer packet;
+  int i;
+
+  for (i = 0; i < ctx->sessions_count; i++)
+    if (ctx->sessions[i].server_entry == ctx->sock->user_data)
+      ctx->session = ctx->sessions[i].session;
+  
+  /* We've received all the CONNECTED packets and now we'll send the
+     ENDING packet to the new primary router. */
+  packet = silc_buffer_alloc(2);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
+                    SILC_STR_UI_CHAR(ctx->session),
+                    SILC_STR_END);
+  silc_server_packet_send(server, ctx->sock, 
+                         SILC_PACKET_RESUME_ROUTER, 0, 
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+  
+  protocol->state = SILC_PROTOCOL_STATE_END;
+}
+
 /* Resume protocol with RESUME_ROUTER packet: 
 
    SILC_PACKET_RESUME_ROUTER:
@@ -687,8 +769,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        if (silc_idcache_list_first(list, &id_cache)) {
          while (id_cache) {
            server_entry = (SilcServerEntry)id_cache->context;
-           if ((server_entry == server->id_entry) || 
-               !server_entry->connection) {
+           if (!server_entry || (server_entry == server->id_entry) || 
+               !server_entry->connection || !server_entry->data.send_key ||
+               (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
              if (!silc_idcache_list_next(list, &id_cache))
                break;
              else
@@ -703,7 +786,54 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
            ctx->sessions[ctx->sessions_count].server_entry = server_entry;
 
            SILC_LOG_DEBUG(("********************************"));
-           SILC_LOG_DEBUG(("START for session %d", ctx->sessions_count));
+           SILC_LOG_DEBUG(("START (local) for session %d", 
+                           ctx->sessions_count));
+
+           /* This connection is performing this protocol too now */
+           ((SilcSocketConnection)server_entry->connection)->protocol =
+             protocol;
+
+           if (server_entry->server_type == SILC_ROUTER)
+             packet->data[0] = SILC_SERVER_BACKUP_START;
+           else
+             packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
+           packet->data[1] = ctx->sessions_count;
+           silc_server_packet_send(server, server_entry->connection,
+                                   SILC_PACKET_RESUME_ROUTER, 0, 
+                                   packet->data, packet->len, FALSE);
+           ctx->sessions_count++;
+
+           if (!silc_idcache_list_next(list, &id_cache))
+             break;
+         }
+       }
+
+       silc_idcache_list_free(list);
+      }
+
+      if (silc_idcache_get_all(server->global_list->servers, &list)) {
+       if (silc_idcache_list_first(list, &id_cache)) {
+         while (id_cache) {
+           server_entry = (SilcServerEntry)id_cache->context;
+           if (!server_entry || (server_entry == server->id_entry) || 
+               !server_entry->connection || !server_entry->data.send_key ||
+               (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
+             if (!silc_idcache_list_next(list, &id_cache))
+               break;
+             else
+               continue;
+           }
+
+           ctx->sessions = silc_realloc(ctx->sessions,
+                                        sizeof(*ctx->sessions) *
+                                        (ctx->sessions_count + 1));
+           ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
+           ctx->sessions[ctx->sessions_count].connected = FALSE;
+           ctx->sessions[ctx->sessions_count].server_entry = server_entry;
+
+           SILC_LOG_DEBUG(("********************************"));
+           SILC_LOG_DEBUG(("START (global) for session %d", 
+                           ctx->sessions_count));
 
            /* This connection is performing this protocol too now */
            ((SilcSocketConnection)server_entry->connection)->protocol =
@@ -729,16 +859,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
       silc_buffer_free(packet);
 
-      /* If we are router then announce our possible servers. */
-      if (server->server_type == SILC_ROUTER)
-       silc_server_announce_servers(server, FALSE, 0, ctx->sock);
+      /* Announce all of our information */
+      silc_server_announce_servers(server, TRUE, 0, ctx->sock);
       silc_server_announce_clients(server, 0, ctx->sock);
       silc_server_announce_channels(server, 0, ctx->sock);
 
       protocol->state++;
     } else {
       /* Responder of the protocol. */
-      SilcServerConfigSectionServerConnection *primary;
+      SilcServerConfigSectionRouter *primary;
 
       /* We should have received START or START_GLOBAL packet */
       if (ctx->type != SILC_SERVER_BACKUP_START &&
@@ -754,18 +883,11 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
         to be back online. We send the CONNECTED packet after we've
         established the connection to the primary router. */
       primary = silc_server_config_get_primary_router(server->config);
-      if (primary) {
+      if (primary && server->backup_primary) {
        silc_server_backup_reconnect(server,
                                     primary->host, primary->port,
                                     silc_server_backup_connect_primary,
                                     ctx->sock);
-       if (server->server_type == SILC_ROUTER &&
-           (!server->router || 
-            server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
-         protocol->state++;
-       else
-         protocol->state = SILC_PROTOCOL_STATE_END;
-
       } else {
        /* Nowhere to connect just return the CONNECTED packet */
 
@@ -783,9 +905,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                                SILC_PACKET_RESUME_ROUTER, 0, 
                                packet->data, packet->len, FALSE);
        silc_buffer_free(packet);
-       protocol->state++;
       }
 
+      if (server->server_type == SILC_ROUTER &&
+         (!server->router || 
+          server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
+       protocol->state++;
+      else
+       protocol->state = SILC_PROTOCOL_STATE_END;
+
       ctx->sessions = silc_realloc(ctx->sessions,
                                   sizeof(*ctx->sessions) *
                                   (ctx->sessions_count + 1));
@@ -822,24 +950,12 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       SILC_LOG_DEBUG(("********************************"));
       SILC_LOG_DEBUG(("Sending ENDING packet to primary"));
 
-      for (i = 0; i < ctx->sessions_count; i++)
-       if (ctx->sessions[i].server_entry == ctx->sock->user_data)
-         ctx->session = ctx->sessions[i].session;
-
-      /* We've received all the CONNECTED packets and now we'll send the
-        ENDING packet to the new primary router. */
-      packet = silc_buffer_alloc(2);
-      silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-      silc_buffer_format(packet,
-                        SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
-                        SILC_STR_UI_CHAR(ctx->session),
-                        SILC_STR_END);
-      silc_server_packet_send(server, ctx->sock, 
-                             SILC_PACKET_RESUME_ROUTER, 0, 
-                             packet->data, packet->len, FALSE);
-      silc_buffer_free(packet);
-
-      protocol->state = SILC_PROTOCOL_STATE_END;
+      /* Send with a timeout */
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_backup_send_resumed,
+                            protocol, 1, 0, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      return;
     } else {
       /* Responder */
 
@@ -865,10 +981,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        break;
       }
 
-      /* Switch announced informations to our entry instead of using the
+      /* Switch announced informations to our primary router of using the
         backup router. */
+      silc_server_update_servers_by_server(server, ctx->sock->user_data, 
+                                          server->router);
       silc_server_update_clients_by_server(server, ctx->sock->user_data,
-                                          server->id_entry, TRUE, FALSE);
+                                          server->router, TRUE, FALSE);
+      if (server->server_type == SILC_SERVER)
+       silc_server_update_channels_by_server(server, ctx->sock->user_data, 
+                                             server->router);
 
       packet = silc_buffer_alloc(2);
       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
@@ -878,8 +999,45 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        if (silc_idcache_list_first(list, &id_cache)) {
          while (id_cache) {
            server_entry = (SilcServerEntry)id_cache->context;
-           if ((server_entry == server->id_entry) || 
-               !server_entry->connection) {
+           if (!server_entry || (server_entry == server->id_entry) || 
+               !server_entry->connection || !server_entry->data.send_key) {
+             if (!silc_idcache_list_next(list, &id_cache))
+               break;
+             else
+               continue;
+           }
+
+           SILC_LOG_DEBUG(("********************************"));
+           SILC_LOG_DEBUG(("RESUMED packet (local)"));
+
+           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+           /* This connection is performing this protocol too now */
+           ((SilcSocketConnection)server_entry->connection)->protocol =
+             protocol;
+
+           if (server_entry->server_type == SILC_ROUTER)
+             packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
+           else
+             packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
+           silc_server_packet_send(server, server_entry->connection,
+                                   SILC_PACKET_RESUME_ROUTER, 0, 
+                                   packet->data, packet->len, FALSE);
+
+           if (!silc_idcache_list_next(list, &id_cache))
+             break;
+         }
+       }
+
+       silc_idcache_list_free(list);
+      }
+
+      if (silc_idcache_get_all(server->global_list->servers, &list)) {
+       if (silc_idcache_list_first(list, &id_cache)) {
+         while (id_cache) {
+           server_entry = (SilcServerEntry)id_cache->context;
+           if (!server_entry || (server_entry == server->id_entry) || 
+               !server_entry->connection || !server_entry->data.send_key) {
              if (!silc_idcache_list_next(list, &id_cache))
                break;
              else
@@ -887,7 +1045,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
            }
 
            SILC_LOG_DEBUG(("********************************"));
-           SILC_LOG_DEBUG(("RESUMED packet"));
+           SILC_LOG_DEBUG(("RESUMED packet (global)"));
+
+           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
 
            /* This connection is performing this protocol too now */
            ((SilcSocketConnection)server_entry->connection)->protocol =
@@ -911,6 +1071,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
       silc_buffer_free(packet);
 
+      SILC_LOG_INFO(("We are now the primary router of our cell again"));
+
       /* For us this is the end of this protocol. */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -922,8 +1084,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   case SILC_PROTOCOL_STATE_END:
     {
       SilcIDListData idata;
-      SilcServerEntry primary;
-      SilcServerEntry backup_router;
+      SilcServerEntry router, backup_router;
 
       /* We should have been received RESUMED packet from our primary
         router. */
@@ -940,41 +1101,48 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       if (server->backup_router)
        server->server_type = SILC_BACKUP_ROUTER;
 
-      primary = (SilcServerEntry)ctx->sock->user_data;
-      if (silc_server_backup_replaced_get(server, primary->id, 
+      router = (SilcServerEntry)ctx->sock->user_data;
+      if (silc_server_backup_replaced_get(server, router->id, 
                                          &backup_router)) {
 
        if (backup_router == server->router) {
-         server->id_entry->router = ctx->sock->user_data;
-         server->router = ctx->sock->user_data;
+         server->id_entry->router = router;
+         server->router = router;
          SILC_LOG_INFO(("Switching back to primary router %s",
                         server->router->server_name));
-         SILC_LOG_DEBUG(("********************************"));
          SILC_LOG_DEBUG(("Switching back to primary router %s",
                          server->router->server_name));
          idata = (SilcIDListData)server->router;
          idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
-
-         /* Update the client entries of the backup router to the new 
-            primary router. */
-         silc_server_update_clients_by_server(server, backup_router,
-                                              primary, TRUE, FALSE);
-         silc_server_backup_replaced_del(server, backup_router);
-         silc_server_backup_add(server, backup_router,
-                                backup_router->server_type != SILC_ROUTER ?
-                                TRUE : FALSE);
+       } else {
+         SILC_LOG_INFO(("Resuming the use of router %s",
+                        router->server_name));
+         SILC_LOG_DEBUG(("Resuming the use of router %s",
+                         router->server_name));
+         idata = (SilcIDListData)router;
+         idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
        }
 
-       /* Announce all of our information to the new primary router. */
+       /* Update the client entries of the backup router to the new 
+          router */
+       silc_server_update_servers_by_server(server, backup_router, router);
+       silc_server_update_clients_by_server(server, backup_router,
+                                            router, TRUE, FALSE);
+       if (server->server_type == SILC_SERVER)
+         silc_server_update_channels_by_server(server, backup_router, router);
+       silc_server_backup_replaced_del(server, backup_router);
+       silc_server_backup_add(server, backup_router, 
+                              ctx->sock->ip, ctx->sock->port,
+                              backup_router->server_type != SILC_ROUTER ?
+                              TRUE : FALSE);
+
+       /* Announce all of our information to the router. */
        if (server->server_type == SILC_ROUTER)
-         silc_server_announce_servers(server, FALSE, 0,
-                                      server->router->connection);
-       
+         silc_server_announce_servers(server, FALSE, 0, router->connection);
+
        /* 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, router->connection);
+       silc_server_announce_channels(server, 0, router->connection);
       }
 
       /* Protocol has ended, call the final callback */
@@ -1023,15 +1191,39 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
   }
 
+  /* Remove this protocol from all server entries that has it */
   if (silc_idcache_get_all(server->local_list->servers, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        server_entry = (SilcServerEntry)id_cache->context;
        sock = (SilcSocketConnection)server_entry->connection;
 
-       if (sock->protocol && sock->protocol->protocol &&
-           sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP)
+       if (sock->protocol == protocol) {
          sock->protocol = NULL;
+
+         if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+       }
+       
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+    silc_idcache_list_free(list);
+  }
+
+  if (silc_idcache_get_all(server->global_list->servers, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       server_entry = (SilcServerEntry)id_cache->context;
+       sock = (SilcSocketConnection)server_entry->connection;
+
+       if (sock->protocol == protocol) {
+         sock->protocol = NULL;
+
+         if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+       }
        
        if (!silc_idcache_list_next(list, &id_cache))
          break;