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