+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerBackupProtocolContext ctx = protocol->context;
+ SilcServer server = ctx->server;
+ SilcServerEntry server_entry;
+ SilcSocketConnection sock;
+ bool error;
+ int i;
+
+ silc_schedule_task_del_by_context(server->schedule, protocol);
+
+ 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_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;
+
+ server_entry = sock->user_data;
+
+ /* 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 (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_socket_free(sock); /* unref */
+ ctx->sock = NULL;
+ }
+
+ 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 = silc_socket_dup(sock);
+ proto_ctx->responder = FALSE;
+ proto_ctx->type = SILC_SERVER_BACKUP_START;
+ proto_ctx->start = time(0);
+
+ /* 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);
+ } 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,
+ sock->user_data);
+ silc_server_update_clients_by_server(server, NULL,
+ sock->user_data, TRUE);
+
+ /* Announce our clients and channels to the router */
+ silc_server_announce_clients(server, 0, sock);
+ silc_server_announce_channels(server, 0, sock);
+ }
+
+ continue;
+ }
+ }
+
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+ }
+ }
+
+ 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);
+ }
+ } 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_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);
+ }
+ }
+ }