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