updates.
[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 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
20 #include "serverincludes.h"
21 #include "server_internal.h"
22
23 SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
24
25 /* Backup router */
26 typedef struct {
27   SilcServerEntry server;
28   bool local;
29 } SilcServerBackupEntry;
30
31 /* Holds IP address and port of the primary router that was replaced
32    by backup router. */
33 typedef struct {
34   SilcIDIP ip;
35   uint16 port;
36   SilcServerEntry server;       /* Backup router that replaced the primary */
37 } SilcServerBackupReplaced;
38
39 /* Backup context */
40 struct SilcServerBackupStruct {
41   SilcServerBackupEntry *servers;
42   uint32 servers_count;
43   SilcServerBackupReplaced **replaced;
44   uint32 replaced_count;
45 };
46
47 typedef struct {
48   uint8 session;
49   bool connected;
50   SilcServerEntry server_entry;
51 } SilcServerBackupProtocolSession;
52
53 /* Backup resuming protocol context  */
54 typedef struct {
55   SilcServer server;
56   SilcSocketConnection sock;
57   bool responder;
58   uint8 type;
59   uint8 session;
60   SilcServerBackupProtocolSession *sessions;
61   uint32 sessions_count;
62   long start;
63 } *SilcServerBackupProtocolContext;
64
65 /* Backup resuming protocol types */
66 #define SILC_SERVER_BACKUP_START            1
67 #define SILC_SERVER_BACKUP_START_GLOBAL     2
68 #define SILC_SERVER_BACKUP_CONNECTED        3
69 #define SILC_SERVER_BACKUP_ENDING           4
70 #define SILC_SERVER_BACKUP_RESUMED          5
71 #define SILC_SERVER_BACKUP_RESUMED_GLOBAL   6
72 #define SILC_SERVER_BACKUP_REPLACED         20
73
74 /* Sets the `backup_server' to be one of our backup router. This can be
75    called multiple times to set multiple backup routers. If `local' is
76    TRUE then the `backup_server' is in the local cell, if FALSE it is
77    in some other cell. */
78
79 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
80                             bool local)
81 {
82   int i;
83
84   if (!server->backup) {
85     server->backup = silc_calloc(1, sizeof(*server->backup));
86     server->backup->servers_count++;
87   }
88
89   for (i = 0; i < server->backup->servers_count; i++) {
90     if (!server->backup->servers[i].server) {
91       server->backup->servers[i].server = backup_server;
92       server->backup->servers[i].local = local;
93       return;
94     }
95   }
96
97   i = server->backup->servers_count;
98   server->backup->servers = silc_realloc(server->backup->servers,
99                                          sizeof(*server->backup->servers) *
100                                          (i + 1));
101   server->backup->servers[i].server = backup_server;
102   server->backup->servers[i].local = local;
103   server->backup->servers_count++;
104 }
105
106 /* Returns the first backup router context. Returns NULL if we do not have
107    any backup servers. */
108
109 SilcServerEntry silc_server_backup_get(SilcServer server)
110 {
111   SilcServerEntry backup_router;
112   int i;
113
114   if (!server->backup)
115     return NULL;
116
117   for (i = 0; i < server->backup->servers_count; i++) {
118     if (server->backup->servers[i].server) {
119       backup_router = server->backup->servers[i].server;
120       server->backup->servers[i].server = NULL;
121       return backup_router;
122     }
123   }
124
125   return NULL;
126 }
127
128 /* Deletes the backup server `server_entry. */
129
130 void silc_server_backup_del(SilcServer server, 
131                             SilcServerEntry server_entry)
132 {
133   int i;
134
135   if (!server->backup)
136     return ;
137
138   for (i = 0; i < server->backup->servers_count; i++) {
139     if (server->backup->servers[i].server == server_entry) {
140       server->backup->servers[i].server = NULL;
141       return;
142     }
143   }
144 }
145
146 /* Marks the IP address and port from the `server_id' as  being replaced
147    by backup router indicated by the `server'. If the router connects at
148    a later time we can check whether it has been replaced by an backup
149    router. */
150
151 void silc_server_backup_replaced_add(SilcServer server, 
152                                      SilcServerID *server_id,
153                                      SilcServerEntry server_entry)
154 {
155   int i;
156   SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
157
158   if (!server->backup) {
159     server->backup = silc_calloc(1, sizeof(*server->backup));
160     server->backup->servers_count++;
161   }
162   if (!server->backup->replaced) {
163     server->backup->replaced = 
164       silc_calloc(1, sizeof(*server->backup->replaced));
165     server->backup->replaced_count = 1;
166   }
167
168   memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
169   //r->port = server_id->port;
170   r->server = server_entry;
171
172   for (i = 0; i < server->backup->replaced_count; i++) {
173     if (!server->backup->replaced[i]) {
174       server->backup->replaced[i] = r;
175       return;
176     }
177   }
178
179   i = server->backup->replaced_count;
180   server->backup->replaced = silc_realloc(server->backup->replaced,
181                                           sizeof(*server->backup->replaced) *
182                                           (i + 1));
183   server->backup->replaced[i] = r;
184   server->backup->replaced_count++;
185 }
186
187 /* Checks whether the IP address and port from the `server_id' has been
188    replaced by an backup router. If it has been then this returns TRUE
189    and the bacup router entry to the `server' pointer if non-NULL. Returns
190    FALSE if the router is not replaced by backup router. */
191
192 bool silc_server_backup_replaced_get(SilcServer server,
193                                      SilcServerID *server_id,
194                                      SilcServerEntry *server_entry)
195 {
196   int i;
197
198   if (!server->backup || !server->backup->replaced)
199     return FALSE;
200
201   for (i = 0; i < server->backup->servers_count; i++) {
202     if (!server->backup->replaced[i])
203       continue;
204     if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip,
205                 sizeof(server_id->ip))) {
206       if (server_entry)
207         *server_entry = server->backup->replaced[i]->server;
208       return TRUE;
209     }
210   }
211
212   return FALSE;
213 }
214
215 /* Deletes the IP address and port from the `server_id' from being replaced
216    by an backup router. */
217
218 void silc_server_backup_replaced_del(SilcServer server,
219                                      SilcServerID *server_id)
220 {
221   int i;
222
223   if (!server->backup || !server->backup->replaced)
224     return;
225
226   for (i = 0; i < server->backup->servers_count; i++) {
227     if (!server->backup->replaced[i])
228       continue;
229     if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip,
230                 sizeof(server_id->ip))) {
231       silc_free(server->backup->replaced[i]);
232       server->backup->replaced[i] = NULL;
233       return;
234     }
235   }
236 }
237
238 /* Broadcast the received packet indicated by `packet' to all of our backup 
239    routers. All router wide information is passed using broadcast packets. 
240    That is why all backup routers need to get this data too. It is expected
241    that the caller already knows that the `packet' is broadcast packet. */
242
243 void silc_server_backup_broadcast(SilcServer server, 
244                                   SilcSocketConnection sender,
245                                   SilcPacketContext *packet)
246 {
247   SilcServerEntry backup;
248   SilcSocketConnection sock;
249   SilcBuffer buffer;
250   SilcIDListData idata;
251   int i;
252
253   if (!server->backup || server->server_type != SILC_ROUTER)
254     return;
255
256   SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
257
258   buffer = packet->buffer;
259   silc_buffer_push(buffer, buffer->data - buffer->head);
260
261   for (i = 0; i < server->backup->servers_count; i++) {
262     backup = server->backup->servers[i].server;
263
264     if (!backup || backup->connection == sender || 
265         server->backup->servers[i].local == FALSE)
266       continue;
267
268     idata = (SilcIDListData)backup;
269     sock = backup->connection;
270
271     silc_packet_send_prepare(sock, 0, 0, buffer->len); 
272     silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
273     silc_packet_encrypt(idata->send_key, idata->hmac_send, 
274                         sock->outbuf, sock->outbuf->len);
275
276     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
277                      sock->outbuf->data, sock->outbuf->len);
278
279     /* Now actually send the packet */
280     silc_server_packet_send_real(server, sock, FALSE);
281   }
282 }
283
284 /* A generic routine to send data to all backup routers. If the `sender'
285    is provided it will indicate the original sender of the packet and the
286    packet won't be resent to that entity. The `data' is the data that will
287    be assembled to packet context before sending. The packet will be
288    encrypted this function. If the `force_send' is TRUE the data is sent
289    immediately and not put to queue. If `local' is TRUE then the packet
290    will be sent only to local backup routers inside the cell. If false the
291    packet can go from one cell to the other. This function has no effect
292    if there are no any backup routers. */
293
294 void silc_server_backup_send(SilcServer server,
295                              SilcServerEntry sender,
296                              SilcPacketType type,
297                              SilcPacketFlags flags,
298                              unsigned char *data,
299                              uint32 data_len,
300                              bool force_send,
301                              bool local)
302 {
303   SilcServerEntry backup;
304   SilcSocketConnection sock;
305   int i;
306
307   if (!server->backup || server->server_type != SILC_ROUTER)
308     return;
309
310   SILC_LOG_DEBUG(("Start"));
311
312   for (i = 0; i < server->backup->servers_count; i++) {
313     backup = server->backup->servers[i].server;
314     if (!backup)
315       continue;
316
317     if (sender == backup)
318       continue;
319
320     if (local && server->backup->servers[i].local == FALSE)
321       continue;
322
323     sock = backup->connection;
324     silc_server_packet_send(server, backup->connection, type, flags, 
325                             data, data_len, force_send);
326   }
327 }
328
329 /* Same as silc_server_backup_send but sets a specific Destination ID to
330    the packet. The Destination ID is indicated by the `dst_id' and the
331    ID type `dst_id_type'. For example, packets destined to channels must
332    be sent using this function. */
333
334 void silc_server_backup_send_dest(SilcServer server,
335                                   SilcServerEntry sender,
336                                   SilcPacketType type,
337                                   SilcPacketFlags flags,
338                                   void *dst_id,
339                                   SilcIdType dst_id_type,
340                                   unsigned char *data,
341                                   uint32 data_len,
342                                   bool force_send,
343                                   bool local)
344 {
345   SilcServerEntry backup;
346   SilcSocketConnection sock;
347   int i;
348
349   if (!server->backup || server->server_type != SILC_ROUTER)
350     return;
351
352   SILC_LOG_DEBUG(("Start"));
353
354   for (i = 0; i < server->backup->servers_count; i++) {
355     backup = server->backup->servers[i].server;
356     if (!backup)
357       continue;
358
359     if (sender == backup)
360       continue;
361
362     if (local && server->backup->servers[i].local == FALSE)
363       continue;
364
365     sock = backup->connection;
366     silc_server_packet_send_dest(server, backup->connection, type, flags, 
367                                  dst_id, dst_id_type, data, data_len, 
368                                  force_send);
369   }
370 }
371
372 /* Processes incoming RESUME_ROUTER packet. This can give the packet
373    for processing to the protocol handler or allocate new protocol if
374    start command is received. */
375
376 void silc_server_backup_resume_router(SilcServer server, 
377                                       SilcSocketConnection sock, 
378                                       SilcPacketContext *packet)
379 {
380   uint8 type, session;
381   int ret;
382
383   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
384       sock->type == SILC_SOCKET_TYPE_UNKNOWN)
385     return;
386
387   SILC_LOG_DEBUG(("Start"));
388
389   ret = silc_buffer_unformat(packet->buffer,
390                              SILC_STR_UI_CHAR(&type),
391                              SILC_STR_UI_CHAR(&session),
392                              SILC_STR_END);
393   if (ret < 0)
394     return;
395   
396   /* If the backup resuming protocol is active then process the packet
397      in the protocol. */
398   if (sock->protocol && sock->protocol->protocol &&
399       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
400     SilcServerBackupProtocolContext ctx = sock->protocol->context;
401     int i;
402
403     ctx->type = type;
404
405     for (i = 0; i < ctx->sessions_count; i++) {
406       if (session == ctx->sessions[i].session) {
407         ctx->session = session;
408         silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
409         return;
410       }
411     }
412
413     SILC_LOG_DEBUG(("Bad resume router packet"));
414     return;
415   }
416
417   /* We don't have protocol active. If we are router and the packet is 
418      coming from our primary router then lets check whether it means we've
419      been replaced by an backup router in my cell. This is usually received
420      immediately after we've connected to our primary router. */
421
422   if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
423       server->router == sock->user_data &&
424       type == SILC_SERVER_BACKUP_REPLACED) {
425     /* We have been replaced by an backup router in our cell. We must
426        mark our primary router connection disabled since we are not allowed
427        to use it at this moment. */
428     SilcIDListData idata = (SilcIDListData)sock->user_data;
429
430     SILC_LOG_DEBUG(("We are replaced by an backup router in this cell"));
431     idata->status |= SILC_IDLIST_STATUS_DISABLED;
432     return;
433   }
434
435   if (type == SILC_SERVER_BACKUP_START ||
436       type == SILC_SERVER_BACKUP_START_GLOBAL) {
437     /* We have received a start for resuming protocol. */
438     SilcServerBackupProtocolContext proto_ctx;
439
440     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
441     proto_ctx->server = server;
442     proto_ctx->sock = sock;
443     proto_ctx->responder = TRUE;
444     proto_ctx->type = type;
445     proto_ctx->session = session;
446     proto_ctx->start = time(0);
447
448     SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
449
450     /* Run the backup resuming protocol */
451     silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
452                         &sock->protocol, proto_ctx, 
453                         silc_server_protocol_backup_done);
454     silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
455   }
456 }
457
458 /* Timeout task callback to connect to remote router */
459
460 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
461 {
462   SilcServerConnection sconn = (SilcServerConnection)context;
463   SilcServer server = sconn->server;
464   int sock;
465
466   SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
467                   sconn->remote_port));
468
469   /* Connect to remote host */
470   sock = silc_net_create_connection(server->config->listen_port->local_ip,
471                                     sconn->remote_port,
472                                     sconn->remote_host);
473   if (sock < 0) {
474     silc_schedule_task_add(server->schedule, 0,
475                            silc_server_backup_connect_to_router,
476                            context, 0, 2, SILC_TASK_TIMEOUT, 
477                            SILC_TASK_PRI_NORMAL);
478     return;
479   }
480
481   /* Continue with key exchange protocol */
482   silc_server_start_key_exchange(server, sconn, sock);
483 }
484
485 /* Constantly tries to reconnect to a primary router indicated by the
486    `ip' and `port'. The `connected' callback will be called when the
487    connection is created. */
488
489 void silc_server_backup_reconnect(SilcServer server,
490                                   const char *ip, uint16 port,
491                                   SilcServerConnectRouterCallback callback,
492                                   void *context)
493 {
494   SilcServerConnection sconn;
495
496   sconn = silc_calloc(1, sizeof(*sconn));
497   sconn->server = server;
498   sconn->remote_host = strdup(ip);
499   sconn->remote_port = port;
500   sconn->callback = callback;
501   sconn->callback_context = context;
502   silc_schedule_task_add(server->schedule, 0, 
503                          silc_server_backup_connect_to_router,
504                          sconn, 2, 0, SILC_TASK_TIMEOUT,
505                          SILC_TASK_PRI_NORMAL);
506 }
507
508 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
509 {
510   SilcServerBackupProtocolContext proto_ctx = 
511     (SilcServerBackupProtocolContext)context;
512   SilcServer server = proto_ctx->server;
513   SilcSocketConnection sock = proto_ctx->sock;
514
515   SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
516
517   /* Run the backup resuming protocol */
518   silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
519                       &sock->protocol, proto_ctx, 
520                       silc_server_protocol_backup_done);
521   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
522 }
523
524 /* Called when we've established connection back to our primary router
525    when we've acting as backup router and have replaced the primary router
526    in the cell. This function will start the backup resuming protocol. */
527
528 void silc_server_backup_connected(SilcServer server,
529                                   SilcServerEntry server_entry,
530                                   void *context)
531 {
532   SilcServerBackupProtocolContext proto_ctx;
533   SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
534
535   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
536   proto_ctx->server = server;
537   proto_ctx->sock = sock;
538   proto_ctx->responder = FALSE;
539   proto_ctx->type = SILC_SERVER_BACKUP_START;
540   proto_ctx->start = time(0);
541
542   /* Start through scheduler */
543   silc_schedule_task_add(server->schedule, 0,
544                          silc_server_backup_connected_later,
545                          proto_ctx, 0, 1,
546                          SILC_TASK_TIMEOUT,
547                          SILC_TASK_PRI_NORMAL);
548 }
549
550 /* Called when normal server has connected to its primary router after
551    backup router has sent the START packet in reusming protocol. We will
552    move the protocol context from the backup router connection to the
553    primary router. */
554
555 static void silc_server_backup_connect_primary(SilcServer server,
556                                                SilcServerEntry server_entry,
557                                                void *context)
558 {
559   SilcSocketConnection backup_router = (SilcSocketConnection)context;
560   SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
561   SilcIDListData idata = (SilcIDListData)server_entry;
562   SilcServerBackupProtocolContext ctx = 
563     (SilcServerBackupProtocolContext)backup_router->protocol->context;
564   SilcBuffer buffer;
565
566   /* Send the CONNECTED packet back to the backup router. */
567   buffer = silc_buffer_alloc(2);
568   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
569   silc_buffer_format(buffer,
570                      SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
571                      SILC_STR_UI_CHAR(ctx->session),
572                      SILC_STR_END);
573   silc_server_packet_send(server, backup_router, 
574                           SILC_PACKET_RESUME_ROUTER, 0, 
575                           buffer->data, buffer->len, FALSE);
576   silc_buffer_free(buffer);
577
578   /* Move this protocol context from this backup router connection to
579      the primary router connection since it will send the subsequent
580      packets in this protocol. We don't talk with backup router 
581      anymore. */
582   sock->protocol = backup_router->protocol;
583   ctx->sock = (SilcSocketConnection)server_entry->connection;
584   backup_router->protocol = NULL;
585
586   /* The primary connection is disabled until it sends the RESUMED packet
587      to us. */
588   idata->status |= SILC_IDLIST_STATUS_DISABLED;
589 }
590
591 /* Resume protocol with RESUME_ROUTER packet: 
592
593    SILC_PACKET_RESUME_ROUTER:
594
595    <uint8 type> <uint8 Session ID>
596
597    <type>          = the protocol opcode
598    <Session ID>    = Identifier for this packet and any subsequent reply
599                      packets must include this identifier.
600
601    Types:
602
603      1    = To router: Comensing backup resuming protocol. This will
604             indicate that the sender is backup router acting as primary
605             and the receiver is primary router that has been replaced by
606             the backup router.
607
608             To server. Comensing backup resuming protocol. This will
609             indicate that the sender is backup router and the receiver
610             must reconnect to the real primary router of the cell.
611
612      2    = To Router: Comesning backup resuming protocol in another
613             cell.  The receiver will connect to its primary router 
614             (the router that is now online again) but will not use
615             the link.  If the receiver is not configured to connect
616             to any router it does as locally configured.  The sender
617             is always backup router.
618
619             To server: this is never sent to server.
620
621      3    = To backup router: Sender is normal server or router and it
622             tells to backup router that they have connected to the
623             primary router.  Backup router never sends this type.
624
625      4    = To router: Ending backup resuming protocol. This is sent
626             to the real primary router to tell that it can take over
627             the task as being primary router.
628
629             To server: same as sending for router.
630
631             Backup router sends this also to the primary route but only
632             after it has sent them to normal servers and has purged all
633             traffic coming from normal servers.
634
635      5    = To router: Sender is the real primary router after it has
636             received type 4 from backup router. To tell that it is again
637             primary router of the cell.
638
639      20   = To router: This is sent only when router is connecting to
640             another router and has been replaced by an backup router.
641             The sender knows that the connectee has been replaced.
642
643  */
644
645 /* Backup resuming protocol. This protocol is executed when the primary
646    router wants to resume its position as being primary router. */
647
648 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
649 {
650   SilcProtocol protocol = (SilcProtocol)protocol;
651   SilcServerBackupProtocolContext ctx = protocol->context;
652   SilcServer server = ctx->server;
653   SilcBuffer packet;
654   SilcIDCacheList list;
655   SilcIDCacheEntry id_cache;
656   SilcServerEntry server_entry;
657   int i;
658
659   SILC_LOG_DEBUG(("Start"));
660
661   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
662     protocol->state = SILC_PROTOCOL_STATE_START;
663
664   SILC_LOG_DEBUG(("State=%d", protocol->state));
665
666   switch(protocol->state) {
667   case SILC_PROTOCOL_STATE_START:
668     if (ctx->responder == FALSE) {
669       /* Initiator of the protocol. We are backup router */
670
671       packet = silc_buffer_alloc(2);
672       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
673
674       /* Send the START packet to primary router and normal servers. */
675       if (silc_idcache_get_all(server->local_list->servers, &list)) {
676         if (silc_idcache_list_first(list, &id_cache)) {
677           while (id_cache) {
678             server_entry = (SilcServerEntry)id_cache->context;
679             if ((server_entry == server->id_entry) || 
680                 !server_entry->connection) {
681               if (!silc_idcache_list_next(list, &id_cache))
682                 break;
683               else
684                 continue;
685             }
686
687             ctx->sessions = silc_realloc(ctx->sessions,
688                                          sizeof(*ctx->sessions) *
689                                          (ctx->sessions_count + 1));
690             ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
691             ctx->sessions[ctx->sessions_count].connected = FALSE;
692             ctx->sessions[ctx->sessions_count].server_entry = server_entry;
693
694             if (server_entry->server_type == SILC_ROUTER)
695               packet->data[0] = SILC_SERVER_BACKUP_START;
696             else
697               packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
698             packet->data[1] = ctx->sessions_count;
699             silc_server_packet_send(server, server_entry->connection,
700                                     SILC_PACKET_RESUME_ROUTER, 0, 
701                                     packet->data, packet->len, FALSE);
702             ctx->sessions_count++;
703
704             if (!silc_idcache_list_next(list, &id_cache))
705               break;
706           }
707         }
708
709         silc_idcache_list_free(list);
710       }
711
712       /* Now, announce all of our information to the primary router */
713       if (server->server_type == SILC_ROUTER)
714         silc_server_announce_servers(server, FALSE, 0);
715       silc_server_announce_clients(server, 0);
716       silc_server_announce_channels(server, 0);
717
718       silc_buffer_free(packet);
719
720       protocol->state++;
721     } else {
722       /* Responder of the protocol. */
723       SilcServerConfigSectionServerConnection *primary;
724
725       /* We should have received START or START_GLOBAL packet */
726       if (ctx->type != SILC_SERVER_BACKUP_START &&
727           ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
728         SILC_LOG_DEBUG(("Bad resume router packet"));
729         break;
730       }
731
732       /* Connect to the primary router that was down that is now supposed
733          to be back online. We send the CONNECTED packet after we've
734          established the connection to the primary router. */
735       primary = silc_server_config_get_primary_router(server->config);
736       if (primary)
737         silc_server_backup_reconnect(server,
738                                      primary->host, primary->port,
739                                      silc_server_backup_connect_primary,
740                                      ctx->sock);
741
742       protocol->state++;
743     }
744     break;
745
746   case 2:
747     if (ctx->responder == FALSE) {
748       /* Initiator */
749
750       /* We should have received CONNECTED packet */
751       if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
752         SILC_LOG_DEBUG(("Bad resume router packet"));
753         break;
754       }
755
756       for (i = 0; i < ctx->sessions_count; i++) {
757         if (ctx->sessions[i].session == ctx->session) {
758           ctx->sessions[i].connected = TRUE;
759         }
760       }
761
762       for (i = 0; i < ctx->sessions_count; i++) {
763         if (!ctx->sessions[i].connected)
764           break;
765       }
766
767       /* We've received all the CONNECTED packets and now we'll send the
768          ENDING packet to the new primary router. */
769       packet = silc_buffer_alloc(2);
770       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
771       silc_buffer_format(packet,
772                          SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
773                          SILC_STR_UI_CHAR(ctx->session),
774                          SILC_STR_END);
775       silc_server_packet_send(server, ctx->sock, 
776                               SILC_PACKET_RESUME_ROUTER, 0, 
777                               packet->data, packet->len, FALSE);
778       silc_buffer_free(packet);
779
780       protocol->state = SILC_PROTOCOL_STATE_END;
781     } else {
782       /* Responder */
783
784       /* We should have been received ENDING packet */
785       if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
786         SILC_LOG_DEBUG(("Bad resume router packet"));
787         break;
788       }
789
790       /* This state is received by the primary router but also servers
791          and perhaps other routers so check that if we are the primary
792          router of the cell then start sending RESUMED packets.  If we
793          are normal server or one of those other routers then procede
794          to next state. */
795       if (!(server->router->data.status & SILC_IDLIST_STATUS_DISABLED)) {
796         /* We'll wait for RESUMED packet */
797         protocol->state = SILC_PROTOCOL_STATE_END;
798         break;
799       }
800
801       packet = silc_buffer_alloc(2);
802       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
803
804       /* We are the primary router, start sending RESUMED packets. */
805       if (silc_idcache_get_all(server->local_list->servers, &list)) {
806         if (silc_idcache_list_first(list, &id_cache)) {
807           while (id_cache) {
808             server_entry = (SilcServerEntry)id_cache->context;
809             if ((server_entry == server->id_entry) || 
810                 !server_entry->connection) {
811               if (!silc_idcache_list_next(list, &id_cache))
812                 break;
813               else
814                 continue;
815             }
816
817             if (server_entry->server_type == SILC_ROUTER)
818               packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
819             else
820               packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
821             packet->data[1] = ctx->sessions_count;
822             silc_server_packet_send(server, server_entry->connection,
823                                     SILC_PACKET_RESUME_ROUTER, 0, 
824                                     packet->data, packet->len, FALSE);
825
826             if (!silc_idcache_list_next(list, &id_cache))
827               break;
828           }
829         }
830
831         silc_idcache_list_free(list);
832       }
833
834       silc_buffer_free(packet);
835
836       /* For us this is the end of this protocol. */
837       if (protocol->final_callback)
838         silc_protocol_execute_final(protocol, server->schedule);
839       else
840         silc_protocol_free(protocol);
841     }
842     break;
843
844   case SILC_PROTOCOL_STATE_END:
845     {
846       SilcIDListData idata;
847       SilcServerEntry primary;
848       SilcServerEntry backup_router;
849
850       /* We should have been received RESUMED packet from our primary
851          router. */
852       if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
853           ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
854         SILC_LOG_DEBUG(("Bad resume router packet"));
855         break;
856       }
857
858       /* We have now new primary router. All traffic goes there from now on. */
859       if (server->backup_router)
860         server->server_type = SILC_BACKUP_ROUTER;
861
862       primary = (SilcServerEntry)ctx->sock->user_data;
863       if (silc_server_backup_replaced_get(server, primary->id, 
864                                           &backup_router)) {
865
866         if (backup_router == server->router) {
867           server->id_entry->router = ctx->sock->user_data;
868           server->router = ctx->sock->user_data;
869           SILC_LOG_DEBUG(("Switching back to primary router %s",
870                         server->router->server_name));
871           idata = (SilcIDListData)server->router;
872           idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
873         }
874
875         /* Announce all of our information to the new primary router. We
876            announce all that was updated after the protocol was started since
877            the router knows all the older stuff. */
878         if (server->server_type == SILC_ROUTER)
879           silc_server_announce_servers(server, FALSE, ctx->start - 60);
880         
881         /* Announce our clients and channels to the router */
882         silc_server_announce_clients(server, ctx->start - 60);
883         silc_server_announce_channels(server, ctx->start - 60);
884       }
885
886       /* Protocol has ended, call the final callback */
887       if (protocol->final_callback)
888         silc_protocol_execute_final(protocol, server->schedule);
889       else
890         silc_protocol_free(protocol);
891     }
892     break;
893
894   case SILC_PROTOCOL_STATE_ERROR:
895     break;
896
897   case SILC_PROTOCOL_STATE_FAILURE:
898     break;
899
900   case SILC_PROTOCOL_STATE_UNKNOWN:
901     break;
902   }
903 }
904
905 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
906 {
907
908 }