7bf72544c6c4d1fdbd5d8dc90b37fdbce57fd982
[silc.git] / apps / silcd / server_backup.c
1 /*
2
3   server_backup.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 - 2003 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
24 SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
25 static void silc_server_backup_connect_primary(SilcServer server,
26                                                SilcServerEntry server_entry,
27                                                void *context);
28
29
30 /************************** Types and Definitions ***************************/
31
32 /* Backup router */
33 typedef struct {
34   SilcServerEntry server;
35   SilcIDIP ip;
36   SilcUInt16 port;
37   bool local;
38 } SilcServerBackupEntry;
39
40 /* Holds IP address and port of the primary router that was replaced
41    by backup router. */
42 typedef struct {
43   SilcIDIP ip;
44   SilcUInt16 port;
45   SilcServerEntry server;       /* Backup router that replaced the primary */
46 } SilcServerBackupReplaced;
47
48 /* Backup context */
49 struct SilcServerBackupStruct {
50   SilcServerBackupEntry *servers;
51   SilcUInt32 servers_count;
52   SilcServerBackupReplaced **replaced;
53   SilcUInt32 replaced_count;
54 };
55
56 typedef struct {
57   SilcUInt8 session;
58   bool connected;
59   SilcServerEntry server_entry;
60 } SilcServerBackupProtocolSession;
61
62 /* Backup resuming protocol context  */
63 typedef struct {
64   SilcServer server;
65   SilcSocketConnection sock;
66   bool responder;
67   SilcUInt8 type;
68   SilcUInt8 session;
69   SilcServerBackupProtocolSession *sessions;
70   SilcUInt32 sessions_count;
71   long start;
72 } *SilcServerBackupProtocolContext;
73
74
75 /********************* Backup Configuration Routines ************************/
76
77 /* Adds the `backup_server' to be one of our backup router. This can be
78    called multiple times to set multiple backup routers. The `ip' and `port'
79    is the IP and port that the `backup_router' will replace if the `ip'
80    will become unresponsive. If `local' is TRUE then the `backup_server' is
81    in the local cell, if FALSE it is in some other cell. */
82
83 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
84                             const char *ip, int port, bool local)
85 {
86   int i;
87
88   if (!ip)
89     return;
90
91   if (!server->backup) {
92     server->backup = silc_calloc(1, sizeof(*server->backup));
93     if (!server->backup)
94       return;
95   }
96
97   /* See if already added */
98   for (i = 0; i < server->backup->servers_count; i++) {
99     if (server->backup->servers[i].server == backup_server)
100       return;
101   }
102
103   SILC_LOG_DEBUG(("Backup router %s will replace %s",
104                   ((SilcSocketConnection)backup_server->connection)->ip,
105                   ip, port));
106
107   for (i = 0; i < server->backup->servers_count; i++) {
108     if (!server->backup->servers[i].server) {
109       server->backup->servers[i].server = backup_server;
110       server->backup->servers[i].local = local;
111       server->backup->servers[i].port = SILC_SWAB_16(port);
112       memset(server->backup->servers[i].ip.data, 0,
113              sizeof(server->backup->servers[i].ip.data));
114       silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
115                         sizeof(server->backup->servers[i].ip.data));
116       return;
117     }
118   }
119
120   i = server->backup->servers_count;
121   server->backup->servers = silc_realloc(server->backup->servers,
122                                          sizeof(*server->backup->servers) *
123                                          (i + 1));
124   server->backup->servers[i].server = backup_server;
125   server->backup->servers[i].local = local;
126   server->backup->servers[i].port = SILC_SWAB_16(port);
127   memset(server->backup->servers[i].ip.data, 0,
128          sizeof(server->backup->servers[i].ip.data));
129   silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
130                     sizeof(server->backup->servers[i].ip.data));
131   server->backup->servers_count++;
132 }
133
134 /* Returns backup router for IP and port in `server_id' or NULL if there
135    does not exist backup router. */
136
137 SilcServerEntry silc_server_backup_get(SilcServer server,
138                                        SilcServerID *server_id)
139 {
140   int i;
141
142   if (!server->backup)
143     return NULL;
144
145   for (i = 0; i < server->backup->servers_count; i++) {
146     if (server->backup->servers[i].server &&
147         server->backup->servers[i].port == server_id->port &&
148         !memcmp(server->backup->servers[i].ip.data, server_id->ip.data,
149                 sizeof(server_id->ip.data))) {
150       SILC_LOG_DEBUG(("Found backup router %s for %s",
151                       server->backup->servers[i].server->server_name,
152                       silc_id_render(server_id, SILC_ID_SERVER)));
153       return server->backup->servers[i].server;
154     }
155   }
156
157   return NULL;
158 }
159
160 /* Deletes the backup server `server_entry'. */
161
162 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
163 {
164   int i;
165
166   if (!server->backup)
167     return;
168
169   for (i = 0; i < server->backup->servers_count; i++) {
170     if (server->backup->servers[i].server == server_entry) {
171       SILC_LOG_DEBUG(("Removing %s as backup router",
172                       silc_id_render(server->backup->servers[i].server->id,
173                                      SILC_ID_SERVER)));
174       server->backup->servers[i].server = NULL;
175       memset(server->backup->servers[i].ip.data, 0,
176              sizeof(server->backup->servers[i].ip.data));
177     }
178   }
179 }
180
181 /* Frees all data allocated for backup routers.  Call this after deleting
182    all backup routers and when new routers are added no more, for example
183    when shutting down the server. */
184
185 void silc_server_backup_free(SilcServer server)
186 {
187   int i;
188
189   if (!server->backup)
190     return;
191
192   /* Delete existing servers if caller didn't do it */
193   for (i = 0; i < server->backup->servers_count; i++) {
194     if (server->backup->servers[i].server)
195       silc_server_backup_del(server, server->backup->servers[i].server);
196   }
197
198   silc_free(server->backup->servers);
199   silc_free(server->backup);
200   server->backup = NULL;
201 }
202
203 /* Marks the IP address and port from the `server_id' as  being replaced
204    by backup router indicated by the `server'. If the router connects at
205    a later time we can check whether it has been replaced by an backup
206    router. */
207
208 void silc_server_backup_replaced_add(SilcServer server,
209                                      SilcServerID *server_id,
210                                      SilcServerEntry server_entry)
211 {
212   int i;
213   SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
214
215   if (!server->backup)
216     server->backup = silc_calloc(1, sizeof(*server->backup));
217   if (!server->backup->replaced) {
218     server->backup->replaced =
219       silc_calloc(1, sizeof(*server->backup->replaced));
220     server->backup->replaced_count = 1;
221   }
222
223   SILC_LOG_DEBUG(("Replacing router %s with %s",
224                   silc_id_render(server_id, SILC_ID_SERVER),
225                   server_entry->server_name));
226
227   memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
228   r->server = server_entry;
229
230   for (i = 0; i < server->backup->replaced_count; i++) {
231     if (!server->backup->replaced[i]) {
232       server->backup->replaced[i] = r;
233       return;
234     }
235   }
236
237   i = server->backup->replaced_count;
238   server->backup->replaced = silc_realloc(server->backup->replaced,
239                                           sizeof(*server->backup->replaced) *
240                                           (i + 1));
241   server->backup->replaced[i] = r;
242   server->backup->replaced_count++;
243 }
244
245 /* Checks whether the IP address and port from the `server_id' has been
246    replaced by an backup router. If it has been then this returns TRUE
247    and the bacup router entry to the `server' pointer if non-NULL. Returns
248    FALSE if the router is not replaced by backup router. */
249
250 bool silc_server_backup_replaced_get(SilcServer server,
251                                      SilcServerID *server_id,
252                                      SilcServerEntry *server_entry)
253 {
254   int i;
255
256   if (!server->backup || !server->backup->replaced)
257     return FALSE;
258
259   for (i = 0; i < server->backup->replaced_count; i++) {
260     if (!server->backup->replaced[i])
261       continue;
262     if (!memcmp(server->backup->replaced[i]->ip.data, server_id->ip.data,
263                 sizeof(server_id->ip.data))) {
264       if (server_entry)
265         *server_entry = server->backup->replaced[i]->server;
266       SILC_LOG_DEBUG(("Router %s is replaced by %s",
267                       silc_id_render(server_id, SILC_ID_SERVER),
268                       server->backup->replaced[i]->server->server_name));
269       return TRUE;
270     }
271   }
272
273   SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
274                   silc_id_render(server_id, SILC_ID_SERVER)));
275   return FALSE;
276 }
277
278 /* Deletes a replaced host by the set `server_entry. */
279
280 void silc_server_backup_replaced_del(SilcServer server,
281                                      SilcServerEntry server_entry)
282 {
283   int i;
284
285   if (!server->backup || !server->backup->replaced)
286     return;
287
288   for (i = 0; i < server->backup->replaced_count; i++) {
289     if (!server->backup->replaced[i])
290       continue;
291     if (server->backup->replaced[i]->server == server_entry) {
292       silc_free(server->backup->replaced[i]);
293       server->backup->replaced[i] = NULL;
294       return;
295     }
296   }
297 }
298
299 /* Broadcast the received packet indicated by `packet' to all of our backup
300    routers. All router wide information is passed using broadcast packets.
301    That is why all backup routers need to get this data too. It is expected
302    that the caller already knows that the `packet' is broadcast packet. */
303
304 void silc_server_backup_broadcast(SilcServer server,
305                                   SilcSocketConnection sender,
306                                   SilcPacketContext *packet)
307 {
308   SilcServerEntry backup;
309   SilcSocketConnection sock;
310   SilcBuffer buffer;
311   const SilcBufferStruct p;
312   SilcIDListData idata;
313   int i;
314
315   if (!server->backup || server->server_type != SILC_ROUTER)
316     return;
317
318   SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
319
320   buffer = packet->buffer;
321   silc_buffer_push(buffer, buffer->data - buffer->head);
322
323   for (i = 0; i < server->backup->servers_count; i++) {
324     backup = server->backup->servers[i].server;
325
326     if (!backup || backup->connection == sender ||
327         server->backup->servers[i].local == FALSE)
328       continue;
329     if (server->backup->servers[i].server == server->id_entry)
330       continue;
331
332     idata = (SilcIDListData)backup;
333     sock = backup->connection;
334
335     if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
336                                   (const SilcBuffer)&p)) {
337       SILC_LOG_ERROR(("Cannot send packet"));
338       return;
339     }
340     silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
341     silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
342                         (SilcBuffer)&p, p.len);
343
344     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
345
346     /* Now actually send the packet */
347     silc_server_packet_send_real(server, sock, FALSE);
348
349     /* Check for mandatory rekey */
350     if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
351       silc_schedule_task_add(server->schedule, sender->sock,
352                              silc_server_rekey_callback, sender, 0, 1,
353                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
354   }
355 }
356
357 /* A generic routine to send data to all backup routers. If the `sender'
358    is provided it will indicate the original sender of the packet and the
359    packet won't be resent to that entity. The `data' is the data that will
360    be assembled to packet context before sending. The packet will be
361    encrypted this function. If the `force_send' is TRUE the data is sent
362    immediately and not put to queue. If `local' is TRUE then the packet
363    will be sent only to local backup routers inside the cell. If false the
364    packet can go from one cell to the other. This function has no effect
365    if there are no any backup routers. */
366
367 void silc_server_backup_send(SilcServer server,
368                              SilcServerEntry sender,
369                              SilcPacketType type,
370                              SilcPacketFlags flags,
371                              unsigned char *data,
372                              SilcUInt32 data_len,
373                              bool force_send,
374                              bool local)
375 {
376   SilcServerEntry backup;
377   SilcSocketConnection sock;
378   int i;
379
380   if (!server->backup || server->server_type != SILC_ROUTER)
381     return;
382
383   for (i = 0; i < server->backup->servers_count; i++) {
384     backup = server->backup->servers[i].server;
385     if (!backup || sender == backup)
386       continue;
387     if (local && server->backup->servers[i].local == FALSE)
388       continue;
389     if (server->backup->servers[i].server == server->id_entry)
390       continue;
391
392     sock = backup->connection;
393
394     SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
395                     silc_get_packet_name(type), sock->hostname, sock->ip));
396
397     silc_server_packet_send(server, backup->connection, type, flags,
398                             data, data_len, force_send);
399   }
400 }
401
402 /* Same as silc_server_backup_send but sets a specific Destination ID to
403    the packet. The Destination ID is indicated by the `dst_id' and the
404    ID type `dst_id_type'. For example, packets destined to channels must
405    be sent using this function. */
406
407 void silc_server_backup_send_dest(SilcServer server,
408                                   SilcServerEntry sender,
409                                   SilcPacketType type,
410                                   SilcPacketFlags flags,
411                                   void *dst_id,
412                                   SilcIdType dst_id_type,
413                                   unsigned char *data,
414                                   SilcUInt32 data_len,
415                                   bool force_send,
416                                   bool local)
417 {
418   SilcServerEntry backup;
419   SilcSocketConnection sock;
420   int i;
421
422   if (!server->backup || server->server_type != SILC_ROUTER)
423     return;
424
425   for (i = 0; i < server->backup->servers_count; i++) {
426     backup = server->backup->servers[i].server;
427     if (!backup || sender == backup)
428       continue;
429     if (local && server->backup->servers[i].local == FALSE)
430       continue;
431     if (server->backup->servers[i].server == server->id_entry)
432       continue;
433
434     sock = backup->connection;
435
436     SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
437                     silc_get_packet_name(type), sock->hostname, sock->ip));
438
439     silc_server_packet_send_dest(server, backup->connection, type, flags,
440                                  dst_id, dst_id_type, data, data_len,
441                                  force_send);
442   }
443 }
444
445 /* Send the START_USE indication to remote connection.  If `failure' is
446    TRUE then this sends SILC_PACKET_FAILURE.  Otherwise it sends
447    SILC_PACKET_RESUME_ROUTER. */
448
449 void silc_server_backup_send_start_use(SilcServer server,
450                                        SilcSocketConnection sock,
451                                        bool failure)
452 {
453   unsigned char data[4];
454
455   SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
456                   failure ? "failure" : "success", sock->ip));
457
458   if (failure) {
459     SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
460     silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
461                             data, 4, FALSE);
462   } else {
463     data[0] = SILC_SERVER_BACKUP_START_USE;
464     data[1] = 0;
465     silc_server_packet_send(server, sock,
466                             SILC_PACKET_RESUME_ROUTER, 0,
467                             data, 2, FALSE);
468   }
469 }
470
471 /* Send the REPLACED indication to remote router.  This is send by the
472    primary router (remote router) of the primary router that came back
473    online.  This is not sent by backup router or any other server. */
474
475 void silc_server_backup_send_replaced(SilcServer server,
476                                       SilcSocketConnection sock)
477 {
478   unsigned char data[4];
479
480   SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
481
482   data[0] = SILC_SERVER_BACKUP_REPLACED;
483   data[1] = 0;
484   silc_server_packet_send(server, sock,
485                           SILC_PACKET_RESUME_ROUTER, 0,
486                           data, 2, FALSE);
487 }
488
489
490 /************************ Backup Resuming Protocol **************************/
491
492 /* Timeout callback for protocol */
493
494 SILC_TASK_CALLBACK(silc_server_backup_timeout)
495 {
496   SilcProtocol protocol = context;
497   SilcServer server = app_context;
498
499   SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
500   silc_protocol_cancel(protocol, server->schedule);
501   protocol->state = SILC_PROTOCOL_STATE_ERROR;
502   silc_protocol_execute_final(protocol, server->schedule);
503 }
504
505 /* Callback to start the protocol as responder */
506
507 SILC_TASK_CALLBACK(silc_server_backup_responder_start)
508 {
509   SilcServerBackupProtocolContext proto_ctx = context;
510   SilcSocketConnection sock = proto_ctx->sock;
511   SilcServer server = app_context;
512
513   /* If other protocol is executing at the same time, start with timeout. */
514   if (sock->protocol) {
515     silc_schedule_task_add(server->schedule, sock->sock,
516                            silc_server_backup_responder_start,
517                            proto_ctx, 2, 0,
518                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
519     return;
520   }
521
522   /* Run the backup resuming protocol */
523   silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
524                       &sock->protocol, proto_ctx,
525                       silc_server_protocol_backup_done);
526   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
527   silc_schedule_task_add(server->schedule, sock->sock,
528                          silc_server_backup_timeout,
529                          sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
530                          SILC_TASK_PRI_NORMAL);
531 }
532
533 typedef struct {
534   SilcServer server;
535   SilcSocketConnection sock;
536   SilcPacketContext *packet;
537 } *SilcServerBackupPing;
538
539 /* PING command reply callback */
540
541 void silc_server_backup_ping_reply(void *context, void *reply)
542 {
543   SilcServerBackupPing pc = context;
544   SilcServerCommandReplyContext cmdr = reply;
545
546   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
547     /* Timeout error occurred, the primary is really down. */
548     SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
549
550     SILC_LOG_DEBUG(("PING timeout, primary is down"));
551
552     if (primary) {
553       if (primary->user_data)
554         silc_server_free_sock_user_data(pc->server, primary, NULL);
555       SILC_SET_DISCONNECTING(primary);
556       silc_server_close_connection(pc->server, primary);
557     }
558
559     /* Reprocess the RESUME_ROUTER packet */
560     silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
561   } else {
562     /* The primary is not down, refuse to serve the server as primary */
563     SILC_LOG_DEBUG(("PING received, primary is up"));
564     silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
565   }
566
567   silc_socket_free(pc->sock);
568   silc_packet_context_free(pc->packet);
569   silc_free(pc);
570 }
571
572 /* Processes incoming RESUME_ROUTER packet. This can give the packet
573    for processing to the protocol handler or allocate new protocol if
574    start command is received. */
575
576 void silc_server_backup_resume_router(SilcServer server,
577                                       SilcSocketConnection sock,
578                                       SilcPacketContext *packet)
579 {
580   SilcUInt8 type, session;
581   SilcServerBackupProtocolContext ctx;
582   SilcIDListData idata;
583   int i, ret;
584
585   SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
586
587   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
588       sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
589     SILC_LOG_DEBUG(("Bad packet received"));
590     return;
591   }
592
593   idata = (SilcIDListData)sock->user_data;
594
595   ret = silc_buffer_unformat(packet->buffer,
596                              SILC_STR_UI_CHAR(&type),
597                              SILC_STR_UI_CHAR(&session),
598                              SILC_STR_END);
599   if (ret < 0) {
600     SILC_LOG_ERROR(("Malformed resume router packet received"));
601     return;
602   }
603
604   /* Check whether this packet is used to tell us that server will start
605      using us as primary router. */
606   if (type == SILC_SERVER_BACKUP_START_USE) {
607     SilcBuffer idp;
608     SilcServerBackupPing pc;
609
610     /* If we are normal server then backup router has sent us back
611        this reply and we use the backup as primary router now. */
612     if (server->server_type == SILC_SERVER) {
613       /* Nothing to do here actually, since we have switched already. */
614       SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
615       return;
616     }
617
618     /* Backup router following. */
619
620     /* If we are marked as router then the primary is down and we send
621        success START_USE back to the server. */
622     if (server->server_type == SILC_ROUTER) {
623       SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
624       silc_server_backup_send_start_use(server, sock, FALSE);
625       return;
626     }
627
628     /* We have just lost primary, send success START_USE back */
629     if (server->standalone) {
630       SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
631                       sock->ip));
632       silc_server_backup_send_start_use(server, sock, FALSE);
633       return;
634     }
635
636     /* We are backup router. This server claims that our primary is down.
637        We will check this ourselves by sending PING command to the primary. */
638     SILC_LOG_DEBUG(("Sending PING to detect status of primary router"));
639     idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
640     silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
641                              SILC_COMMAND_PING, ++server->cmd_ident, 1,
642                              1, idp->data, idp->len);
643     silc_buffer_free(idp);
644
645     /* Reprocess this packet after received reply from router */
646     pc = silc_calloc(1, sizeof(*pc));
647     pc->server = server;
648     pc->sock = silc_socket_dup(sock);
649     pc->packet = silc_packet_context_dup(packet);
650     silc_server_command_pending_timed(server, SILC_COMMAND_PING,
651                                       server->cmd_ident,
652                                       silc_server_backup_ping_reply, pc, 15);
653     return;
654   }
655
656
657   /* Start the resuming protocol if requested. */
658   if (type == SILC_SERVER_BACKUP_START) {
659     /* We have received a start for resuming protocol.  We are either
660        primary router that came back online or normal server. */
661     SilcServerBackupProtocolContext proto_ctx;
662
663     /* If backup had closed the connection earlier we won't allow resuming
664        since we (primary router) have never gone away. */
665     if (server->server_type == SILC_ROUTER && !server->backup_router &&
666         server->backup_closed) {
667       unsigned char data[4];
668       SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
669                       "primary router"));
670       SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
671       silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
672                               data, 4, FALSE);
673       server->backup_closed = FALSE;
674       return;
675     }
676
677     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
678     proto_ctx->server = server;
679     proto_ctx->sock = silc_socket_dup(sock);
680     proto_ctx->responder = TRUE;
681     proto_ctx->type = type;
682     proto_ctx->session = session;
683     proto_ctx->start = time(0);
684
685     SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
686     SILC_LOG_INFO(("Starting backup resuming protocol"));
687
688     /* Start protocol immediately */
689     silc_schedule_task_add(server->schedule, sock->sock,
690                            silc_server_backup_responder_start,
691                            proto_ctx, 0, 1,
692                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
693     return;
694   }
695
696
697   /* If we are router and the packet is coming from our primary router
698      then it means we have been replaced by an backup router in our cell. */
699   if (type == SILC_SERVER_BACKUP_REPLACED &&
700       server->server_type == SILC_ROUTER &&
701       sock->type == SILC_SOCKET_TYPE_ROUTER &&
702       SILC_PRIMARY_ROUTE(server) == sock) {
703     /* We have been replaced by an backup router in our cell. We must
704        mark our primary router connection disabled since we are not allowed
705        to use it at this moment. */
706     SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
707                    "wait until backup resuming protocol is executed"));
708     idata->status |= SILC_IDLIST_STATUS_DISABLED;
709     return;
710   }
711
712
713   /* Activate the shared protocol context for this socket connection
714      if necessary */
715   if (type == SILC_SERVER_BACKUP_RESUMED &&
716       sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
717       idata->status & SILC_IDLIST_STATUS_DISABLED) {
718     SilcServerEntry backup_router;
719
720     if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->id,
721                                         &backup_router)) {
722       SilcSocketConnection bsock =
723         (SilcSocketConnection)backup_router->connection;
724       if (bsock->protocol && bsock->protocol->protocol &&
725           bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
726         sock->protocol = bsock->protocol;
727         ctx = sock->protocol->context;
728         if (ctx->sock)
729           silc_socket_free(ctx->sock); /* unref */
730         ctx->sock = silc_socket_dup(sock);
731       }
732     }
733   }
734
735
736   /* Call the resuming protocol if the protocol is active. */
737   if (SILC_SERVER_IS_BACKUP(sock)) {
738     ctx = sock->protocol->context;
739     ctx->type = type;
740
741     for (i = 0; i < ctx->sessions_count; i++) {
742       if (session == ctx->sessions[i].session) {
743         ctx->session = session;
744         silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
745         return;
746       }
747     }
748
749     /* If RESUMED received the session ID is zero, execute the protocol. */
750     if (type == SILC_SERVER_BACKUP_RESUMED) {
751       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
752       return;
753     }
754
755     SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
756     return;
757   }
758 }
759
760 /* Timeout task callback to connect to remote router */
761
762 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
763 {
764   SilcServer server = app_context;
765   SilcServerConnection sconn = (SilcServerConnection)context;
766   int sock;
767   const char *server_ip;
768
769   SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
770                   sconn->remote_port));
771
772   /* Connect to remote host */
773   server_ip = server->config->server_info->primary == NULL ? NULL :
774     server->config->server_info->primary->server_ip;
775   sock = silc_net_create_connection(server_ip, sconn->remote_port,
776                                     sconn->remote_host);
777   if (sock < 0) {
778     if (server->server_type == SILC_SERVER) {
779       sconn->retry_count++;
780       if (sconn->retry_count > 3) {
781         silc_free(sconn->remote_host);
782         silc_free(sconn);
783         return;
784       }
785     }
786     silc_schedule_task_add(server->schedule, 0,
787                            silc_server_backup_connect_to_router,
788                            context, 10, 0, SILC_TASK_TIMEOUT,
789                            SILC_TASK_PRI_NORMAL);
790     return;
791   }
792
793   /* Continue with key exchange protocol */
794   silc_server_start_key_exchange(server, sconn, sock);
795 }
796
797 /* Constantly tries to reconnect to a primary router indicated by the
798    `ip' and `port'. The `connected' callback will be called when the
799    connection is created. */
800
801 void silc_server_backup_reconnect(SilcServer server,
802                                   const char *ip, SilcUInt16 port,
803                                   SilcServerConnectRouterCallback callback,
804                                   void *context)
805 {
806   SilcServerConnection sconn;
807
808   SILC_LOG_INFO(("Attempting to reconnect to primary router"));
809
810   sconn = silc_calloc(1, sizeof(*sconn));
811   sconn->remote_host = strdup(ip);
812   sconn->remote_port = port;
813   sconn->callback = callback;
814   sconn->callback_context = context;
815   sconn->no_reconnect = TRUE;
816   sconn->retry_count = 0;
817   silc_schedule_task_add(server->schedule, 0,
818                          silc_server_backup_connect_to_router,
819                          sconn, 1, 0, SILC_TASK_TIMEOUT,
820                          SILC_TASK_PRI_NORMAL);
821 }
822
823 /* Task that is called after backup router has connected back to
824    primary router and we are starting the resuming protocol */
825
826 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
827 {
828   SilcServerBackupProtocolContext proto_ctx =
829     (SilcServerBackupProtocolContext)context;
830   SilcServer server = proto_ctx->server;
831   SilcSocketConnection sock = proto_ctx->sock;
832
833   /* If running other protocol already run this one a bit later. */
834   if (sock->protocol) {
835     silc_schedule_task_add(server->schedule, 0,
836                            silc_server_backup_connected_later,
837                            proto_ctx, 10, 0,
838                            SILC_TASK_TIMEOUT,
839                            SILC_TASK_PRI_NORMAL);
840     return;
841   }
842
843   SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
844   SILC_LOG_INFO(("Starting backup resuming protocol"));
845
846   /* Run the backup resuming protocol */
847   silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
848                       &sock->protocol, proto_ctx,
849                       silc_server_protocol_backup_done);
850   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
851
852   silc_schedule_task_add(server->schedule, sock->sock,
853                          silc_server_backup_timeout,
854                          sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
855                          SILC_TASK_PRI_NORMAL);
856 }
857
858 /* Called when we've established connection back to our primary router
859    when we've acting as backup router and have replaced the primary router
860    in the cell. This function will start the backup resuming protocol. */
861
862 void silc_server_backup_connected(SilcServer server,
863                                   SilcServerEntry server_entry,
864                                   void *context)
865 {
866   SilcServerBackupProtocolContext proto_ctx;
867   SilcSocketConnection sock;
868
869   if (!server_entry) {
870     /* Try again */
871     SilcServerConfigRouter *primary;
872     primary = silc_server_config_get_primary_router(server);
873     if (primary) {
874       if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
875                                            primary->host, primary->port))
876         silc_server_backup_reconnect(server,
877                                      primary->host, primary->port,
878                                      silc_server_backup_connected,
879                                      context);
880     }
881     return;
882   }
883
884   sock = (SilcSocketConnection)server_entry->connection;
885   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
886   proto_ctx->server = server;
887   proto_ctx->sock = silc_socket_dup(sock);
888   proto_ctx->responder = FALSE;
889   proto_ctx->type = SILC_SERVER_BACKUP_START;
890   proto_ctx->start = time(0);
891
892   /* Start through scheduler */
893   silc_schedule_task_add(server->schedule, 0,
894                          silc_server_backup_connected_later,
895                          proto_ctx, 0, 1,
896                          SILC_TASK_TIMEOUT,
897                          SILC_TASK_PRI_NORMAL);
898 }
899
900 /* Called when normal server has connected to its primary router after
901    backup router has sent the START packet in reusming protocol. We will
902    move the protocol context from the backup router connection to the
903    primary router. */
904
905 static void silc_server_backup_connect_primary(SilcServer server,
906                                                SilcServerEntry server_entry,
907                                                void *context)
908 {
909   SilcSocketConnection backup_router = (SilcSocketConnection)context;
910   SilcServerBackupProtocolContext ctx;
911   SilcSocketConnection sock;
912   SilcIDListData idata;
913   unsigned char data[2];
914
915   if (SILC_IS_DISCONNECTING(backup_router) ||
916       SILC_IS_DISCONNECTED(backup_router)) {
917     silc_socket_free(backup_router);
918     return;
919   }
920
921   if (!server_entry) {
922     /* Try again */
923     SilcServerConfigRouter *primary;
924     primary = silc_server_config_get_primary_router(server);
925     if (primary)
926       if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
927                                            primary->host, primary->port))
928         silc_server_backup_reconnect(server,
929                                      primary->host, primary->port,
930                                      silc_server_backup_connect_primary,
931                                      context);
932     return;
933   }
934
935   /* Unref */
936   silc_socket_free(backup_router);
937
938   if (!backup_router->protocol)
939     return;
940   if (!server_entry->connection)
941     return;
942
943   ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
944   sock = (SilcSocketConnection)server_entry->connection;
945   idata = (SilcIDListData)server_entry;
946
947   SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
948   SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
949                 ctx->session));
950
951   /* Send the CONNECTED packet back to the backup router. */
952   data[0] = SILC_SERVER_BACKUP_CONNECTED;
953   data[1] = ctx->session;
954   silc_server_packet_send(server, backup_router,
955                           SILC_PACKET_RESUME_ROUTER, 0, data, 2, FALSE);
956
957   /* The primary connection is disabled until it sends the RESUMED packet
958      to us. */
959   idata->status |= SILC_IDLIST_STATUS_DISABLED;
960
961   /* Move this protocol context from this backup router connection to
962      the primary router connection since it will send the subsequent
963      packets in this protocol. We don't talk with backup router
964      anymore. */
965   sock->protocol = backup_router->protocol;
966   if (ctx->sock)
967     silc_socket_free(ctx->sock); /* unref */
968   ctx->sock = silc_socket_dup(server_entry->connection);
969   backup_router->protocol = NULL;
970 }
971
972 /* Timeout callback used by the backup router to send the ENDING packet
973    to primary router to indicate that it can now resume as being primary
974    router. All CONNECTED packets has been received when we reach this. */
975
976 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
977 {
978   SilcProtocol protocol = (SilcProtocol)context;
979   SilcServerBackupProtocolContext ctx = protocol->context;
980   SilcServer server = ctx->server;
981   unsigned char data[2];
982   int i;
983
984   SILC_LOG_DEBUG(("Start"));
985
986   for (i = 0; i < ctx->sessions_count; i++)
987     if (ctx->sessions[i].server_entry == ctx->sock->user_data)
988       ctx->session = ctx->sessions[i].session;
989
990   /* We've received all the CONNECTED packets and now we'll send the
991      ENDING packet to the new primary router. */
992   data[0] = SILC_SERVER_BACKUP_ENDING;
993   data[1] = ctx->session;
994   silc_server_packet_send(server, ctx->sock, SILC_PACKET_RESUME_ROUTER, 0,
995                           data, sizeof(data), FALSE);
996
997   /* The protocol will go to END state. */
998   protocol->state = SILC_PROTOCOL_STATE_END;
999 }
1000
1001 /* Backup resuming protocol. This protocol is executed when the primary
1002    router wants to resume its position as being primary router. */
1003
1004 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
1005 {
1006   SilcProtocol protocol = (SilcProtocol)context;
1007   SilcServerBackupProtocolContext ctx = protocol->context;
1008   SilcServer server = ctx->server;
1009   SilcServerEntry server_entry;
1010   SilcSocketConnection sock = NULL;
1011   unsigned char data[2];
1012   int i;
1013
1014   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
1015     protocol->state = SILC_PROTOCOL_STATE_START;
1016
1017   switch(protocol->state) {
1018   case SILC_PROTOCOL_STATE_START:
1019     if (ctx->responder == FALSE) {
1020       /*
1021        * Initiator (backup router)
1022        */
1023
1024       /* Send the START packet to primary router and normal servers. The
1025          packet will indicate to the primary router that it has been replaced
1026          by us.  For normal servers it means that we will be resigning as
1027          being primary router shortly. */
1028       for (i = 0; i < server->config->param.connections_max; i++) {
1029         sock = server->sockets[i];
1030         if (!sock || !sock->user_data ||
1031             sock->user_data == server->id_entry ||
1032             (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1033              sock->type != SILC_SOCKET_TYPE_SERVER))
1034           continue;
1035
1036         server_entry = sock->user_data;
1037         if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1038           continue;
1039
1040         ctx->sessions = silc_realloc(ctx->sessions,
1041                                      sizeof(*ctx->sessions) *
1042                                      (ctx->sessions_count + 1));
1043         ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
1044         ctx->sessions[ctx->sessions_count].connected = FALSE;
1045         ctx->sessions[ctx->sessions_count].server_entry = server_entry;
1046
1047         SILC_LOG_DEBUG(("Sending START to %s (session %d)",
1048                         server_entry->server_name, ctx->sessions_count));
1049         SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
1050                        server_entry->server_name, ctx->sessions_count));
1051
1052         /* This connection is performing this protocol too now */
1053         sock->protocol = protocol;
1054
1055         data[0] = SILC_SERVER_BACKUP_START;
1056         data[1] = ctx->sessions_count;
1057         silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
1058                                 data, sizeof(data), FALSE);
1059         ctx->sessions_count++;
1060       }
1061
1062       /* If we are not standalone and our primary is not the one we're
1063          talking to now, then announce our information to it since we
1064          haven't done that yet.  Standalone backup router announces
1065          these during connecting to the primary. */
1066       if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
1067         silc_server_announce_servers(server, TRUE, 0, ctx->sock);
1068         silc_server_announce_clients(server, 0, ctx->sock);
1069         silc_server_announce_channels(server, 0, ctx->sock);
1070       }
1071
1072       protocol->state++;
1073
1074     } else {
1075       /*
1076        * Responder (all servers and routers)
1077        */
1078       SilcServerConfigRouter *primary;
1079
1080       /* We should have received START packet */
1081       if (ctx->type != SILC_SERVER_BACKUP_START) {
1082         SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
1083         break;
1084       }
1085
1086       /* Connect to the primary router that was down that is now supposed
1087          to be back online. We send the CONNECTED packet after we've
1088          established the connection to the primary router. */
1089       primary = silc_server_config_get_primary_router(server);
1090       if (primary && server->backup_primary &&
1091           !silc_server_num_sockets_by_remote(server,
1092                                              silc_net_is_ip(primary->host) ?
1093                                              primary->host : NULL,
1094                                              silc_net_is_ip(primary->host) ?
1095                                              NULL : primary->host,
1096                                              primary->port,
1097                                              SILC_SOCKET_TYPE_ROUTER)) {
1098         SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
1099                         ctx->session));
1100         silc_server_backup_reconnect(server,
1101                                      primary->host, primary->port,
1102                                      silc_server_backup_connect_primary,
1103                                      silc_socket_dup(ctx->sock));
1104       } else {
1105         /* Nowhere to connect just return the CONNECTED packet */
1106         SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
1107                         ctx->session));
1108         SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
1109                       ctx->session));
1110
1111         /* Send the CONNECTED packet back to the backup router. */
1112         data[0] = SILC_SERVER_BACKUP_CONNECTED;
1113         data[1] = ctx->session;
1114         silc_server_packet_send(server, ctx->sock,
1115                                 SILC_PACKET_RESUME_ROUTER, 0,
1116                                 data, sizeof(data), FALSE);
1117       }
1118
1119       /* Add this resuming session */
1120       ctx->sessions = silc_realloc(ctx->sessions,
1121                                    sizeof(*ctx->sessions) *
1122                                    (ctx->sessions_count + 1));
1123       ctx->sessions[ctx->sessions_count].session = ctx->session;
1124       ctx->sessions_count++;
1125
1126       /* Normal server goes directly to the END state. */
1127       if (server->server_type == SILC_ROUTER &&
1128           (!server->router ||
1129            server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
1130         protocol->state++;
1131       else
1132         protocol->state = SILC_PROTOCOL_STATE_END;
1133     }
1134     break;
1135
1136   case 2:
1137     if (ctx->responder == FALSE) {
1138       /*
1139        * Initiator (backup router)
1140        */
1141
1142       /* We should have received CONNECTED packet */
1143       if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
1144         SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
1145         break;
1146       }
1147
1148       for (i = 0; i < ctx->sessions_count; i++) {
1149         if (ctx->sessions[i].session == ctx->session) {
1150           ctx->sessions[i].connected = TRUE;
1151           SILC_LOG_INFO(("Received CONNECTED from %s (session %d)",
1152                          ctx->sessions[i].server_entry->server_name,
1153                          ctx->session));
1154           SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
1155           break;
1156         }
1157       }
1158
1159       /* See if all returned CONNECTED, if not, then continue waiting. */
1160       for (i = 0; i < ctx->sessions_count; i++) {
1161         if (!ctx->sessions[i].connected)
1162           return;
1163       }
1164
1165       SILC_LOG_INFO(("All sessions have returned CONNECTED packets, "
1166                      "continuing"));
1167       SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
1168
1169       /* The ENDING is sent with timeout, and then we continue to the
1170          END state in the protocol. */
1171       silc_schedule_task_add(server->schedule, 0,
1172                              silc_server_backup_send_resumed,
1173                              protocol, 1, 0, SILC_TASK_TIMEOUT,
1174                              SILC_TASK_PRI_NORMAL);
1175       return;
1176
1177     } else {
1178       /*
1179        * Responder (primary router)
1180        */
1181
1182       /* We should have been received ENDING packet */
1183       if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
1184         SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
1185         break;
1186       }
1187
1188       SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
1189
1190       /* Switch announced informations to our primary router of using the
1191          backup router. */
1192       silc_server_local_servers_toggle_enabled(server, TRUE);
1193       silc_server_update_servers_by_server(server, ctx->sock->user_data,
1194                                            server->router);
1195       silc_server_update_clients_by_server(server, ctx->sock->user_data,
1196                                            server->router, TRUE);
1197
1198       /* We as primary router now must send RESUMED packets to all servers
1199          and routers so that they know we are back.   For backup router we
1200          send the packet last so that we give the backup as much time as
1201          possible to deal with message routing at this critical moment. */
1202       for (i = 0; i < server->config->param.connections_max; i++) {
1203         sock = server->sockets[i];
1204         if (!sock || !sock->user_data ||
1205             sock->user_data == server->id_entry ||
1206             (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1207              sock->type != SILC_SOCKET_TYPE_SERVER))
1208           continue;
1209
1210         /* Send to backup last */
1211         if (sock == ctx->sock)
1212           continue;
1213
1214       send_to_backup:
1215         server_entry = sock->user_data;
1216         server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1217
1218         SILC_LOG_DEBUG(("Sending RESUMED to %s", server_entry->server_name));
1219         SILC_LOG_INFO(("Sending RESUMED to %s", server_entry->server_name));
1220
1221         /* This connection is performing this protocol too now */
1222         sock->protocol = protocol;
1223
1224         data[0] = SILC_SERVER_BACKUP_RESUMED;
1225         data[1] = 0;
1226         silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
1227                                 data, sizeof(data), FALSE);
1228         silc_server_packet_queue_purge(server,sock);
1229       }
1230
1231       /* Now send the same packet to backup */
1232       if (sock != ctx->sock) {
1233         sleep(1);
1234         sock = ctx->sock;
1235         goto send_to_backup;
1236       }
1237
1238       /* We are now resumed and are back as primary router in the cell. */
1239       SILC_LOG_INFO(("We are now the primary router of our cell again"));
1240       server->wait_backup = FALSE;
1241
1242       /* For us this is the end of this protocol. */
1243       if (protocol->final_callback)
1244         silc_protocol_execute_final(protocol, server->schedule);
1245       else
1246         silc_protocol_free(protocol);
1247     }
1248     break;
1249
1250   case SILC_PROTOCOL_STATE_END:
1251     {
1252       /*
1253        * Responder (backup router, servers, and remote router)
1254        */
1255       SilcServerEntry router, backup_router;
1256
1257       /* We should have been received RESUMED from our primary router. */
1258       if (ctx->type != SILC_SERVER_BACKUP_RESUMED) {
1259         SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1260         break;
1261       }
1262
1263       SILC_LOG_INFO(("Received RESUMED from new primary router"));
1264
1265       /* If we are the backup router, mark that we are no longer primary
1266          but are back to backup router status. */
1267       if (server->backup_router)
1268         server->server_type = SILC_BACKUP_ROUTER;
1269
1270       /* We have now new primary router. All traffic goes there from now on. */
1271       router = ctx->sock->user_data;
1272       if (silc_server_backup_replaced_get(server, router->id,
1273                                           &backup_router)) {
1274
1275         if (backup_router == server->router) {
1276           /* We have new primary router now */
1277           server->id_entry->router = router;
1278           server->router = router;
1279           SILC_LOG_INFO(("Switching back to primary router %s",
1280                          server->router->server_name));
1281         } else {
1282           /* We are connected to new primary and now continue using it */
1283           SILC_LOG_INFO(("Resuming the use of primary router %s",
1284                          router->server_name));
1285         }
1286         server->backup_primary = FALSE;
1287         sock = router->connection;
1288
1289         /* Update the client entries of the backup router to the new
1290            router */
1291         silc_server_local_servers_toggle_enabled(server, FALSE);
1292         router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1293         silc_server_update_servers_by_server(server, backup_router, router);
1294         silc_server_update_clients_by_server(server, NULL, router, FALSE);
1295         if (server->server_type == SILC_SERVER)
1296           silc_server_update_channels_by_server(server, backup_router, router);
1297         silc_server_backup_replaced_del(server, backup_router);
1298
1299         /* Announce all of our information to the router. */
1300         if (server->server_type == SILC_ROUTER)
1301           silc_server_announce_servers(server, FALSE, ctx->start, sock);
1302
1303         /* Announce our clients and channels to the router */
1304         silc_server_announce_clients(server, ctx->start, sock);
1305         silc_server_announce_channels(server, ctx->start, sock);
1306       }
1307
1308       /* Send notify about primary router going down to local operators */
1309       SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1310                              SILC_NOTIFY_TYPE_NONE,
1311                              ("%s resumed the use of primary router %s",
1312                               server->server_name,
1313                               server->router->server_name));
1314
1315       /* Protocol has ended, call the final callback */
1316       if (protocol->final_callback)
1317         silc_protocol_execute_final(protocol, server->schedule);
1318       else
1319         silc_protocol_free(protocol);
1320     }
1321     break;
1322
1323   case SILC_PROTOCOL_STATE_ERROR:
1324     /* Protocol has ended, call the final callback */
1325     if (protocol->final_callback)
1326       silc_protocol_execute_final(protocol, server->schedule);
1327     else
1328       silc_protocol_free(protocol);
1329     break;
1330
1331   case SILC_PROTOCOL_STATE_FAILURE:
1332     /* Protocol has ended, call the final callback */
1333     SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1334     if (protocol->final_callback)
1335       silc_protocol_execute_final(protocol, server->schedule);
1336     else
1337       silc_protocol_free(protocol);
1338     break;
1339
1340   case SILC_PROTOCOL_STATE_UNKNOWN:
1341     break;
1342   }
1343 }
1344
1345 /* Final resuming protocol completion callback */
1346
1347 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1348 {
1349   SilcProtocol protocol = (SilcProtocol)context;
1350   SilcServerBackupProtocolContext ctx = protocol->context;
1351   SilcServer server = ctx->server;
1352   SilcServerEntry server_entry;
1353   SilcSocketConnection sock;
1354   bool error;
1355   int i;
1356
1357   silc_schedule_task_del_by_context(server->schedule, protocol);
1358
1359   error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1360            protocol->state == SILC_PROTOCOL_STATE_FAILURE);
1361
1362   if (error) {
1363     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1364     if (server->server_type == SILC_SERVER)
1365       silc_schedule_task_del_by_callback(server->schedule,
1366                                          silc_server_backup_connect_to_router);
1367   }
1368
1369   if (server->server_shutdown)
1370     return;
1371
1372   /* Remove this protocol from all server entries that has it */
1373   for (i = 0; i < server->config->param.connections_max; i++) {
1374     sock = server->sockets[i];
1375     if (!sock || !sock->user_data ||
1376         (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1377          sock->type != SILC_SOCKET_TYPE_SERVER))
1378       continue;
1379
1380     server_entry = sock->user_data;
1381
1382     /* The SilcProtocol context was shared between all connections, clear
1383        it from all connections. */
1384     if (sock->protocol == protocol) {
1385       sock->protocol = NULL;
1386
1387       if (error) {
1388         /* If we are server close all router connections except backup,
1389            send confirmation to backup that using it is still ok and continue
1390            sending traffic there.  The backup will reply with error if
1391            it's not ok. */
1392         if (server->server_type == SILC_SERVER &&
1393             server_entry->server_type == SILC_ROUTER) {
1394           server->backup_noswitch = TRUE;
1395           if (sock->user_data)
1396             silc_server_free_sock_user_data(server, sock, NULL);
1397           silc_server_disconnect_remote(server, sock, 0, NULL);
1398           server->backup_noswitch = FALSE;
1399
1400           /* Send START_USE just in case using backup wouldn't be ok. */
1401           silc_server_backup_send_start_use(server, server->router->connection,
1402                                             FALSE);
1403
1404           silc_server_create_connections(server);
1405           continue;
1406         }
1407
1408         /* If error occurred and we are backup router, we close connections. */
1409         if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1410           server->backup_noswitch = TRUE;
1411           server->server_type = SILC_BACKUP_ROUTER;
1412           if (ctx->sock == sock) {
1413             silc_socket_free(sock); /* unref */
1414             ctx->sock = NULL;
1415           }
1416
1417           server->backup_noswitch = TRUE;
1418           if (sock->user_data)
1419             silc_server_free_sock_user_data(server, sock, NULL);
1420           silc_server_disconnect_remote(server, sock, 0, NULL);
1421           server->backup_noswitch = FALSE;
1422
1423           silc_server_create_connections(server);
1424           continue;
1425         }
1426       }
1427
1428       server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1429     }
1430   }
1431
1432   if (!error)
1433     SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
1434
1435   if (ctx->sock && ctx->sock->protocol)
1436     ctx->sock->protocol = NULL;
1437   if (ctx->sock)
1438     silc_socket_free(ctx->sock); /* unref */
1439   silc_protocol_free(protocol);
1440   silc_free(ctx->sessions);
1441   silc_free(ctx);
1442 }