Fixed backup router shutdown crash
[silc.git] / apps / silcd / server_backup.c
index db4725eeb3cb96979bba99454cfe733e9c8d9c8f..3bde1802a3f00cb405bba34c5fa26c89f50b42f4 100644 (file)
@@ -108,7 +108,8 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
   }
 
   SILC_LOG_DEBUG(("Backup router %s will replace %s",
-                 backup_server->data.sconn->remote_host, 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) {
@@ -551,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_packet_stream_unref(pc->sock);
-  silc_packet_free(pc->packet);
   silc_free(pc);
 }
 
@@ -711,8 +712,17 @@ void silc_server_backup_resume_router(SilcServer server,
   if (type == SILC_SERVER_BACKUP_RESUMED &&
       idata->conn_type == SILC_CONN_ROUTER && !router->backup &&
       idata->status & SILC_IDLIST_STATUS_DISABLED) {
-    if (silc_server_backup_replaced_get(server, router->id, NULL))
+    SilcServerEntry backup_router;
+
+    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. */
@@ -776,6 +786,9 @@ 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,
@@ -802,7 +815,7 @@ void silc_server_backup_connected(SilcServer server,
     /* Try again */
     silc_schedule_task_add_timeout(server->schedule,
                                   silc_server_backup_connected_again,
-                                  context, 0, 1);
+                                  context, 5, 0);
     return;
   }
 
@@ -861,13 +874,10 @@ static void silc_server_backup_connect_primary(SilcServer server,
     return;
   }
 
-  /* Unref */
-  silc_packet_stream_unref(backup_router);
-
-  if (!router->backup)
-    return;
-  if (!server_entry->connection)
+  if (!router->backup || !server_entry->connection) {
+    silc_packet_stream_unref(backup_router);
     return;
+  }
 
   ctx = router->backup_proto;
   sock = server_entry->connection;
@@ -891,10 +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. */
+  if (ctx->sock)
+    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
@@ -1146,7 +1163,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup)
        if (sock == ctx->sock)
          continue;
 
-      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));
@@ -1161,14 +1178,27 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup)
        silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
                                data, sizeof(data));
       }
-      silc_packet_engine_free_streams_list(list);
 
       /* 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"));
@@ -1183,7 +1213,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup)
       /* For us this is the end of this protocol. */
       silc_schedule_task_add_timeout(server->schedule,
                                     silc_server_protocol_backup_done,
-                                    ctx->sock, 0, 1);
+                                    ctx, 0, 1);
     }
     break;
 
@@ -1249,7 +1279,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup)
       /* Protocol has ended, call the final callback */
       silc_schedule_task_add_timeout(server->schedule,
                                     silc_server_protocol_backup_done,
-                                    ctx->sock, 0, 1);
+                                    ctx, 0, 1);
     }
     break;
 
@@ -1257,7 +1287,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup)
     /* Protocol has ended, call the final callback */
     silc_schedule_task_add_timeout(server->schedule,
                                   silc_server_protocol_backup_done,
-                                  ctx->sock, 0, 1);
+                                  ctx, 0, 1);
     break;
 
   case 252:
@@ -1266,7 +1296,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup)
     ctx->received_failure = TRUE;
     silc_schedule_task_add_timeout(server->schedule,
                                   silc_server_protocol_backup_done,
-                                  ctx->sock, 0, 1);
+                                  ctx, 0, 1);
     break;
 
   default:
@@ -1284,7 +1314,6 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
   SilcServerEntry server_entry;
   SilcPacketStream sock;
   SilcBool error;
-  int i;
 
   silc_schedule_task_del_by_context(server->schedule, ctx);
 
@@ -1341,6 +1370,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
            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_timeout(server->schedule,
@@ -1364,6 +1394,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
            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);
@@ -1392,6 +1423,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
       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);
@@ -1409,14 +1441,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
                                          FALSE);
 
        /* Check couple of times same START_USE just in case. */
+       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,
@@ -1425,8 +1460,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
     }
   }
 
-  if (ctx->sock)
+  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);
 }