+ silc_schedule_task_del_by_context(server->schedule, ctx);
+
+ error = ctx->error;
+
+ 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 */
+ 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)
+ continue;
+
+ 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 &&
+ server_entry->server_type == SILC_ROUTER)
+ continue;
+
+ /* Backup router */
+ if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
+ if (ctx->sock == sock) {
+ 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;
+
+ /* Restart the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = server;
+ 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_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
+ to perfom resuming protocol. */
+ server->server_type = SILC_BACKUP_ROUTER;
+ 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,
+ silc_packet_get_context(sock));
+ silc_server_update_clients_by_server(server, NULL,
+ 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;
+ }
+ }
+
+ 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"));
+
+ if (ctx->type == SILC_SERVER_BACKUP_RESUMED && server->router) {
+ /* Announce all of our information to the router. */
+ if (server->server_type == SILC_ROUTER)
+ silc_server_announce_servers(server, FALSE, 0,
+ server->router->connection);
+
+ /* Announce our clients and channels to the router */
+ silc_server_announce_clients(server, 0, server->router->connection);
+ silc_server_announce_channels(server, 0, server->router->connection);
+
+ /* 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 */
+
+ if (server->server_type == SILC_SERVER) {
+ /* If we are still using backup router Send confirmation to backup
+ that using it is still ok and continue sending traffic there.
+ The backup will reply with error if it's not ok. */
+ if (server->router && server->backup_primary) {
+ /* Send START_USE just in case using backup wouldn't be ok. */
+ silc_server_backup_send_start_use(server, server->router->connection,
+ 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,
+ 60, 1);
+ }
+ }
+ }
+
+ 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);