Backup protocol version 1.2 implementation. Testing required.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 5 Oct 2003 17:23:08 +0000 (17:23 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 5 Oct 2003 17:23:08 +0000 (17:23 +0000)
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server_backup.c
apps/silcd/server_backup.h
apps/silcd/server_internal.h

index e6b4e7d7c7d8d40c399df8aa8f663204e9f804a6..3d06ca0305ef69bdcba9ae3903643ab6ae33f0a5 100644 (file)
@@ -596,7 +596,7 @@ void silc_server_notify(SilcServer server,
                                      SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
-                                     channel->founder_key);
+                                     channel->founder_key, NULL);
       }
 
       /* If we received same mode from our primary check whether founder
@@ -617,6 +617,48 @@ void silc_server_notify(SilcServer server,
                                            &channel->founder_key);
       }
 
+      /* Check also for channel public key list */
+      if (server->server_type == SILC_SERVER &&
+         sock == SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+       SilcBuffer chpklist;
+       SilcBuffer sidp;
+       unsigned char mask[4];
+
+       SILC_LOG_DEBUG(("Channel public key list received from router"));
+       tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+       if (!tmp)
+         break;
+
+       /* Set the router's list, and send the notify to channel too so that
+          channel gets the list */
+       silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len);
+       chpklist = silc_server_get_channel_pk_list(server, channel,
+                                                  FALSE, FALSE);
+       if (!chpklist)
+         break;
+       sidp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+       SILC_PUT32_MSB(channel->mode, mask);
+       silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+                                          SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+                                          sidp->data, sidp->len,
+                                          mask, 4,
+                                          channel->cipher,
+                                          channel->cipher ?
+                                          strlen(channel->cipher) : 0,
+                                          channel->hmac_name,
+                                          channel->hmac_name ?
+                                          strlen(channel->hmac_name) : 0,
+                                          channel->passphrase,
+                                          channel->passphrase ?
+                                          strlen(channel->passphrase) : 0,
+                                          NULL, 0,
+                                          chpklist->data, chpklist->len);
+       silc_buffer_free(sidp);
+       silc_buffer_free(chpklist);
+       goto out;
+      }
+
       break;
     }
 
@@ -631,7 +673,7 @@ void silc_server_notify(SilcServer server,
                                      SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
-                                     channel->founder_key);
+                                     channel->founder_key, NULL);
        goto out;
       }
     } else {
@@ -646,7 +688,7 @@ void silc_server_notify(SilcServer server,
                                      SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
-                                     channel->founder_key);
+                                     channel->founder_key, NULL);
        goto out;
       }
 
@@ -665,7 +707,7 @@ void silc_server_notify(SilcServer server,
                                          SILC_ID_SERVER, channel->cipher,
                                          channel->hmac_name,
                                          channel->passphrase,
-                                         channel->founder_key);
+                                         channel->founder_key, NULL);
            silc_hash_table_list_reset(&htl);
            goto out;
          }
@@ -728,7 +770,7 @@ void silc_server_notify(SilcServer server,
                                      mode, server->id, SILC_ID_SERVER,
                                      channel->cipher,
                                      channel->hmac_name,
-                                     channel->passphrase, NULL);
+                                     channel->passphrase, NULL, NULL);
        if (channel->founder_key)
          silc_pkcs_public_key_free(channel->founder_key);
        channel->founder_key = NULL;
@@ -743,7 +785,27 @@ void silc_server_notify(SilcServer server,
                                    mode, server->id, SILC_ID_SERVER,
                                    channel->cipher,
                                    channel->hmac_name,
-                                   channel->passphrase, NULL);
+                                   channel->passphrase, NULL, NULL);
+    }
+
+    /* Process channel public key(s). */
+    tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+    if (tmp && mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+      SilcStatus ret =
+       silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len);
+
+      /* If list was set already we will enforce the same list to server. */
+      if (ret == SILC_STATUS_ERR_OPERATION_ALLOWED) {
+       SilcBuffer chpklist = silc_server_get_channel_pk_list(server, channel,
+                                                             TRUE, FALSE);
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     mode, server->id, SILC_ID_SERVER,
+                                     channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase, NULL,
+                                     chpklist);
+       silc_buffer_free(chpklist);
+      }
     }
 
     /* Send the same notify to the channel */
@@ -754,12 +816,20 @@ void silc_server_notify(SilcServer server,
     /* Change mode */
     channel->mode = mode;
 
+    /* Cleanup if some modes are removed */
+
     if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) &&
        channel->founder_key) {
       silc_pkcs_public_key_free(channel->founder_key);
       channel->founder_key = NULL;
     }
 
+    if (!(channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) &&
+       channel->channel_pubkeys) {
+      silc_hash_table_free(channel->channel_pubkeys);
+      channel->channel_pubkeys = NULL;
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
@@ -1304,9 +1374,9 @@ void silc_server_notify(SilcServer server,
        sock = server_entry->connection;
        SILC_LOG_DEBUG(("Closing connection %s after SERVER_SIGNOFF",
                       sock->hostname));
-       SILC_SET_DISCONNECTING(sock);
        if (sock->user_data)
          silc_server_free_sock_user_data(server, sock, NULL);
+       SILC_SET_DISCONNECTING(sock);
        silc_server_close_connection(server, sock);
       }
 
@@ -2550,21 +2620,15 @@ SilcServerEntry silc_server_new_server(SilcServer server,
      protocol has been completed. */
   if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
       silc_server_backup_replaced_get(server, server_id, NULL)) {
-    /* Send packet to the server indicating that it cannot use this
+    /* Send packet to the router indicating that it cannot use this
        connection as it has been replaced by backup router. */
-    SilcBuffer 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_REPLACED),
-                      SILC_STR_UI_CHAR(0),
-                      SILC_STR_END);
-    silc_server_packet_send(server, sock,
-                           SILC_PACKET_RESUME_ROUTER, 0,
-                           packet->data, packet->len, TRUE);
-    silc_buffer_free(packet);
+    SILC_LOG_DEBUG(("Remote router has been replaced by backup router, "
+                   "disabling its connection"));
+
+    silc_server_backup_send_replaced(server, sock);
 
     /* Mark the router disabled. The data sent earlier will go but nothing
-       after this does not go to this connection. */
+       after this goes to this connection. */
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
   } else {
     /* If it is router announce our stuff to it. */
index bc39e010828c788bafde4ff3ff436b163ceb6426..1f18368ec07d0e8a2170c502877a788a381e69b7 100644 (file)
@@ -291,8 +291,6 @@ bool silc_server_init(SilcServer server)
   if (server->config->debug_string) {
     silc_debug = TRUE;
     silc_log_set_debug_string(server->config->debug_string);
-  } else {
-    silc_debug = FALSE;
   }
 #endif /* SILC_DEBUG */
 
@@ -436,10 +434,7 @@ bool silc_server_init(SilcServer server)
   /* Register protocols */
   silc_server_protocols_register();
 
-  /* Add the first task to the scheduler. This is task that is executed by
-     timeout. It expires as soon as the caller calls silc_server_run. This
-     task performs authentication protocol and key exchange with our
-     primary router. */
+  /* Create connections to configured routers. */
   silc_server_create_connections(server);
 
   /* Add listener task to the scheduler. This task receives new connections
@@ -784,6 +779,8 @@ void silc_server_stop(SilcServer server)
 
        silc_schedule_task_del_by_context(server->schedule,
                                          server->sockets[i]);
+       silc_schedule_task_del_by_fd(server->schedule,
+                                    server->sockets[i]->sock);
        silc_server_disconnect_remote(server, server->sockets[i],
                                      SILC_STATUS_OK,
                                      "Server is shutting down");
@@ -1304,8 +1301,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     silc_free(ctx->dest_id);
+    sock->protocol = NULL;
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
+    sock->protocol = protocol;
 
     /* Try reconnecting if configuration wants it */
     if (!sconn->no_reconnect) {
@@ -1375,8 +1374,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   if (!id_entry) {
     silc_free(ctx->dest_id);
     SILC_LOG_ERROR(("Cannot add new server entry to cache"));
+    sock->protocol = NULL;
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
+    sock->protocol = protocol;
     goto out;
   }
 
@@ -1411,6 +1412,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       SILC_LOG_DEBUG(("This connection is our primary router"));
       server->id_entry->router = id_entry;
       server->router = id_entry;
+      server->router->server_type = SILC_ROUTER;
       server->standalone = FALSE;
 
       /* If we are router then announce our possible servers.  Backup
@@ -1432,6 +1434,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     }
   } else {
     /* Add this server to be our backup router */
+    id_entry->server_type = SILC_BACKUP_ROUTER;
     silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
                           sconn->backup_replace_port, FALSE);
   }
@@ -1673,7 +1676,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
       (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
     /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error key exchange protocol"));
+    SILC_LOG_DEBUG(("Error in key exchange protocol"));
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     silc_ske_free_key_material(ctx->keymat);
@@ -1686,9 +1689,19 @@ 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_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
-                                 NULL);
+
+    if (!SILC_IS_DISCONNECTING(sock)) {
+      SILC_LOG_INFO(("Key exchange failed for %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_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
+                                   NULL);
+    }
+
     server->stat.auth_failures++;
     return;
   }
@@ -1804,8 +1817,17 @@ 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_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
-                                 NULL);
+
+    if (!SILC_IS_DISCONNECTING(sock)) {
+      SILC_LOG_INFO(("Authentication failed for %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_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
+                                   NULL);
+    }
     server->stat.auth_failures++;
     return;
   }
@@ -1840,6 +1862,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                            router->backup_replace_ip, 0)) {
          SILC_LOG_INFO(("Will not accept connections because we do "
                         "not have backup router connection established"));
+         sock->protocol = NULL;
          silc_server_disconnect_remote(server, sock,
                                        SILC_STATUS_ERR_PERM_DENIED,
                                        "We do not have connection to backup "
@@ -1868,6 +1891,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
+       sock->protocol = NULL;
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_AUTH_FAILED, NULL);
        server->stat.auth_failures++;
@@ -1923,6 +1947,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
          !SILC_PRIMARY_ROUTE(server)) {
        SILC_LOG_INFO(("Will not accept server connection because we do "
                       "not have primary router connection established"));
+       sock->protocol = NULL;
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_PERM_DENIED,
                                      "We do not have connection to primary "
@@ -2011,6 +2036,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                            router->backup_replace_ip, 0)) {
          SILC_LOG_INFO(("Will not accept connections because we do "
                         "not have backup router connection established"));
+         sock->protocol = NULL;
          silc_server_disconnect_remote(server, sock,
                                        SILC_STATUS_ERR_PERM_DENIED,
                                        "We do not have connection to backup "
@@ -2056,6 +2082,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       if (!new_server) {
        SILC_LOG_ERROR(("Could not add new server to cache"));
        silc_free(sock->user_data);
+       sock->protocol = NULL;
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_AUTH_FAILED, NULL);
        server->stat.auth_failures++;
@@ -2176,7 +2203,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
   if (type == SILC_TASK_WRITE) {
     /* Do not send data to disconnected connection */
-    if (SILC_IS_DISCONNECTED(sock)) {
+    if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
       SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
       return;
     }
@@ -2207,9 +2234,9 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router")));
 
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
     }
     return;
@@ -2229,9 +2256,9 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
                       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_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
     }
     return;
@@ -2251,10 +2278,18 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     }
 
     SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
-    SILC_SET_DISCONNECTING(sock);
 
     if (sock->user_data) {
       char tmp[128];
+
+      /* If backup disconnected then mark that resuming willl not be allowed */
+      if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
+       SilcServerEntry server_entry = sock->user_data;
+       if (server_entry->server_type == SILC_BACKUP_ROUTER)
+         server->backup_closed = TRUE;
+      }
+
       if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
        silc_server_free_sock_user_data(server, sock, tmp);
       else
@@ -2264,6 +2299,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
       silc_server_create_connections(server);
     }
 
+    SILC_SET_DISCONNECTING(sock);
     silc_server_close_connection(server, sock);
     return;
   }
@@ -2307,9 +2343,9 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
       server->backup_noswitch = TRUE;
 
-    SILC_SET_DISCONNECTING(sock);
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock, NULL);
+    SILC_SET_DISCONNECTING(sock);
     silc_server_close_connection(server, sock);
   }
 }
@@ -2450,9 +2486,9 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
       if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
        server->backup_noswitch = TRUE;
 
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
     }
 
@@ -2522,10 +2558,18 @@ void silc_server_packet_parse_type(SilcServer server,
       /* Do not switch to backup in case of error */
       server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
 
+      /* If backup disconnected then mark that resuming willl not be allowed */
+      if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
+       SilcServerEntry server_entry = sock->user_data;
+       if (server_entry->server_type == SILC_BACKUP_ROUTER)
+         server->backup_closed = TRUE;
+      }
+
       /* Handle the disconnection from our end too */
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
       server->backup_noswitch = FALSE;
     }
@@ -2554,6 +2598,19 @@ void silc_server_packet_parse_type(SilcServer server,
     if (sock->protocol) {
       sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      break;
+    }
+
+    /* Check for failure START_USE from backup router */
+    if (server->server_type == SILC_SERVER &&
+       server->backup_primary && packet->buffer->len == 4) {
+      SilcUInt32 type;
+      SILC_GET32_MSB(type, packet->buffer->data);
+      if (type == SILC_SERVER_BACKUP_START_USE) {
+       /* Attempt to reconnect to primary */
+       SILC_LOG_DEBUG(("Received failed START_USE from backup %s", sock->ip));
+       silc_server_create_connections(server);
+      }
     }
     break;
 
@@ -2944,8 +3001,11 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
   SilcServer server = app_context;
   SilcSocketConnection sock = context;
 
+  SILC_LOG_DEBUG(("Deleting socket %p", sock));
+
   /* Close the actual connection */
   silc_net_close_connection(sock->sock);
+  server->sockets[sock->sock] = NULL;
 
   /* We won't listen for this connection anymore */
   silc_schedule_task_del_by_fd(server->schedule, sock->sock);
@@ -2961,53 +3021,49 @@ void silc_server_close_connection(SilcServer server,
 {
   char tmp[128];
 
-  if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
+  if (SILC_IS_DISCONNECTED(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);
+    server->sockets[sock->sock] = NULL;
+    return;
+  }
+
+  /* If any protocol is active cancel its execution. It will call
+     the final callback which will finalize the disconnection. */
+  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;
+    silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
     return;
   }
 
   memset(tmp, 0, sizeof(tmp));
   silc_socket_get_error(sock, tmp, sizeof(tmp));
   SILC_LOG_INFO(("Closing 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"), tmp[0] ? tmp : ""));
-
-  /* Unregister all tasks */
-  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
-
-  server->sockets[sock->sock] = NULL;
-
-  /* If sock->user_data is NULL then we'll check for active protocols
-     here since the silc_server_free_sock_user_data has not been called
-     for this connection. */
-  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 && 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;
-      silc_protocol_execute_final(sock->protocol, server->schedule);
-      sock->protocol = NULL;
-      return;
-    }
-  }
+                sock->port,
+                (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                 sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                 "Router"), tmp[0] ? tmp : ""));
 
+  SILC_SET_DISCONNECTED(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);
+  server->sockets[sock->sock] = NULL;
 }
 
 /* Sends disconnect message to remote connection and disconnects the
-   connection. */
+   connection.  NOTE: If this is called from protocol callback
+   then sock->protocol must be set NULL before calling this, since
+   this routine dispatches protocol callbacks too. */
 
 void silc_server_disconnect_remote(SilcServer server,
                                   SilcSocketConnection sock,
@@ -3022,7 +3078,8 @@ void silc_server_disconnect_remote(SilcServer server,
   if (!sock)
     return;
 
-  if (SILC_IS_DISCONNECTED(sock)) {
+  if (SILC_IS_DISCONNECTING(sock)) {
+    SILC_SET_DISCONNECTED(sock);
     silc_server_close_connection(server, sock);
     return;
   }
@@ -3061,7 +3118,7 @@ void silc_server_disconnect_remote(SilcServer server,
   silc_server_packet_queue_purge(server, sock);
 
   /* Mark the connection to be disconnected */
-  SILC_SET_DISCONNECTED(sock);
+  SILC_SET_DISCONNECTING(sock);
   silc_server_close_connection(server, sock);
 }
 
@@ -3151,6 +3208,17 @@ void silc_server_free_sock_user_data(SilcServer server,
                                     SilcSocketConnection sock,
                                     const char *signoff_message)
 {
+
+  /* If any protocol is active cancel its execution */
+  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;
+    silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
+  }
+
   switch (sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
@@ -3197,16 +3265,22 @@ void silc_server_free_sock_user_data(SilcServer server,
            server->router = backup_router;
            server->router_connect = time(0);
            server->backup_primary = TRUE;
+           backup_router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+           /* Send START_USE to backup router to indicate we have switched */
+           silc_server_backup_send_start_use(server,
+                                             backup_router->connection,
+                                             FALSE);
          } else {
            SILC_LOG_INFO(("We are now new primary router in this cell"));
            server->id_entry->router = NULL;
            server->router = NULL;
            server->standalone = TRUE;
-
-           /* We stop here to take a breath */
-           sleep(2);
          }
 
+         /* We stop here to take a breath */
+         sleep(2);
+
          if (server->server_type == SILC_BACKUP_ROUTER) {
            server->server_type = SILC_ROUTER;
 
@@ -3349,16 +3423,6 @@ void silc_server_free_sock_user_data(SilcServer server,
     }
   }
 
-  /* If any protocol is active cancel its execution */
-  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;
-    silc_protocol_execute_final(sock->protocol, server->schedule);
-    sock->protocol = NULL;
-  }
-
   sock->user_data = NULL;
 }
 
@@ -4289,7 +4353,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   SilcBuffer chidp, clidp, csidp;
-  SilcBuffer tmp, fkey = NULL;
+  SilcBuffer tmp, fkey = NULL, chpklist;
   int len;
   unsigned char mode[4];
   char *hmac;
@@ -4298,6 +4362,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
 
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   csidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+  chpklist = silc_server_get_channel_pk_list(server, channel, TRUE, FALSE);
 
   /* CMODE notify */
   SILC_PUT32_MSB(channel->mode, mode);
@@ -4306,7 +4371,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
     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,
+                                      7, csidp->data, csidp->len,
                                       mode, sizeof(mode),
                                       NULL, 0,
                                       hmac, hmac ? strlen(hmac) : 0,
@@ -4314,7 +4379,9 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                       channel->passphrase ?
                                       strlen(channel->passphrase) : 0,
                                       fkey ? fkey->data : NULL,
-                                      fkey ? fkey->len : 0);
+                                      fkey ? fkey->len : 0,
+                                      chpklist ? chpklist->data : NULL,
+                                      chpklist ? chpklist->len : 0);
   len = tmp->len;
   *channel_modes =
     silc_buffer_realloc(*channel_modes,
index 700e76f24c086f04786096f06ca41c9cc7d3ca1a..48cff69b13e147c9efa6fd4870cb3c718dff62e7 100644 (file)
@@ -26,6 +26,9 @@ static void silc_server_backup_connect_primary(SilcServer server,
                                               SilcServerEntry server_entry,
                                               void *context);
 
+
+/************************** Types and Definitions ***************************/
+
 /* Backup router */
 typedef struct {
   SilcServerEntry server;
@@ -68,6 +71,9 @@ typedef struct {
   long start;
 } *SilcServerBackupProtocolContext;
 
+
+/********************* Backup Configuration Routines ************************/
+
 /* 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'
@@ -88,6 +94,12 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
       return;
   }
 
+  /* See if already added */
+  for (i = 0; i < server->backup->servers_count; i++) {
+    if (server->backup->servers[i].server == backup_server)
+      return;
+  }
+
   SILC_LOG_DEBUG(("Backup router %s will replace %s",
                  ((SilcSocketConnection)backup_server->connection)->ip,
                  ip, port));
@@ -119,7 +131,7 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
   server->backup->servers_count++;
 }
 
-/* Returns backup router for IP and port in `replacing' or NULL if there
+/* Returns backup router for IP and port in `server_id' or NULL if there
    does not exist backup router. */
 
 SilcServerEntry silc_server_backup_get(SilcServer server,
@@ -430,6 +442,53 @@ void silc_server_backup_send_dest(SilcServer server,
   }
 }
 
+/* Send the START_USE indication to remote connection.  If `failure' is
+   TRUE then this sends SILC_PACKET_FAILURE.  Otherwise it sends
+   SILC_PACKET_RESUME_ROUTER. */
+
+void silc_server_backup_send_start_use(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      bool failure)
+{
+  unsigned char data[4];
+
+  SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
+                 failure ? "failure" : "success", sock->ip));
+
+  if (failure) {
+    SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
+    silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
+                           data, 4, FALSE);
+  } else {
+    data[0] = SILC_SERVER_BACKUP_START_USE;
+    data[1] = 0;
+    silc_server_packet_send(server, sock,
+                           SILC_PACKET_RESUME_ROUTER, 0,
+                           data, 2, FALSE);
+  }
+}
+
+/* Send the REPLACED indication to remote router.  This is send by the
+   primary router (remote router) of the primary router that came back
+   online.  This is not sent by backup router or any other server. */
+
+void silc_server_backup_send_replaced(SilcServer server,
+                                     SilcSocketConnection sock)
+{
+  unsigned char data[4];
+
+  SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
+
+  data[0] = SILC_SERVER_BACKUP_REPLACED;
+  data[1] = 0;
+  silc_server_packet_send(server, sock,
+                         SILC_PACKET_RESUME_ROUTER, 0,
+                         data, 2, FALSE);
+}
+
+
+/************************ Backup Resuming Protocol **************************/
+
 SILC_TASK_CALLBACK(silc_server_backup_timeout)
 {
   SilcProtocol protocol = context;
@@ -441,6 +500,45 @@ SILC_TASK_CALLBACK(silc_server_backup_timeout)
   silc_protocol_execute_final(protocol, server->schedule);
 }
 
+typedef struct {
+  SilcServer server;
+  SilcSocketConnection sock;
+  SilcPacketContext *packet;
+} *SilcServerBackupPing;
+
+/* PING command reply callback */
+
+void silc_server_backup_ping_reply(void *context, void *reply)
+{
+  SilcServerBackupPing pc = context;
+  SilcServerCommandReplyContext cmdr = reply;
+
+  if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
+    /* Timeout error occurred, the primary is really down. */
+    SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
+
+    SILC_LOG_DEBUG(("PING timeout, primary is down"));
+
+    if (primary) {
+      if (primary->user_data)
+       silc_server_free_sock_user_data(pc->server, primary, NULL);
+      SILC_SET_DISCONNECTING(primary);
+      silc_server_close_connection(pc->server, primary);
+    }
+
+    /* Reprocess the RESUME_ROUTER packet */
+    silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
+  } else {
+    /* The primary is not down, refuse to serve the server as primary */
+    SILC_LOG_DEBUG(("PING received, primary is up"));
+    silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
+  }
+
+  silc_socket_free(pc->sock);
+  silc_packet_context_free(pc->packet);
+  silc_free(pc);
+}
+
 /* Processes incoming RESUME_ROUTER packet. This can give the packet
    for processing to the protocol handler or allocate new protocol if
    start command is received. */
@@ -451,14 +549,19 @@ void silc_server_backup_resume_router(SilcServer server,
 {
   SilcUInt8 type, session;
   SilcServerBackupProtocolContext ctx;
+  SilcIDListData idata;
   int i, ret;
 
+  SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
+
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
       sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
     SILC_LOG_DEBUG(("Bad packet received"));
     return;
   }
 
+  idata = (SilcIDListData)sock->user_data;
+
   ret = silc_buffer_unformat(packet->buffer,
                             SILC_STR_UI_CHAR(&type),
                             SILC_STR_UI_CHAR(&session),
@@ -468,77 +571,79 @@ void silc_server_backup_resume_router(SilcServer server,
     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;
-      }
+  /* Check whether this packet is used to tell us that server will start
+     using us as primary router. */
+  if (type == SILC_SERVER_BACKUP_START_USE) {
+    SilcBuffer idp;
+    SilcServerBackupPing pc;
+
+    /* If we are normal server then backup router has sent us back
+       this reply and we use the backup as primary router now. */
+    if (server->server_type == SILC_SERVER) {
+      /* Nothing to do here actually, since we have switched already. */
+      SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
+      return;
     }
-  }
 
-  /* 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) {
-    ctx = sock->protocol->context;
-    ctx->type = type;
+    /* Backup router following. */
 
-    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);
+    /* If we are marked as router then the primary is down and we send
+       success START_USE back to the server. */
+    if (server->server_type == SILC_ROUTER) {
+      SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
+      silc_server_backup_send_start_use(server, sock, FALSE);
       return;
     }
 
-    SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
-    return;
-  }
-
-  /* We don't have protocol active. If we are router and the packet is
-     coming from our primary router then lets check whether it means we've
-     been replaced by an backup router in my cell. This is usually received
-     immediately after we've connected to our primary router. */
+    /* We have just lost primary, send success START_USE back */
+    if (server->standalone) {
+      SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
+                     sock->ip));
+      silc_server_backup_send_start_use(server, sock, FALSE);
+      return;
+    }
 
-  if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
-      sock && SILC_PRIMARY_ROUTE(server) == sock &&
-      type == SILC_SERVER_BACKUP_REPLACED) {
-    /* We have been replaced by an backup router in our cell. We must
-       mark our primary router connection disabled since we are not allowed
-       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"));
-    idata->status |= SILC_IDLIST_STATUS_DISABLED;
+    /* We are backup router. This server claims that our primary is down.
+       We will check this ourselves by sending PING command to the primary. */
+    SILC_LOG_DEBUG(("Sending PING to detect status of primary router"));
+    idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+    silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
+                            SILC_COMMAND_PING, ++server->cmd_ident, 1,
+                            1, idp->data, idp->len);
+    silc_buffer_free(idp);
+
+    /* Reprocess this packet after received reply from router */
+    pc = silc_calloc(1, sizeof(*pc));
+    pc->server = server;
+    pc->sock = silc_socket_dup(sock);
+    pc->packet = silc_packet_context_dup(packet);
+    silc_server_command_pending_timed(server, SILC_COMMAND_PING,
+                                     server->cmd_ident,
+                                     silc_server_backup_ping_reply, pc, 15);
     return;
   }
 
-  if (type == SILC_SERVER_BACKUP_START ||
-      type == SILC_SERVER_BACKUP_START_GLOBAL) {
-    /* We have received a start for resuming protocol. */
+
+  /* Start the resuming protocol if requested. */
+  if (type == SILC_SERVER_BACKUP_START) {
+    /* We have received a start for resuming protocol.  We are either
+       primary router that came back online or normal server. */
     SilcServerBackupProtocolContext proto_ctx;
 
+    /* If backup had closed the connection earlier we won't allow resuming
+       since we (primary router) have never gone away. */
+    if (server->server_type == SILC_ROUTER && !server->backup_router &&
+       server->backup_closed) {
+      unsigned char data[4];
+      SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
+                     "primary router"));
+      SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
+      silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
+                             data, 4, FALSE);
+      server->backup_closed = FALSE;
+      return;
+    }
+
     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
     proto_ctx->server = server;
     proto_ctx->sock = sock;
@@ -559,6 +664,68 @@ void silc_server_backup_resume_router(SilcServer server,
                           silc_server_backup_timeout,
                           sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_NORMAL);
+    return;
+  }
+
+
+  /* If we are router and the packet is coming from our primary router
+     then it means we have been replaced by an backup router in our cell. */
+  if (type == SILC_SERVER_BACKUP_REPLACED &&
+      server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      SILC_PRIMARY_ROUTE(server) == sock) {
+    /* We have been replaced by an backup router in our cell. We must
+       mark our primary router connection disabled since we are not allowed
+       to use it at this moment. */
+    SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
+                  "wait until backup resuming protocol is executed"));
+    idata->status |= SILC_IDLIST_STATUS_DISABLED;
+    return;
+  }
+
+
+  /* Activate the shared protocol context for this socket connection
+     if necessary */
+  if (type == SILC_SERVER_BACKUP_RESUMED &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
+      idata->status & SILC_IDLIST_STATUS_DISABLED) {
+    SilcServerEntry backup_router;
+
+    if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->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;
+      }
+    }
+  }
+
+
+  /* Call the resuming protocol if the protocol is active. */
+  if (SILC_SERVER_IS_BACKUP(sock)) {
+    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;
+      }
+    }
+
+    /* If RESUMED received the session ID is zero, execute the protocol. */
+    if (type == SILC_SERVER_BACKUP_RESUMED) {
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      return;
+    }
+
+    SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
+    return;
   }
 }
 
@@ -582,7 +749,7 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
   if (sock < 0) {
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_backup_connect_to_router,
-                          context, 5, 0, SILC_TASK_TIMEOUT,
+                          context, 10, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_NORMAL);
     return;
   }
@@ -693,7 +860,7 @@ static void silc_server_backup_connect_primary(SilcServer server,
   SilcServerBackupProtocolContext ctx;
   SilcSocketConnection sock;
   SilcIDListData idata;
-  SilcBuffer buffer;
+  unsigned char data[2];
 
   if (!server_entry) {
     /* Try again */
@@ -707,6 +874,11 @@ static void silc_server_backup_connect_primary(SilcServer server,
     return;
   }
 
+  if (!backup_router->protocol)
+    return;
+  if (!server_entry->connection)
+    return;
+
   ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
   sock = (SilcSocketConnection)server_entry->connection;
   idata = (SilcIDListData)server_entry;
@@ -716,16 +888,10 @@ static void silc_server_backup_connect_primary(SilcServer server,
                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));
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
-                    SILC_STR_UI_CHAR(ctx->session),
-                    SILC_STR_END);
+  data[0] = SILC_SERVER_BACKUP_CONNECTED;
+  data[1] = ctx->session;
   silc_server_packet_send(server, backup_router,
-                         SILC_PACKET_RESUME_ROUTER, 0,
-                         buffer->data, buffer->len, FALSE);
-  silc_buffer_free(buffer);
+                         SILC_PACKET_RESUME_ROUTER, 0, data, 2, FALSE);
 
   /* The primary connection is disabled until it sends the RESUMED packet
      to us. */
@@ -740,31 +906,32 @@ static void silc_server_backup_connect_primary(SilcServer server,
   backup_router->protocol = NULL;
 }
 
+/* Timeout callback used by the backup router to send the ENDING packet
+   to primary router to indicate that it can now resume as being primary
+   router. All CONNECTED packets has been received when we reach this. */
+
 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
 {
   SilcProtocol protocol = (SilcProtocol)context;
   SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = ctx->server;
-  SilcBuffer packet;
+  unsigned char data[2];
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
   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);
+  data[0] = SILC_SERVER_BACKUP_ENDING;
+  data[1] = ctx->session;
+  silc_server_packet_send(server, ctx->sock, SILC_PACKET_RESUME_ROUTER, 0,
+                         data, sizeof(data), FALSE);
 
+  /* The protocol will go to END state. */
   protocol->state = SILC_PROTOCOL_STATE_END;
 }
 
@@ -776,10 +943,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   SilcProtocol protocol = (SilcProtocol)context;
   SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = ctx->server;
-  SilcBuffer packet;
-  SilcIDCacheList list;
-  SilcIDCacheEntry id_cache;
   SilcServerEntry server_entry;
+  SilcSocketConnection sock;
+  unsigned char data[2];
   int i;
 
   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
@@ -788,109 +954,49 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     if (ctx->responder == FALSE) {
-      /* Initiator of the protocol. We are backup router */
-
-      packet = silc_buffer_alloc(2);
-      silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-
-      /* 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_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(("Sending START to %s (session %d)",
-                           server_entry->server_name, ctx->sessions_count));
-           SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
-                           server_entry->server_name, 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);
+      /*
+       * Initiator (backup router)
+       */
+
+      /* Send the START packet to primary router and normal servers. The
+        packet will indicate to the primary router that it has been replaced
+        by us.  For normal servers it means that we will be resigning as
+        being primary router shortly. */
+      for (i = 0; i < server->config->param.connections_max; i++) {
+       sock = server->sockets[i];
+       if (!sock || !sock->user_data ||
+           sock->user_data == server->id_entry ||
+           (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+            sock->type != SILC_SOCKET_TYPE_SERVER))
+         continue;
+
+       server_entry = sock->user_data;
+       if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+         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(("Sending START to %s (session %d)",
+                       server_entry->server_name, ctx->sessions_count));
+       SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
+                      server_entry->server_name, ctx->sessions_count));
+
+       /* This connection is performing this protocol too now */
+       sock->protocol = protocol;
+
+       data[0] = SILC_SERVER_BACKUP_START;
+       data[1] = ctx->sessions_count;
+       silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
+                               data, sizeof(data), FALSE);
+       ctx->sessions_count++;
       }
 
-      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(("Sending START to %s (session %d)",
-                           server_entry->server_name, ctx->sessions_count));
-           SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
-                           server_entry->server_name, 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);
-
-      /* If we are not standalone and our primary is not the one we've
+      /* If we are not standalone and our primary is not the one we're
         talking to now, then announce our information to it since we
         haven't done that yet.  Standalone backup router announces
         these during connecting to the primary. */
@@ -901,13 +1007,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       }
 
       protocol->state++;
+
     } else {
-      /* Responder of the protocol. */
+      /*
+       * Responder (all servers and routers)
+       */
       SilcServerConfigRouter *primary;
 
-      /* We should have received START or START_GLOBAL packet */
-      if (ctx->type != SILC_SERVER_BACKUP_START &&
-         ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
+      /* We should have received START packet */
+      if (ctx->type != SILC_SERVER_BACKUP_START) {
        SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
        break;
       }
@@ -938,36 +1046,35 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                      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);
+       data[0] = SILC_SERVER_BACKUP_CONNECTED;
+       data[1] = ctx->session;
        silc_server_packet_send(server, ctx->sock,
                                SILC_PACKET_RESUME_ROUTER, 0,
-                               packet->data, packet->len, FALSE);
-       silc_buffer_free(packet);
+                               data, sizeof(data), FALSE);
       }
 
+      /* Add this resuming session */
+      ctx->sessions = silc_realloc(ctx->sessions,
+                                  sizeof(*ctx->sessions) *
+                                  (ctx->sessions_count + 1));
+      ctx->sessions[ctx->sessions_count].session = ctx->session;
+      ctx->sessions_count++;
+
+      /* Normal server goes directly to the END 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));
-      ctx->sessions[ctx->sessions_count].session = ctx->session;
-      ctx->sessions_count++;
     }
     break;
 
   case 2:
     if (ctx->responder == FALSE) {
-      /* Initiator */
+      /*
+       * Initiator (backup router)
+       */
 
       /* We should have received CONNECTED packet */
       if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
@@ -986,6 +1093,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        }
       }
 
+      /* See if all returned CONNECTED, if not, then continue waiting. */
       for (i = 0; i < ctx->sessions_count; i++) {
        if (!ctx->sessions[i].connected)
          return;
@@ -995,14 +1103,18 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                     "continuing"));
       SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
 
-      /* Send with a timeout */
+      /* The ENDING is sent with timeout, and then we continue to the
+        END state in the protocol. */
       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 */
+      /*
+       * Responder (primary router)
+       */
 
       /* We should have been received ENDING packet */
       if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
@@ -1012,19 +1124,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
       SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
 
-      /* 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 &&
-         !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
-         silc_server_config_is_primary_route(server)) {
-       /* 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_local_servers_toggle_enabled(server, TRUE);
@@ -1032,94 +1131,34 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                                           server->router);
       silc_server_update_clients_by_server(server, ctx->sock->user_data,
                                           server->router, TRUE);
-      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));
-
-      /* We are the primary router, start sending RESUMED packets. */
-      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_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(("Sending RESUMED to %s",
-                           server_entry->server_name));
-           SILC_LOG_INFO(("Sending RESUMED to %s",
-                          server_entry->server_name));
-
-           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(("Sending RESUMED to %s",
-                           server_entry->server_name));
-           SILC_LOG_INFO(("Sending RESUMED to %s",
-                          server_entry->server_name));
-
-           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);
+      /* We as primary router now must send RESUMED packets to all servers
+        and routers so that they know we are back. */
+      for (i = 0; i < server->config->param.connections_max; i++) {
+       sock = server->sockets[i];
+       if (!sock || !sock->user_data ||
+           sock->user_data == server->id_entry ||
+           (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+            sock->type != SILC_SOCKET_TYPE_SERVER))
+         continue;
+
+       server_entry = sock->user_data;
+       server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+       SILC_LOG_DEBUG(("Sending RESUMED to %s", server_entry->server_name));
+       SILC_LOG_INFO(("Sending RESUMED to %s", server_entry->server_name));
+
+       /* This connection is performing this protocol too now */
+       sock->protocol = protocol;
+
+       data[0] = SILC_SERVER_BACKUP_RESUMED;
+       data[1] = 0;
+       silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
+                               data, sizeof(data), FALSE);
+       silc_server_packet_queue_purge(server,sock);
       }
 
-      silc_buffer_free(packet);
-
+      /* We are now resumed and are back as primary router in the cell. */
       SILC_LOG_INFO(("We are now the primary router of our cell again"));
       server->wait_backup = FALSE;
 
@@ -1133,23 +1172,26 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
   case SILC_PROTOCOL_STATE_END:
     {
+      /*
+       * Responder (backup router, servers, and remote router)
+       */
       SilcServerEntry router, backup_router;
 
-      /* We should have been received RESUMED packet from our primary
-        router. */
-      if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
-         ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
+      /* We should have been received RESUMED from our primary router. */
+      if (ctx->type != SILC_SERVER_BACKUP_RESUMED) {
        SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
        break;
       }
 
       SILC_LOG_INFO(("Received RESUMED from new primary router"));
 
+      /* If we are the backup router, mark that we are no longer primary
+        but are back to backup router status. */
       if (server->backup_router)
        server->server_type = SILC_BACKUP_ROUTER;
 
       /* We have now new primary router. All traffic goes there from now on. */
-      router = (SilcServerEntry)ctx->sock->user_data;
+      router = ctx->sock->user_data;
       if (silc_server_backup_replaced_get(server, router->id,
                                          &backup_router)) {
 
@@ -1165,6 +1207,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                         router->server_name));
        }
        server->backup_primary = FALSE;
+       sock = router->connection;
 
        /* Update the client entries of the backup router to the new
           router */
@@ -1178,14 +1221,11 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
        /* Announce all of our information to the router. */
        if (server->server_type == SILC_ROUTER)
-         silc_server_announce_servers(server, FALSE, ctx->start,
-                                      router->connection);
+         silc_server_announce_servers(server, FALSE, ctx->start, sock);
 
        /* Announce our clients and channels to the router */
-       silc_server_announce_clients(server, ctx->start,
-                                    router->connection);
-       silc_server_announce_channels(server, ctx->start,
-                                     router->connection);
+       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 */
@@ -1225,6 +1265,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   }
 }
 
+/* Final resuming protocol completion callback */
+
 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
 {
   SilcProtocol protocol = (SilcProtocol)context;
@@ -1232,98 +1274,73 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
   SilcServer server = ctx->server;
   SilcServerEntry server_entry;
   SilcSocketConnection sock;
-  SilcIDCacheList list;
-  SilcIDCacheEntry id_cache;
+  bool error;
+  int i;
 
   silc_schedule_task_del_by_context(server->schedule, protocol);
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+  error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+          protocol->state == SILC_PROTOCOL_STATE_FAILURE);
+
+  if (error)
     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
-  }
 
   if (server->server_shutdown)
     return;
 
   /* 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;
-
-         /* Backup closes connection and reconnects if error occurred */
-         if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
-           if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-               protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-             server->backup_noswitch = TRUE;
-             server->server_type = SILC_BACKUP_ROUTER;
-             if (ctx->sock == sock)
-               ctx->sock = NULL;
-
-             silc_server_disconnect_remote(server, sock, 0, NULL);
-             silc_server_create_connections(server);
-
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             continue;
-           }
-         }
-
-         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);
-  }
+  for (i = 0; i < server->config->param.connections_max; i++) {
+    sock = server->sockets[i];
+    if (!sock || !sock->user_data ||
+       (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+        sock->type != SILC_SOCKET_TYPE_SERVER))
+      continue;
 
-  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;
-
-         /* Backup closes connection and reconnects if error occurred */
-         if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
-           if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-               protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-             server->backup_noswitch = TRUE;
-             server->server_type = SILC_BACKUP_ROUTER;
-             if (ctx->sock == sock)
-               ctx->sock = NULL;
-
-             silc_server_disconnect_remote(server, sock, 0, NULL);
-             silc_server_create_connections(server);
-
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             continue;
-           }
-         }
-
-         if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
-           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+    server_entry = sock->user_data;
+
+    /* The SilcProtocol context was shared between all connections, clear
+       it from all connections. */
+    if (sock->protocol == protocol) {
+      sock->protocol = NULL;
+
+      if (error) {
+       /* If we are normal server close router connections and reconnect. */
+       if (server->server_type == SILC_SERVER &&
+           (server_entry->server_type == SILC_BACKUP_ROUTER ||
+            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;
+
+         silc_server_create_connections(server);
+         continue;
        }
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+       /* If error occurred and we are backup router, we close connections. */
+       if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
+         server->backup_noswitch = TRUE;
+         server->server_type = SILC_BACKUP_ROUTER;
+         if (ctx->sock == sock)
+           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;
+
+         silc_server_create_connections(server);
+         continue;
+       }
       }
+
+      server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
     }
-    silc_idcache_list_free(list);
   }
 
-  if (protocol->state != SILC_PROTOCOL_STATE_ERROR &&
-      protocol->state != SILC_PROTOCOL_STATE_FAILURE)
+  if (!error)
     SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
 
   if (ctx->sock && ctx->sock->protocol)
index 2ca105b3a9ce47b4dd1429dadd709148bef2aa13..e6ea92259bbe7328aa45f2cc796a2c9ea3512182 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_backup.h 
+  server_backup.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 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
 #define SERVER_BACKUP_H
 
 /* 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
+#define SILC_SERVER_BACKUP_START          1   /* Start protocol */
+#define SILC_SERVER_BACKUP_CONNECTED      2   /* Connected to primary */
+#define SILC_SERVER_BACKUP_ENDING         3   /* Giving up as primary */
+#define SILC_SERVER_BACKUP_RESUMED        4   /* Primary is back online */
+#define SILC_SERVER_BACKUP_REPLACED       20  /* Primary has been replaced */
+#define SILC_SERVER_BACKUP_START_USE      21  /* Start use backup as primary */
 
 /* Adds the `backup_server' to be one of our backup router. This can be
    called multiple times to set multiple backup routers. The `replacing' is
@@ -37,9 +36,9 @@
 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
                            const char *ip, int port, bool local);
 
-/* Returns backup router for IP and port in `replacing' or NULL if there
+/* Returns backup router for IP and port in `server_id' 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);
 
 /* Deletes the backup server `server_entry'. */
@@ -54,7 +53,7 @@ void silc_server_backup_free(SilcServer server);
    by backup router indicated by the `server'. If the router connects at
    a later time we can check whether it has been replaced by an backup
    router. */
-void silc_server_backup_replaced_add(SilcServer server, 
+void silc_server_backup_replaced_add(SilcServer server,
                                     SilcServerID *server_id,
                                     SilcServerEntry server_entry);
 
@@ -70,11 +69,11 @@ bool silc_server_backup_replaced_get(SilcServer server,
 void silc_server_backup_replaced_del(SilcServer server,
                                     SilcServerEntry server_entry);
 
-/* Broadcast the received packet indicated by `packet' to all of our backup 
-   routers. All router wide information is passed using broadcast packets. 
+/* Broadcast the received packet indicated by `packet' to all of our backup
+   routers. All router wide information is passed using broadcast packets.
    That is why all backup routers need to get this data too. It is expected
    that the caller already knows that the `packet' is broadcast packet. */
-void silc_server_backup_broadcast(SilcServer server, 
+void silc_server_backup_broadcast(SilcServer server,
                                  SilcSocketConnection sender,
                                  SilcPacketContext *packet);
 
@@ -111,11 +110,24 @@ void silc_server_backup_send_dest(SilcServer server,
                                  bool force_send,
                                  bool local);
 
+/* Send the START_USE indication to remote connection.  If `failure' is
+   TRUE then this sends SILC_PACKET_FAILURE.  Otherwise it sends
+   SILC_PACKET_RESUME_ROUTER. */
+void silc_server_backup_send_start_use(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      bool failure);
+
+/* Send the REPLACED indication to remote router.  This is send by the
+   primary router (remote router) of the primary router that came back
+   online.  This is not sent by backup router or any other server. */
+void silc_server_backup_send_replaced(SilcServer server,
+                                     SilcSocketConnection sock);
+
 /* Processes incoming RESUME_ROUTER packet. This can give the packet
    for processing to the protocol handler or allocate new protocol if
    start command is received. */
-void silc_server_backup_resume_router(SilcServer server, 
-                                     SilcSocketConnection sock, 
+void silc_server_backup_resume_router(SilcServer server,
+                                     SilcSocketConnection sock,
                                      SilcPacketContext *packet);
 
 /* Constantly tries to reconnect to a primary router indicated by the
index c3379b4e4ff16d05dd6c81b29e6cda8b9661baa3..bd601f9e1de758c2bbf5913e4af3918993fe4a06 100644 (file)
@@ -87,6 +87,8 @@ struct SilcServerStruct {
                                        router to a backup router. */
   unsigned int backup_noswitch: 1;   /* Set if we've won't switch to
                                        become primary (we are backup) */
+  unsigned int backup_closed  : 1;   /* Set if backup closed connection.
+                                       Do not allow resuming in this case. */
   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 */