New silcconfig library and server parser. Merged silc-newconfig-final.patch.
[silc.git] / apps / silcd / server_backup.c
index a3aaf17e888183828e3a862e9c8f3346f737f625..6b3d876a8e74999f6cf0c7be9696d10614773128 100644 (file)
@@ -16,6 +16,7 @@
   GNU General Public License for more details.
 
 */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
@@ -25,6 +26,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
 /* Backup router */
 typedef struct {
   SilcServerEntry server;
+  SilcIDIP ip;
+  uint16 port;
   bool local;
 } SilcServerBackupEntry;
 
@@ -62,34 +65,34 @@ typedef struct {
   long start;
 } *SilcServerBackupProtocolContext;
 
-/* Backup resuming protocol types */
-#define SILC_SERVER_BACKUP_START            1
-#define SILC_SERVER_BACKUP_START_GLOBAL     2
-#define SILC_SERVER_BACKUP_CONNECTED        3
-#define SILC_SERVER_BACKUP_ENDING           4
-#define SILC_SERVER_BACKUP_RESUMED          5
-#define SILC_SERVER_BACKUP_RESUMED_GLOBAL   6
-#define SILC_SERVER_BACKUP_REPLACED         20
-
-/* 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;
 
-  if (!server->backup) {
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!ip)
+    return;
+
+  if (!server->backup)
     server->backup = silc_calloc(1, sizeof(*server->backup));
-    server->backup->servers_count++;
-  }
 
   for (i = 0; i < server->backup->servers_count; i++) {
     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;
     }
   }
@@ -100,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 ;
 
@@ -155,16 +166,19 @@ void silc_server_backup_replaced_add(SilcServer server,
   int i;
   SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
 
-  if (!server->backup) {
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!server->backup)
     server->backup = silc_calloc(1, sizeof(*server->backup));
-    server->backup->servers_count++;
-  }
   if (!server->backup->replaced) {
     server->backup->replaced = 
       silc_calloc(1, sizeof(*server->backup->replaced));
     server->backup->replaced_count = 1;
   }
 
+  SILC_LOG_DEBUG(("********************************"));
+  SILC_LOG_DEBUG(("Replaced added"));
+
   memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
   //r->port = server_id->port;
   r->server = server_entry;
@@ -195,39 +209,48 @@ bool silc_server_backup_replaced_get(SilcServer server,
 {
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
+  SILC_LOG_DEBUG(("*************************************"));
+
   if (!server->backup || !server->backup->replaced)
     return FALSE;
 
-  for (i = 0; i < server->backup->servers_count; i++) {
+  for (i = 0; i < server->backup->replaced_count; i++) {
     if (!server->backup->replaced[i])
       continue;
-    if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip,
-               sizeof(server_id->ip))) {
+    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.data,
+               sizeof(server_id->ip.data))) {
       if (server_entry)
        *server_entry = server->backup->replaced[i]->server;
+      SILC_LOG_DEBUG(("REPLACED"));
       return TRUE;
     }
   }
 
+  SILC_LOG_DEBUG(("NOT REPLACED"));
   return FALSE;
 }
 
-/* Deletes the IP address and port from the `server_id' from being replaced
-   by an backup router. */
+/* Deletes a replaced host by the set `server_entry. */
 
 void silc_server_backup_replaced_del(SilcServer server,
-                                    SilcServerID *server_id)
+                                    SilcServerEntry server_entry)
 {
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!server->backup || !server->backup->replaced)
     return;
 
-  for (i = 0; i < server->backup->servers_count; i++) {
+  for (i = 0; i < server->backup->replaced_count; i++) {
     if (!server->backup->replaced[i])
       continue;
-    if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip,
-               sizeof(server_id->ip))) {
+    if (server->backup->replaced[i]->server == server_entry) {
       silc_free(server->backup->replaced[i]);
       server->backup->replaced[i] = NULL;
       return;
@@ -270,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),
@@ -378,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)
@@ -393,21 +417,51 @@ 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;
 
-    for (i = 0; i < ctx->sessions_count; i++) {
-      if (session == ctx->sessions[i].session) {
-       ctx->session = session;
-       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-       return;
+    SILC_LOG_DEBUG(("********************************"));
+    SILC_LOG_DEBUG(("Continuing protocol, type %d", type));
+
+    if (type != SILC_SERVER_BACKUP_RESUMED &&
+       type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
+      for (i = 0; i < ctx->sessions_count; i++) {
+       if (session == ctx->sessions[i].session) {
+         ctx->session = session;
+         silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+         return;
+       }
       }
+    } else {
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      return;
     }
 
     SILC_LOG_DEBUG(("Bad resume router packet"));
@@ -427,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;
@@ -467,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, 0, 2, SILC_TASK_TIMEOUT, 
+                          context, 5, 0, SILC_TASK_TIMEOUT, 
                           SILC_TASK_PRI_NORMAL);
     return;
   }
@@ -501,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);
 }
 
@@ -563,6 +620,11 @@ 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));
+
   /* Send the CONNECTED packet back to the backup router. */
   buffer = silc_buffer_alloc(2);
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
@@ -575,6 +637,10 @@ static void silc_server_backup_connect_primary(SilcServer server,
                          buffer->data, buffer->len, FALSE);
   silc_buffer_free(buffer);
 
+  /* The primary connection is disabled until it sends the RESUMED packet
+     to us. */
+  idata->status |= SILC_IDLIST_STATUS_DISABLED;
+
   /* Move this protocol context from this backup router connection to
      the primary router connection since it will send the subsequent
      packets in this protocol. We don't talk with backup router 
@@ -582,10 +648,34 @@ static void silc_server_backup_connect_primary(SilcServer server,
   sock->protocol = backup_router->protocol;
   ctx->sock = (SilcSocketConnection)server_entry->connection;
   backup_router->protocol = NULL;
+}
 
-  /* The primary connection is disabled until it sends the RESUMED packet
-     to us. */
-  idata->status |= SILC_IDLIST_STATUS_DISABLED;
+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: 
@@ -647,7 +737,7 @@ static void silc_server_backup_connect_primary(SilcServer server,
 
 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 {
-  SilcProtocol protocol = (SilcProtocol)protocol;
+  SilcProtocol protocol = (SilcProtocol)context;
   SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = ctx->server;
   SilcBuffer packet;
@@ -671,13 +761,17 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       packet = silc_buffer_alloc(2);
       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
 
+      SILC_LOG_DEBUG(("********************************"));
+      SILC_LOG_DEBUG(("Sending START packets"));
+
       /* Send the START packet to primary router and normal servers. */
       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;
-           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
@@ -691,6 +785,14 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
            ctx->sessions[ctx->sessions_count].connected = FALSE;
            ctx->sessions[ctx->sessions_count].server_entry = server_entry;
 
+           SILC_LOG_DEBUG(("********************************"));
+           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
@@ -709,18 +811,63 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        silc_idcache_list_free(list);
       }
 
-      /* Now, announce all of our information to the primary router */
-      if (server->server_type == SILC_ROUTER)
-       silc_server_announce_servers(server, FALSE, 0);
-      silc_server_announce_clients(server, 0);
-      silc_server_announce_channels(server, 0);
+      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 =
+             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);
+      }
 
       silc_buffer_free(packet);
 
+      /* 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 &&
@@ -729,17 +876,49 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        break;
       }
 
+      SILC_LOG_DEBUG(("********************************"));
+      SILC_LOG_DEBUG(("Received START packet, reconnecting to router"));
+
       /* Connect to the primary router that was down that is now supposed
         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);
+      } else {
+       /* Nowhere to connect just return the CONNECTED packet */
 
-      protocol->state++;
+       SILC_LOG_DEBUG(("********************************"));
+       SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
+       
+       /* Send the CONNECTED packet back to the backup 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_CONNECTED),
+                          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);
+      }
+
+      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));
+      ctx->sessions[ctx->sessions_count].session = ctx->session;
+      ctx->sessions_count++;
     }
     break;
 
@@ -753,31 +932,30 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        break;
       }
 
+      SILC_LOG_DEBUG(("********************************"));
+      SILC_LOG_DEBUG(("Received CONNECTED packet, session %d", ctx->session));
+
       for (i = 0; i < ctx->sessions_count; i++) {
        if (ctx->sessions[i].session == ctx->session) {
          ctx->sessions[i].connected = TRUE;
+         break;
        }
       }
 
       for (i = 0; i < ctx->sessions_count; i++) {
        if (!ctx->sessions[i].connected)
-         break;
+         return;
       }
 
-      /* 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);
+      SILC_LOG_DEBUG(("********************************"));
+      SILC_LOG_DEBUG(("Sending ENDING packet to primary"));
 
-      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 */
 
@@ -787,17 +965,32 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        break;
       }
 
+      SILC_LOG_DEBUG(("********************************"));
+      SILC_LOG_DEBUG(("Received ENDING packet, sending RESUMED packets"));
+
       /* This state is received by the primary router but also servers
         and perhaps other routers so check that if we are the primary
         router of the cell then start sending RESUMED packets.  If we
         are normal server or one of those other routers then procede
         to next state. */
-      if (!(server->router->data.status & SILC_IDLIST_STATUS_DISABLED)) {
+      if (server->router &&
+         !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
+         silc_server_config_is_primary_route(server->config)) {
        /* We'll wait for RESUMED packet */
        protocol->state = SILC_PROTOCOL_STATE_END;
        break;
       }
 
+      /* 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->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));
 
@@ -806,19 +999,64 @@ 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
+               continue;
+           }
+
+           SILC_LOG_DEBUG(("********************************"));
+           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 =
+             protocol;
+
            if (server_entry->server_type == SILC_ROUTER)
              packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
            else
              packet->data[0] = SILC_SERVER_BACKUP_RESUMED_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);
@@ -833,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);
@@ -844,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. */
@@ -855,32 +1094,55 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        break;
       }
 
+      SILC_LOG_DEBUG(("********************************"));
+      SILC_LOG_DEBUG(("Received RESUMED packet"));
+
       /* We have now new primary router. All traffic goes there from now on. */
       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(("Switching back to primary router %s",
-                       server->router->server_name));
+                         server->router->server_name));
          idata = (SilcIDListData)server->router;
          idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
+       } 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. We
-          announce all that was updated after the protocol was started since
-          the router knows all the older stuff. */
+       /* 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, ctx->start - 60);
-       
+         silc_server_announce_servers(server, FALSE, 0, router->connection);
+
        /* Announce our clients and channels to the router */
-       silc_server_announce_clients(server, ctx->start - 60);
-       silc_server_announce_channels(server, ctx->start - 60);
+       silc_server_announce_clients(server, 0, router->connection);
+       silc_server_announce_channels(server, 0, router->connection);
       }
 
       /* Protocol has ended, call the final callback */
@@ -892,9 +1154,19 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
     break;
 
   case SILC_PROTOCOL_STATE_ERROR:
+    /* Protocol has ended, call the final callback */
+    if (protocol->final_callback)
+      silc_protocol_execute_final(protocol, server->schedule);
+    else
+      silc_protocol_free(protocol);
     break;
 
   case SILC_PROTOCOL_STATE_FAILURE:
+    /* Protocol has ended, call the final callback */
+    if (protocol->final_callback)
+      silc_protocol_execute_final(protocol, server->schedule);
+    else
+      silc_protocol_free(protocol);
     break;
 
   case SILC_PROTOCOL_STATE_UNKNOWN:
@@ -904,5 +1176,65 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
 {
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServer server = ctx->server;
+  SilcServerEntry server_entry;
+  SilcSocketConnection sock;
+  SilcIDCacheList list;
+  SilcIDCacheEntry id_cache;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+    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 == 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;
+      }
+    }
+    silc_idcache_list_free(list);
+  }
 
+  if (ctx->sock->protocol)
+    ctx->sock->protocol = NULL;
+  silc_protocol_free(protocol);
+  silc_free(ctx->sessions);
+  silc_free(ctx);
 }