+
+ /* 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;
+ }
+
+ /* Backup router following. */
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+
+ /* 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_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);
+ server->backup_closed = FALSE;
+ return;
+ }
+
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = server;
+ proto_ctx->sock = silc_socket_dup(sock);
+ proto_ctx->responder = TRUE;
+ proto_ctx->type = type;
+ proto_ctx->session = session;
+ proto_ctx->start = time(0);
+
+ 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);
+ 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) {