+/* Callback to start the protocol as responder */
+
+SILC_TASK_CALLBACK(silc_server_backup_responder_start)
+{
+ SilcServerBackupProtocolContext proto_ctx = context;
+ SilcSocketConnection sock = proto_ctx->sock;
+ SilcServer server = app_context;
+
+ /* If other protocol is executing at the same time, start with timeout. */
+ if (sock->protocol) {
+ 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);
+ return;
+ }
+
+ /* 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);
+}
+
+/* Callback to send START_USE to backup to check whether using backup
+ is ok. */
+
+SILC_TASK_CALLBACK(silc_server_backup_check_status)
+{
+ SilcSocketConnection sock = context;
+ SilcServer server = app_context;
+
+ /* Check whether we are still using backup */
+ if (!server->backup_primary)
+ return;
+
+ silc_server_backup_send_start_use(server, sock, FALSE);
+ silc_socket_free(sock); /* unref */
+}
+
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ SilcPacketContext *packet;
+} *SilcServerBackupPing;
+
+/* PING command reply callback */
+
+void silc_server_backup_ping_reply(void *context, void *reply)
+{
+ SilcServerBackupPing pc = context;
+ SilcServerCommandReplyContext cmdr = 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);
+
+ 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_close_connection(pc->server, primary);
+ }
+
+ /* Reprocess the RESUME_ROUTER packet */
+ silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
+ } else {
+ /* 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_socket_free(pc->sock);
+ silc_packet_context_free(pc->packet);
+ silc_free(pc);
+}
+