Fixed backup router shutdown crash
[silc.git] / apps / silcd / server_backup.c
index dce3c9be2d41ff4300f769d0920ab902bf3758dd..3bde1802a3f00cb405bba34c5fa26c89f50b42f4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2003 Pekka Riikonen
+  Copyright (C) 2001 - 2007 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
@@ -22,6 +22,8 @@
 #include "server_internal.h"
 
 SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
+SILC_TASK_CALLBACK(silc_server_backup_announce_watches);
+
 static void silc_server_backup_connect_primary(SilcServer server,
                                               SilcServerEntry server_entry,
                                               void *context);
@@ -34,7 +36,7 @@ typedef struct {
   SilcServerEntry server;
   SilcIDIP ip;
   SilcUInt16 port;
-  bool local;
+  SilcBool local;
 } SilcServerBackupEntry;
 
 /* Holds IP address and port of the primary router that was replaced
@@ -55,22 +57,25 @@ struct SilcServerBackupStruct {
 
 typedef struct {
   SilcUInt8 session;
-  bool connected;
+  SilcBool connected;
   SilcServerEntry server_entry;
 } SilcServerBackupProtocolSession;
 
 /* Backup resuming protocol context  */
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   SilcUInt8 type;
   SilcUInt8 session;
   SilcServerBackupProtocolSession *sessions;
   SilcUInt32 sessions_count;
+  SilcUInt32 initiator_restart;
   long start;
+  int state;
   unsigned int responder        : 1;
   unsigned int received_failure : 1;
   unsigned int timeout          : 1;
+  unsigned int error            : 1;
 } *SilcServerBackupProtocolContext;
 
 
@@ -83,7 +88,7 @@ typedef struct {
    in the local cell, if FALSE it is in some other cell. */
 
 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
-                           const char *ip, int port, bool local)
+                           const char *ip, int port, SilcBool local)
 {
   int i;
 
@@ -103,8 +108,8 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
   }
 
   SILC_LOG_DEBUG(("Backup router %s will replace %s",
-                 ((SilcSocketConnection)backup_server->connection)->ip,
-                 ip, port));
+                 backup_server->data.sconn ?
+                 backup_server->data.sconn->remote_host : "(me)", ip));
 
   for (i = 0; i < server->backup->servers_count; i++) {
     if (!server->backup->servers[i].server) {
@@ -249,9 +254,9 @@ void silc_server_backup_replaced_add(SilcServer server,
    and the bacup router entry to the `server' pointer if non-NULL. Returns
    FALSE if the router is not replaced by backup router. */
 
-bool silc_server_backup_replaced_get(SilcServer server,
-                                    SilcServerID *server_id,
-                                    SilcServerEntry *server_entry)
+SilcBool silc_server_backup_replaced_get(SilcServer server,
+                                        SilcServerID *server_id,
+                                        SilcServerEntry *server_entry)
 {
   int i;
 
@@ -293,7 +298,6 @@ void silc_server_backup_replaced_del(SilcServer server,
     if (server->backup->replaced[i]->server == server_entry) {
       silc_free(server->backup->replaced[i]);
       server->backup->replaced[i] = NULL;
-      return;
     }
   }
 }
@@ -304,14 +308,11 @@ void silc_server_backup_replaced_del(SilcServer server,
    that the caller already knows that the `packet' is broadcast packet. */
 
 void silc_server_backup_broadcast(SilcServer server,
-                                 SilcSocketConnection sender,
-                                 SilcPacketContext *packet)
+                                 SilcPacketStream sender,
+                                 SilcPacket packet)
 {
   SilcServerEntry backup;
-  SilcSocketConnection sock;
-  SilcBuffer buffer;
-  const SilcBufferStruct p;
-  SilcIDListData idata;
+  SilcPacketStream sock;
   int i;
 
   if (!server->backup || server->server_type != SILC_ROUTER)
@@ -319,9 +320,6 @@ void silc_server_backup_broadcast(SilcServer server,
 
   SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
 
-  buffer = packet->buffer;
-  silc_buffer_push(buffer, buffer->data - buffer->head);
-
   for (i = 0; i < server->backup->servers_count; i++) {
     backup = server->backup->servers[i].server;
 
@@ -331,28 +329,8 @@ void silc_server_backup_broadcast(SilcServer server,
     if (server->backup->servers[i].server == server->id_entry)
       continue;
 
-    idata = (SilcIDListData)backup;
     sock = backup->connection;
-
-    if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
-                                 (const SilcBuffer)&p)) {
-      SILC_LOG_ERROR(("Cannot send packet"));
-      return;
-    }
-    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
-                       (SilcBuffer)&p, p.len);
-
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
-
-    /* Now actually send the packet */
-    silc_server_packet_send_real(server, sock, FALSE);
-
-    /* Check for mandatory rekey */
-    if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
-      silc_schedule_task_add(server->schedule, sender->sock,
-                            silc_server_rekey_callback, sender, 0, 1,
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_server_packet_route(server, sock, packet);
   }
 }
 
@@ -372,11 +350,11 @@ void silc_server_backup_send(SilcServer server,
                             SilcPacketFlags flags,
                             unsigned char *data,
                             SilcUInt32 data_len,
-                            bool force_send,
-                            bool local)
+                            SilcBool force_send,
+                            SilcBool local)
 {
   SilcServerEntry backup;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   int i;
 
   if (!server->backup || server->server_type != SILC_ROUTER)
@@ -393,11 +371,8 @@ void silc_server_backup_send(SilcServer server,
 
     sock = backup->connection;
 
-    SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
-                   silc_get_packet_name(type), sock->hostname, sock->ip));
-
     silc_server_packet_send(server, backup->connection, type, flags,
-                           data, data_len, force_send);
+                           data, data_len);
   }
 }
 
@@ -414,11 +389,11 @@ void silc_server_backup_send_dest(SilcServer server,
                                  SilcIdType dst_id_type,
                                  unsigned char *data,
                                  SilcUInt32 data_len,
-                                 bool force_send,
-                                 bool local)
+                                 SilcBool force_send,
+                                 SilcBool local)
 {
   SilcServerEntry backup;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   int i;
 
   if (!server->backup || server->server_type != SILC_ROUTER)
@@ -435,12 +410,8 @@ void silc_server_backup_send_dest(SilcServer server,
 
     sock = backup->connection;
 
-    SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
-                   silc_get_packet_name(type), sock->hostname, sock->ip));
-
     silc_server_packet_send_dest(server, backup->connection, type, flags,
-                                dst_id, dst_id_type, data, data_len,
-                                force_send);
+                                dst_id, dst_id_type, data, data_len);
   }
 }
 
@@ -449,24 +420,24 @@ void silc_server_backup_send_dest(SilcServer server,
    SILC_PACKET_RESUME_ROUTER. */
 
 void silc_server_backup_send_start_use(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      bool failure)
+                                      SilcPacketStream sock,
+                                      SilcBool failure)
 {
   unsigned char data[4];
 
-  SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
-                 failure ? "failure" : "success", sock->ip));
+  SILC_LOG_DEBUG(("Sending START_USE (%s)",
+                 failure ? "failure" : "success"));
 
   if (failure) {
     SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
     silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
-                           data, 4, FALSE);
+                           data, 4);
   } 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);
+                           data, 2);
   }
 }
 
@@ -475,17 +446,17 @@ void silc_server_backup_send_start_use(SilcServer server,
    online.  This is not sent by backup router or any other server. */
 
 void silc_server_backup_send_replaced(SilcServer server,
-                                     SilcSocketConnection sock)
+                                     SilcPacketStream sock)
 {
   unsigned char data[4];
 
-  SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
+  SILC_LOG_DEBUG(("Sending REPLACED"));
 
   data[0] = SILC_SERVER_BACKUP_REPLACED;
   data[1] = 0;
   silc_server_packet_send(server, sock,
                          SILC_PACKET_RESUME_ROUTER, 0,
-                         data, 2, FALSE);
+                         data, 2);
 }
 
 
@@ -495,15 +466,15 @@ void silc_server_backup_send_replaced(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_backup_timeout)
 {
-  SilcProtocol protocol = context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = app_context;
 
   SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
   ctx->timeout = TRUE;
-  silc_protocol_cancel(protocol, server->schedule);
-  protocol->state = SILC_PROTOCOL_STATE_ERROR;
-  silc_protocol_execute_final(protocol, server->schedule);
+  ctx->error = TRUE;
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_protocol_backup_done, context,
+                                0, 0);
 }
 
 /* Callback to start the protocol as responder */
@@ -511,28 +482,28 @@ SILC_TASK_CALLBACK(silc_server_backup_timeout)
 SILC_TASK_CALLBACK(silc_server_backup_responder_start)
 {
   SilcServerBackupProtocolContext proto_ctx = context;
-  SilcSocketConnection sock = proto_ctx->sock;
+  SilcPacketStream sock = proto_ctx->sock;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServer server = app_context;
 
   /* If other protocol is executing at the same time, start with timeout. */
-  if (sock->protocol) {
+  if (idata->sconn->op) {
     SILC_LOG_DEBUG(("Other protocol is executing, wait for it to finish"));
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_backup_responder_start,
-                          proto_ctx, 2, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_responder_start,
+                                  proto_ctx, 2, 0);
     return;
   }
 
+  /* Register protocol timeout */
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_backup_timeout,
+                                proto_ctx, 30, 0);
+
   /* Run the backup resuming protocol */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
-                     &sock->protocol, proto_ctx,
-                     silc_server_protocol_backup_done);
-  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_backup_timeout,
-                        sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_protocol_backup,
+                                proto_ctx, 0, 0);
 }
 
 /* Callback to send START_USE to backup to check whether using backup
@@ -540,7 +511,7 @@ SILC_TASK_CALLBACK(silc_server_backup_responder_start)
 
 SILC_TASK_CALLBACK(silc_server_backup_check_status)
 {
-  SilcSocketConnection sock = context;
+  SilcPacketStream sock = context;
   SilcServer server = app_context;
 
   /* Check whether we are still using backup */
@@ -548,13 +519,13 @@ SILC_TASK_CALLBACK(silc_server_backup_check_status)
     return;
 
   silc_server_backup_send_start_use(server, sock, FALSE);
-  silc_socket_free(sock);      /* unref */
+  silc_packet_stream_unref(sock);
 }
 
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
-  SilcPacketContext *packet;
+  SilcPacketStream sock;
+  SilcPacket packet;
 } *SilcServerBackupPing;
 
 /* PING command reply callback */
@@ -566,14 +537,12 @@ void silc_server_backup_ping_reply(void *context, void *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);
+    SilcPacketStream 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_free_sock_user_data(pc->server, primary, NULL);
       silc_server_close_connection(pc->server, primary);
     }
 
@@ -583,10 +552,10 @@ void silc_server_backup_ping_reply(void *context, void *reply)
     /* 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_packet_free(pc->packet);
   }
 
-  silc_socket_free(pc->sock);
-  silc_packet_context_free(pc->packet);
+  silc_packet_stream_unref(pc->sock);
   silc_free(pc);
 }
 
@@ -595,30 +564,31 @@ void silc_server_backup_ping_reply(void *context, void *reply)
    start command is received. */
 
 void silc_server_backup_resume_router(SilcServer server,
-                                     SilcSocketConnection sock,
-                                     SilcPacketContext *packet)
+                                     SilcPacketStream sock,
+                                     SilcPacket packet)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
+  SilcServerEntry router = (SilcServerEntry)idata;
   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) {
+  if (idata->conn_type == SILC_CONN_CLIENT ||
+      idata->conn_type == SILC_CONN_UNKNOWN) {
     SILC_LOG_DEBUG(("Bad packet received"));
+    silc_packet_free(packet);
     return;
   }
 
-  idata = (SilcIDListData)sock->user_data;
-
-  ret = silc_buffer_unformat(packet->buffer,
+  ret = silc_buffer_unformat(&packet->buffer,
                             SILC_STR_UI_CHAR(&type),
                             SILC_STR_UI_CHAR(&session),
                             SILC_STR_END);
   if (ret < 0) {
     SILC_LOG_ERROR(("Malformed resume router packet received"));
+    silc_packet_free(packet);
     return;
   }
 
@@ -633,6 +603,7 @@ void silc_server_backup_resume_router(SilcServer server,
     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"));
+      silc_packet_free(packet);
       return;
     }
 
@@ -641,16 +612,17 @@ void silc_server_backup_resume_router(SilcServer server,
     /* 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_LOG_DEBUG(("Sending success START_USE back"));
       silc_server_backup_send_start_use(server, sock, FALSE);
+      silc_packet_free(packet);
       return;
     }
 
     /* 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_LOG_DEBUG(("We are stanalone, sending success START_USE back"));
       silc_server_backup_send_start_use(server, sock, FALSE);
+      silc_packet_free(packet);
       return;
     }
 
@@ -660,21 +632,21 @@ void silc_server_backup_resume_router(SilcServer server,
     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);
+                            1, idp->data, silc_buffer_len(idp));
     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);
+    pc->sock = sock;
+    pc->packet = packet;
+    silc_packet_stream_ref(sock);
     silc_server_command_pending_timed(server, SILC_COMMAND_PING,
                                      server->cmd_ident,
                                      silc_server_backup_ping_reply, pc, 15);
     return;
   }
 
-
   /* Start the resuming protocol if requested. */
   if (type == SILC_SERVER_BACKUP_START) {
     /* We have received a start for resuming protocol.  We are either
@@ -688,38 +660,42 @@ void silc_server_backup_resume_router(SilcServer server,
       unsigned char data[4];
       SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
                      "primary router"));
+      SILC_LOG_INFO(("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);
+                             data, 4);
       server->backup_closed = FALSE;
+      silc_packet_free(packet);
       return;
     }
 
     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
     proto_ctx->server = server;
-    proto_ctx->sock = silc_socket_dup(sock);
+    proto_ctx->sock = sock;
     proto_ctx->responder = TRUE;
     proto_ctx->type = type;
     proto_ctx->session = session;
     proto_ctx->start = time(0);
+    silc_packet_stream_ref(sock);
+    router->backup = TRUE;
+    router->backup_proto = proto_ctx;
 
     SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
     SILC_LOG_INFO(("Starting backup resuming protocol"));
 
     /* Start protocol immediately */
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_backup_responder_start,
-                          proto_ctx, 0, 1,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_responder_start,
+                                  proto_ctx, 0, 1);
     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 &&
+      idata->conn_type == SILC_CONN_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
@@ -727,118 +703,59 @@ void silc_server_backup_resume_router(SilcServer server,
     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;
+    silc_packet_free(packet);
     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->conn_type == SILC_CONN_ROUTER && !router->backup &&
       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;
-       if (ctx->sock)
-         silc_socket_free(ctx->sock); /* unref */
-       ctx->sock = silc_socket_dup(sock);
-      }
+    if (silc_server_backup_replaced_get(server, router->id, &backup_router)) {
+      ctx = backup_router->backup_proto;
+      if (ctx->sock)
+       silc_packet_stream_unref(ctx->sock);
+      router->backup = TRUE;
+      router->backup_proto = ctx;
+      ctx->sock = sock;
+      silc_packet_stream_ref(sock);
     }
   }
 
-
   /* Call the resuming protocol if the protocol is active. */
-  if (SILC_SERVER_IS_BACKUP(sock)) {
-    ctx = sock->protocol->context;
+  if (router->backup) {
+    ctx = router->backup_proto;
     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);
+       silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_protocol_backup,
+                                      ctx, 0, 1);
+       silc_packet_free(packet);
        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);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_protocol_backup,
+                                    ctx, 0, 1);
+      silc_packet_free(packet);
       return;
     }
 
     SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
-    return;
-  }
-}
-
-/* Timeout task callback to connect to remote router */
-
-SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
-{
-  SilcServer server = app_context;
-  SilcServerConnection sconn = (SilcServerConnection)context;
-  int sock;
-  const char *server_ip;
-
-  SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
-                 sconn->remote_port));
-
-  /* Connect to remote host */
-  server_ip = server->config->server_info->primary == NULL ? NULL :
-    server->config->server_info->primary->server_ip;
-  sock = silc_net_create_connection(server_ip, sconn->remote_port,
-                                   sconn->remote_host);
-  if (sock < 0) {
-    if (server->server_type == SILC_SERVER) {
-      sconn->retry_count++;
-      if (sconn->retry_count > 3) {
-       silc_free(sconn->remote_host);
-       silc_free(sconn);
-       return;
-      }
-    }
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_backup_connect_to_router,
-                          context, 10, 0, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
+    silc_packet_free(packet);
     return;
   }
 
-  /* Continue with key exchange protocol */
-  silc_server_start_key_exchange(server, sconn, sock);
-}
-
-/* Constantly tries to reconnect to a primary router indicated by the
-   `ip' and `port'. The `connected' callback will be called when the
-   connection is created. */
-
-void silc_server_backup_reconnect(SilcServer server,
-                                 const char *ip, SilcUInt16 port,
-                                 SilcServerConnectRouterCallback callback,
-                                 void *context)
-{
-  SilcServerConnection sconn;
-
-  SILC_LOG_INFO(("Attempting to reconnect to primary router"));
-
-  sconn = silc_calloc(1, sizeof(*sconn));
-  sconn->remote_host = strdup(ip);
-  sconn->remote_port = port;
-  sconn->callback = callback;
-  sconn->callback_context = context;
-  sconn->no_reconnect = TRUE;
-  sconn->retry_count = 0;
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_backup_connect_to_router,
-                        sconn, 1, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_packet_free(packet);
 }
 
 /* Task that is called after backup router has connected back to
@@ -849,32 +766,38 @@ SILC_TASK_CALLBACK(silc_server_backup_connected_later)
   SilcServerBackupProtocolContext proto_ctx =
     (SilcServerBackupProtocolContext)context;
   SilcServer server = proto_ctx->server;
-  SilcSocketConnection sock = proto_ctx->sock;
-
-  /* If running other protocol already run this one a bit later. */
-  if (sock->protocol) {
-    SILC_LOG_DEBUG(("Other protocol is running, wait for it to finish"));
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_backup_connected_later,
-                          proto_ctx, 10, 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-    return;
-  }
 
   SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
   SILC_LOG_INFO(("Starting backup resuming protocol"));
 
+  /* Register protocol timeout */
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_backup_timeout,
+                                proto_ctx, 30, 0);
+
   /* Run the backup resuming protocol */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
-                     &sock->protocol, proto_ctx,
-                     silc_server_protocol_backup_done);
-  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_backup_timeout,
-                        sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_protocol_backup,
+                                proto_ctx, 0, 0);
+}
+
+SILC_TASK_CALLBACK(silc_server_backup_connected_again)
+{
+  SilcServer server = app_context;
+  SilcServerConfigRouter *primary;
+
+  if (server->server_shutdown)
+    return;
+
+  primary = silc_server_config_get_primary_router(server);
+  if (primary) {
+    if (!silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+                                        primary->host, primary->port))
+      silc_server_create_connection(server, FALSE, FALSE,
+                                   primary->host, primary->port,
+                                   silc_server_backup_connected,
+                                   context);
+  }
 }
 
 /* Called when we've established connection back to our primary router
@@ -886,37 +809,45 @@ void silc_server_backup_connected(SilcServer server,
                                  void *context)
 {
   SilcServerBackupProtocolContext proto_ctx;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
 
   if (!server_entry) {
     /* Try again */
-    SilcServerConfigRouter *primary;
-    primary = silc_server_config_get_primary_router(server);
-    if (primary) {
-      if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
-                                          primary->host, primary->port))
-       silc_server_backup_reconnect(server,
-                                    primary->host, primary->port,
-                                    silc_server_backup_connected,
-                                    context);
-    }
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_connected_again,
+                                  context, 5, 0);
     return;
   }
 
-  sock = (SilcSocketConnection)server_entry->connection;
+  sock = server_entry->connection;
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = server;
-  proto_ctx->sock = silc_socket_dup(sock);
+  proto_ctx->sock = sock;
   proto_ctx->responder = FALSE;
   proto_ctx->type = SILC_SERVER_BACKUP_START;
   proto_ctx->start = time(0);
+  silc_packet_stream_ref(sock);
 
   /* Start through scheduler */
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_backup_connected_later,
-                        proto_ctx, 0, 1,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_backup_connected_later,
+                                proto_ctx, 0, 1);
+}
+
+SILC_TASK_CALLBACK(silc_server_backup_connect_primary_again)
+{
+  SilcServer server = app_context;
+  SilcServerConfigRouter *primary;
+
+  primary = silc_server_config_get_primary_router(server);
+  if (primary) {
+    if (!silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+                                        primary->host, primary->port))
+      silc_server_create_connection(server, FALSE, FALSE,
+                                   primary->host, primary->port,
+                                   silc_server_backup_connect_primary,
+                                   context);
+  }
 }
 
 /* Called when normal server has connected to its primary router after
@@ -928,42 +859,28 @@ static void silc_server_backup_connect_primary(SilcServer server,
                                               SilcServerEntry server_entry,
                                               void *context)
 {
-  SilcSocketConnection backup_router = (SilcSocketConnection)context;
+  SilcPacketStream backup_router = context;
+  SilcIDListData idata = silc_packet_get_context(backup_router);
+  SilcServerEntry router = (SilcServerEntry)idata;
   SilcServerBackupProtocolContext ctx;
-  SilcSocketConnection sock;
-  SilcIDListData idata;
+  SilcPacketStream sock;
   unsigned char data[2];
 
-  if (SILC_IS_DISCONNECTING(backup_router) ||
-      SILC_IS_DISCONNECTED(backup_router)) {
-    silc_socket_free(backup_router);
-    return;
-  }
-
   if (!server_entry) {
     /* Try again */
-    SilcServerConfigRouter *primary;
-    primary = silc_server_config_get_primary_router(server);
-    if (primary)
-      if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
-                                          primary->host, primary->port))
-       silc_server_backup_reconnect(server,
-                                    primary->host, primary->port,
-                                    silc_server_backup_connect_primary,
-                                    context);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_connect_primary_again,
+                                  context, 0, 0);
     return;
   }
 
-  /* Unref */
-  silc_socket_free(backup_router);
-
-  if (!backup_router->protocol)
-    return;
-  if (!server_entry->connection)
+  if (!router->backup || !server_entry->connection) {
+    silc_packet_stream_unref(backup_router);
     return;
+  }
 
-  ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
-  sock = (SilcSocketConnection)server_entry->connection;
+  ctx = router->backup_proto;
+  sock = server_entry->connection;
   idata = (SilcIDListData)server_entry;
 
   SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
@@ -974,7 +891,7 @@ static void silc_server_backup_connect_primary(SilcServer server,
   data[0] = SILC_SERVER_BACKUP_CONNECTED;
   data[1] = ctx->session;
   silc_server_packet_send(server, backup_router,
-                         SILC_PACKET_RESUME_ROUTER, 0, data, 2, FALSE);
+                         SILC_PACKET_RESUME_ROUTER, 0, data, 2);
 
   /* The primary connection is disabled until it sends the RESUMED packet
      to us. */
@@ -984,11 +901,17 @@ static void silc_server_backup_connect_primary(SilcServer server,
      the primary router connection since it will send the subsequent
      packets in this protocol. We don't talk with backup router
      anymore. */
-  sock->protocol = backup_router->protocol;
   if (ctx->sock)
-    silc_socket_free(ctx->sock); /* unref */
-  ctx->sock = silc_socket_dup(server_entry->connection);
-  backup_router->protocol = NULL;
+    silc_packet_stream_unref(ctx->sock);
+  ctx->sock = sock;
+  silc_packet_stream_ref(sock);
+  server_entry->backup = TRUE;
+  server_entry->backup_proto = ctx;
+  router->backup = FALSE;
+  router->backup_proto = NULL;
+
+  /* Unref */
+  silc_packet_stream_unref(backup_router);
 }
 
 /* Timeout callback used by the backup router to send the ENDING packet
@@ -997,8 +920,7 @@ static void silc_server_backup_connect_primary(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = ctx->server;
   unsigned char data[2];
   int i;
@@ -1006,7 +928,7 @@ SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
   SILC_LOG_DEBUG(("Start"));
 
   for (i = 0; i < ctx->sessions_count; i++)
-    if (ctx->sessions[i].server_entry == ctx->sock->user_data)
+    if (ctx->sessions[i].server_entry == silc_packet_get_context(ctx->sock))
       ctx->session = ctx->sessions[i].session;
 
   /* We've received all the CONNECTED packets and now we'll send the
@@ -1014,30 +936,30 @@ SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
   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);
+                         data, sizeof(data));
 
   /* The protocol will go to END state. */
-  protocol->state = SILC_PROTOCOL_STATE_END;
+  ctx->state = 250;
 }
 
 /* Backup resuming protocol. This protocol is executed when the primary
    router wants to resume its position as being primary router. */
 
-SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
+SILC_TASK_CALLBACK(silc_server_protocol_backup)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = ctx->server;
-  SilcServerEntry server_entry;
-  SilcSocketConnection sock = NULL;
+  SilcServerEntry server_entry = NULL;
+  SilcPacketStream sock = NULL;
   unsigned char data[2];
+  SilcDList list;
   int i;
 
-  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
-    protocol->state = SILC_PROTOCOL_STATE_START;
+  if (!ctx->state)
+    ctx->state = 1;
 
-  switch(protocol->state) {
-  case SILC_PROTOCOL_STATE_START:
+  switch(ctx->state) {
+  case 1:
     if (ctx->responder == FALSE) {
       /*
        * Initiator (backup router)
@@ -1047,15 +969,19 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
         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))
+      list = silc_packet_engine_get_streams(server->packet_engine);
+      if (!list)
+       return;
+
+      silc_dlist_start(list);
+      while ((sock = silc_dlist_get(list))) {
+       server_entry = silc_packet_get_context(sock);
+
+       if (!server_entry || server_entry == server->id_entry ||
+           (server_entry->data.conn_type != SILC_CONN_ROUTER &&
+            server_entry->data.conn_type != SILC_CONN_SERVER))
          continue;
 
-       server_entry = sock->user_data;
        if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
          continue;
 
@@ -1072,21 +998,23 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                       server_entry->server_name, ctx->sessions_count));
 
        /* This connection is performing this protocol too now */
-       sock->protocol = protocol;
+       server_entry->backup = TRUE;
+       server_entry->backup_proto = ctx;
 
        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);
+                               data, sizeof(data));
        ctx->sessions_count++;
       }
+      silc_packet_engine_free_streams_list(list);
 
       /* Announce data to the new primary to be. */
       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++;
+      ctx->state++;
 
     } else {
       /*
@@ -1111,13 +1039,14 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                                             silc_net_is_ip(primary->host) ?
                                             NULL : primary->host,
                                             primary->port,
-                                            SILC_SOCKET_TYPE_ROUTER)) {
+                                            SILC_CONN_ROUTER)) {
        SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
                        ctx->session));
-       silc_server_backup_reconnect(server,
-                                    primary->host, primary->port,
-                                    silc_server_backup_connect_primary,
-                                    silc_socket_dup(ctx->sock));
+       silc_packet_stream_ref(ctx->sock);
+       silc_server_create_connection(server, FALSE, FALSE,
+                                     primary->host, primary->port,
+                                     silc_server_backup_connect_primary,
+                                     ctx->sock);
       } else {
        /* Nowhere to connect just return the CONNECTED packet */
        SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
@@ -1130,7 +1059,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        data[1] = ctx->session;
        silc_server_packet_send(server, ctx->sock,
                                SILC_PACKET_RESUME_ROUTER, 0,
-                               data, sizeof(data), FALSE);
+                               data, sizeof(data));
       }
 
       /* Add this resuming session */
@@ -1144,9 +1073,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       if (server->server_type == SILC_ROUTER &&
          (!server->router ||
           server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
-       protocol->state++;
+       ctx->state++;
       else
-       protocol->state = SILC_PROTOCOL_STATE_END;
+       ctx->state = 250;
     }
     break;
 
@@ -1185,10 +1114,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
       /* 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);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_backup_send_resumed,
+                                    ctx, 1, 0);
       return;
 
     } else {
@@ -1207,64 +1135,89 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       /* Switch announced informations to our primary router of using the
         backup router. */
       silc_server_local_servers_toggle_enabled(server, TRUE);
-      silc_server_update_servers_by_server(server, ctx->sock->user_data,
-                                          server->router);
-      silc_server_update_clients_by_server(server, ctx->sock->user_data,
+      silc_server_update_servers_by_server(server,
+                                          silc_packet_get_context(ctx->sock),
+                                          server->router);
+      silc_server_update_clients_by_server(server,
+                                          silc_packet_get_context(ctx->sock),
                                           server->router, TRUE);
 
       /* We as primary router now must send RESUMED packets to all servers
         and routers so that they know we are back.   For backup router we
         send the packet last so that we give the backup as much time as
         possible to deal with message routing at this critical moment. */
-      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))
+      list = silc_packet_engine_get_streams(server->packet_engine);
+      if (!list)
+       return;
+
+      silc_dlist_start(list);
+      while ((sock = silc_dlist_get(list))) {
+       server_entry = silc_packet_get_context(sock);
+
+       if (!server_entry || server_entry == server->id_entry ||
+           (server_entry->data.conn_type != SILC_CONN_ROUTER &&
+            server_entry->data.conn_type != SILC_CONN_SERVER))
          continue;
 
        /* Send to backup last */
        if (sock == ctx->sock)
          continue;
 
-      send_to_backup:
-       server_entry = sock->user_data;
+       server_entry = silc_packet_get_context(sock);
        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;
+       server_entry->backup = TRUE;
+       server_entry->backup_proto = ctx;
 
        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);
+                               data, sizeof(data));
       }
 
       /* Now send the same packet to backup */
       if (sock != ctx->sock) {
        sleep(1);
        sock = ctx->sock;
-       goto send_to_backup;
+       server_entry = silc_packet_get_context(sock);
+       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 */
+       server_entry->backup = TRUE;
+       server_entry->backup_proto = ctx;
+
+       data[0] = SILC_SERVER_BACKUP_RESUMED;
+       data[1] = 0;
+       silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
+                               data, sizeof(data));
       }
+      silc_packet_engine_free_streams_list(list);
 
       /* 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;
 
+      /* Announce WATCH list a little later */
+      silc_packet_stream_ref(ctx->sock);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_backup_announce_watches,
+                                    ctx->sock, 4, 0);
+
       /* For us this is the end of this protocol. */
-      if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->schedule);
-      else
-       silc_protocol_free(protocol);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_protocol_backup_done,
+                                    ctx, 0, 1);
     }
     break;
 
-  case SILC_PROTOCOL_STATE_END:
+  case 250:
     {
       /*
        * Responder (backup router, servers, and remote router)
@@ -1285,7 +1238,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        server->server_type = SILC_BACKUP_ROUTER;
 
       /* We have now new primary router. All traffic goes there from now on. */
-      router = ctx->sock->user_data;
+      router = silc_packet_get_context(ctx->sock);
       if (silc_server_backup_replaced_get(server, router->id,
                                          &backup_router)) {
 
@@ -1324,32 +1277,29 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                              server->router->server_name));
 
       /* Protocol has ended, call the final callback */
-      if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->schedule);
-      else
-       silc_protocol_free(protocol);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_protocol_backup_done,
+                                    ctx, 0, 1);
     }
     break;
 
-  case SILC_PROTOCOL_STATE_ERROR:
+  case 251:
     /* Protocol has ended, call the final callback */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_protocol_backup_done,
+                                  ctx, 0, 1);
     break;
 
-  case SILC_PROTOCOL_STATE_FAILURE:
+  case 252:
     /* Protocol has ended, call the final callback */
     SILC_LOG_ERROR(("Error during backup resume: received Failure"));
     ctx->received_failure = TRUE;
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_protocol_backup_done,
+                                  ctx, 0, 1);
     break;
 
-  case SILC_PROTOCOL_STATE_UNKNOWN:
+  default:
     break;
   }
 }
@@ -1358,45 +1308,39 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = ctx->server;
+  SilcDList list;
   SilcServerEntry server_entry;
-  SilcSocketConnection sock;
-  bool error;
-  int i;
+  SilcPacketStream sock;
+  SilcBool error;
 
-  silc_schedule_task_del_by_context(server->schedule, protocol);
+  silc_schedule_task_del_by_context(server->schedule, ctx);
 
-  error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-          protocol->state == SILC_PROTOCOL_STATE_FAILURE);
+  error = ctx->error;
 
-  if (error) {
+  if (error)
     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
-    if (server->server_type == SILC_SERVER)
-      silc_schedule_task_del_by_callback(server->schedule,
-                                        silc_server_backup_connect_to_router);
-  }
 
   if (server->server_shutdown)
     return;
 
   /* Remove this protocol from all server entries that has it */
-  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;
+  list = silc_packet_engine_get_streams(server->packet_engine);
+  if (!list)
+    return;
 
-    server_entry = sock->user_data;
+  silc_dlist_start(list);
+  while ((sock = silc_dlist_get(list))) {
+    server_entry = silc_packet_get_context(sock);
+    if (!server_entry)
+      continue;
 
-    /* The SilcProtocol context was shared between all connections, clear
-       it from all connections. */
-    if (sock->protocol == protocol) {
-      silc_server_packet_queue_purge(server, sock);
-      sock->protocol = NULL;
+    if (server_entry->data.conn_type != SILC_CONN_ROUTER &&
+       server_entry->data.conn_type != SILC_CONN_SERVER)
+      continue;
 
+    if (server_entry->backup_proto == ctx) {
       if (error) {
 
        if (server->server_type == SILC_SERVER &&
@@ -1406,10 +1350,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
        /* Backup router */
        if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
          if (ctx->sock == sock) {
-           silc_socket_free(sock); /* unref */
+           silc_packet_stream_unref(sock);
            ctx->sock = NULL;
          }
 
+         /* If failed after 10 attempts, it won't work, give up */
+         if (ctx->initiator_restart > 10)
+           ctx->received_failure = TRUE;
+
          if (!ctx->received_failure) {
            /* Protocol error, probably timeout. Just restart the protocol. */
            SilcServerBackupProtocolContext proto_ctx;
@@ -1417,17 +1365,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
            /* Restart the protocol. */
            proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
            proto_ctx->server = server;
-           proto_ctx->sock = silc_socket_dup(sock);
+           proto_ctx->sock = sock;
            proto_ctx->responder = FALSE;
            proto_ctx->type = SILC_SERVER_BACKUP_START;
            proto_ctx->start = time(0);
+           proto_ctx->initiator_restart = ctx->initiator_restart + 1;
+           silc_packet_stream_ref(sock);
 
            /* Start through scheduler */
-           silc_schedule_task_add(server->schedule, 0,
-                                  silc_server_backup_connected_later,
-                                  proto_ctx, 2, 0,
-                                  SILC_TASK_TIMEOUT,
-                                  SILC_TASK_PRI_NORMAL);
+           silc_schedule_task_add_timeout(server->schedule,
+                                          silc_server_backup_connected_later,
+                                          proto_ctx, 5, 0);
          } else {
            /* If failure was received, switch back to normal backup router.
               For some reason primary wouldn't accept that we were supposed
@@ -1436,13 +1384,20 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
            silc_server_local_servers_toggle_enabled(server, FALSE);
            server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
            silc_server_update_servers_by_server(server, server->id_entry,
-                                                sock->user_data);
+                                                silc_packet_get_context(sock));
            silc_server_update_clients_by_server(server, NULL,
-                                                sock->user_data, TRUE);
+                                                silc_packet_get_context(sock),
+                                                TRUE);
 
            /* Announce our clients and channels to the router */
            silc_server_announce_clients(server, 0, sock);
            silc_server_announce_channels(server, 0, sock);
+
+           /* Announce WATCH list a little later */
+           silc_packet_stream_ref(sock);
+           silc_schedule_task_add_timeout(server->schedule,
+                                          silc_server_backup_announce_watches,
+                                          sock, 5, 0);
          }
 
          continue;
@@ -1452,6 +1407,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
       server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
     }
   }
+  silc_packet_engine_free_streams_list(list);
 
   if (!error) {
     SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
@@ -1465,6 +1421,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
       /* Announce our clients and channels to the router */
       silc_server_announce_clients(server, 0, server->router->connection);
       silc_server_announce_channels(server, 0, server->router->connection);
+
+      /* Announce WATCH list a little later */
+      silc_packet_stream_ref(server->router->connection);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_backup_announce_watches,
+                                    server->router->connection, 4, 0);
     }
   } else {
     /* Error */
@@ -1479,30 +1441,42 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
                                          FALSE);
 
        /* Check couple of times same START_USE just in case. */
-       silc_schedule_task_add(server->schedule, 0,
-                              silc_server_backup_check_status,
-                              silc_socket_dup(server->router->connection),
-                              5, 1, SILC_TASK_TIMEOUT,
-                              SILC_TASK_PRI_NORMAL);
-       silc_schedule_task_add(server->schedule, 0,
-                              silc_server_backup_check_status,
-                              silc_socket_dup(server->router->connection),
-                              20, 1, SILC_TASK_TIMEOUT,
-                              SILC_TASK_PRI_NORMAL);
-       silc_schedule_task_add(server->schedule, 0,
-                              silc_server_backup_check_status,
-                              silc_socket_dup(server->router->connection),
-                              60, 1, SILC_TASK_TIMEOUT,
-                              SILC_TASK_PRI_NORMAL);
+       silc_packet_stream_ref(server->router->connection);
+       silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_backup_check_status,
+                                      server->router->connection,
+                                      5, 1);
+       silc_packet_stream_ref(server->router->connection);
+       silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_backup_check_status,
+                                      server->router->connection,
+                                      20, 1);
+       silc_packet_stream_ref(server->router->connection);
+       silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_backup_check_status,
+                                      server->router->connection,
+                                      60, 1);
       }
     }
   }
 
-  if (ctx->sock && ctx->sock->protocol)
-    ctx->sock->protocol = NULL;
-  if (ctx->sock)
-    silc_socket_free(ctx->sock); /* unref */
-  silc_protocol_free(protocol);
+  if (ctx->sock) {
+    SilcServerEntry r = silc_packet_get_context(ctx->sock);
+    if (r) {
+      r->backup = FALSE;
+      r->backup_proto = NULL;
+    }
+    silc_packet_stream_unref(ctx->sock);
+  }
   silc_free(ctx->sessions);
   silc_free(ctx);
 }
+
+SILC_TASK_CALLBACK(silc_server_backup_announce_watches)
+{
+  SilcPacketStream sock = context;
+  SilcServer server = app_context;
+  if (silc_packet_stream_is_valid(sock))
+    silc_server_announce_watches(server, sock);
+  silc_packet_stream_unref(sock);
+}