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