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   SilcServerBackupProtocolContext ctx;
405   int i, ret;
406
407   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
408       sock->type == SILC_SOCKET_TYPE_UNKNOWN)
409     return;
410
411   SILC_LOG_DEBUG(("Start"));
412
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   /* Activate the protocol for this socket if necessary */
421   if ((type == SILC_SERVER_BACKUP_RESUMED || 
422       type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
423       sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol && 
424       ((SilcIDListData)sock->user_data)->status & 
425       SILC_IDLIST_STATUS_DISABLED) {
426     SilcServerEntry backup_router;
427
428     if (silc_server_backup_replaced_get(server, 
429                                         ((SilcServerEntry)sock->
430                                          user_data)->id, 
431                                         &backup_router)) {
432       SilcSocketConnection bsock = 
433         (SilcSocketConnection)backup_router->connection;
434       if (bsock->protocol && bsock->protocol->protocol &&
435           bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
436         sock->protocol = bsock->protocol;
437         ctx = sock->protocol->context;
438         ctx->sock = sock;
439       }
440     }
441   }
442
443   /* If the backup resuming protocol is active then process the packet
444      in the protocol. */
445   if (sock->protocol && sock->protocol->protocol &&
446       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
447     ctx = sock->protocol->context;
448     ctx->type = type;
449
450     SILC_LOG_DEBUG(("********************************"));
451     SILC_LOG_DEBUG(("Continuing protocol, type %d", type));
452
453     if (type != SILC_SERVER_BACKUP_RESUMED &&
454         type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
455       for (i = 0; i < ctx->sessions_count; i++) {
456         if (session == ctx->sessions[i].session) {
457           ctx->session = session;
458           silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
459           return;
460         }
461       }
462     } else {
463       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
464       return;
465     }
466
467     SILC_LOG_DEBUG(("Bad resume router packet"));
468     return;
469   }
470
471   /* We don't have protocol active. If we are router and the packet is 
472      coming from our primary router then lets check whether it means we've
473      been replaced by an backup router in my cell. This is usually received
474      immediately after we've connected to our primary router. */
475
476   if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
477       server->router == sock->user_data &&
478       type == SILC_SERVER_BACKUP_REPLACED) {
479     /* We have been replaced by an backup router in our cell. We must
480        mark our primary router connection disabled since we are not allowed
481        to use it at this moment. */
482     SilcIDListData idata = (SilcIDListData)sock->user_data;
483
484     SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
485                    "wait until backup resuming protocol is executed"));
486
487     SILC_LOG_DEBUG(("We are replaced by an backup router in this cell"));
488     idata->status |= SILC_IDLIST_STATUS_DISABLED;
489     return;
490   }
491
492   if (type == SILC_SERVER_BACKUP_START ||
493       type == SILC_SERVER_BACKUP_START_GLOBAL) {
494     /* We have received a start for resuming protocol. */
495     SilcServerBackupProtocolContext proto_ctx;
496
497     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
498     proto_ctx->server = server;
499     proto_ctx->sock = sock;
500     proto_ctx->responder = TRUE;
501     proto_ctx->type = type;
502     proto_ctx->session = session;
503     proto_ctx->start = time(0);
504
505     SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
506
507     /* Run the backup resuming protocol */
508     silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
509                         &sock->protocol, proto_ctx, 
510                         silc_server_protocol_backup_done);
511     silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
512   }
513 }
514
515 /* Timeout task callback to connect to remote router */
516
517 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
518 {
519   SilcServerConnection sconn = (SilcServerConnection)context;
520   SilcServer server = sconn->server;
521   int sock;
522
523   SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
524                   sconn->remote_port));
525
526   /* Connect to remote host */
527   sock = silc_net_create_connection(server->config->listen_port->local_ip,
528                                     sconn->remote_port,
529                                     sconn->remote_host);
530   if (sock < 0) {
531     silc_schedule_task_add(server->schedule, 0,
532                            silc_server_backup_connect_to_router,
533                            context, 5, 0, SILC_TASK_TIMEOUT, 
534                            SILC_TASK_PRI_NORMAL);
535     return;
536   }
537
538   /* Continue with key exchange protocol */
539   silc_server_start_key_exchange(server, sconn, sock);
540 }
541
542 /* Constantly tries to reconnect to a primary router indicated by the
543    `ip' and `port'. The `connected' callback will be called when the
544    connection is created. */
545
546 void silc_server_backup_reconnect(SilcServer server,
547                                   const char *ip, uint16 port,
548                                   SilcServerConnectRouterCallback callback,
549                                   void *context)
550 {
551   SilcServerConnection sconn;
552
553   sconn = silc_calloc(1, sizeof(*sconn));
554   sconn->server = server;
555   sconn->remote_host = strdup(ip);
556   sconn->remote_port = port;
557   sconn->callback = callback;
558   sconn->callback_context = context;
559   silc_schedule_task_add(server->schedule, 0, 
560                          silc_server_backup_connect_to_router,
561                          sconn, 1, 0, SILC_TASK_TIMEOUT,
562                          SILC_TASK_PRI_NORMAL);
563 }
564
565 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
566 {
567   SilcServerBackupProtocolContext proto_ctx = 
568     (SilcServerBackupProtocolContext)context;
569   SilcServer server = proto_ctx->server;
570   SilcSocketConnection sock = proto_ctx->sock;
571
572   SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
573
574   /* Run the backup resuming protocol */
575   silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
576                       &sock->protocol, proto_ctx, 
577                       silc_server_protocol_backup_done);
578   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
579 }
580
581 /* Called when we've established connection back to our primary router
582    when we've acting as backup router and have replaced the primary router
583    in the cell. This function will start the backup resuming protocol. */
584
585 void silc_server_backup_connected(SilcServer server,
586                                   SilcServerEntry server_entry,
587                                   void *context)
588 {
589   SilcServerBackupProtocolContext proto_ctx;
590   SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
591
592   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
593   proto_ctx->server = server;
594   proto_ctx->sock = sock;
595   proto_ctx->responder = FALSE;
596   proto_ctx->type = SILC_SERVER_BACKUP_START;
597   proto_ctx->start = time(0);
598
599   /* Start through scheduler */
600   silc_schedule_task_add(server->schedule, 0,
601                          silc_server_backup_connected_later,
602                          proto_ctx, 0, 1,
603                          SILC_TASK_TIMEOUT,
604                          SILC_TASK_PRI_NORMAL);
605 }
606
607 /* Called when normal server has connected to its primary router after
608    backup router has sent the START packet in reusming protocol. We will
609    move the protocol context from the backup router connection to the
610    primary router. */
611
612 static void silc_server_backup_connect_primary(SilcServer server,
613                                                SilcServerEntry server_entry,
614                                                void *context)
615 {
616   SilcSocketConnection backup_router = (SilcSocketConnection)context;
617   SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
618   SilcIDListData idata = (SilcIDListData)server_entry;
619   SilcServerBackupProtocolContext ctx = 
620     (SilcServerBackupProtocolContext)backup_router->protocol->context;
621   SilcBuffer buffer;
622
623   SILC_LOG_DEBUG(("Start"));
624
625   SILC_LOG_DEBUG(("********************************"));
626   SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
627
628   /* Send the CONNECTED packet back to the backup router. */
629   buffer = silc_buffer_alloc(2);
630   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
631   silc_buffer_format(buffer,
632                      SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
633                      SILC_STR_UI_CHAR(ctx->session),
634                      SILC_STR_END);
635   silc_server_packet_send(server, backup_router, 
636                           SILC_PACKET_RESUME_ROUTER, 0, 
637                           buffer->data, buffer->len, FALSE);
638   silc_buffer_free(buffer);
639
640   /* The primary connection is disabled until it sends the RESUMED packet
641      to us. */
642   idata->status |= SILC_IDLIST_STATUS_DISABLED;
643
644   /* Move this protocol context from this backup router connection to
645      the primary router connection since it will send the subsequent
646      packets in this protocol. We don't talk with backup router 
647      anymore. */
648   sock->protocol = backup_router->protocol;
649   ctx->sock = (SilcSocketConnection)server_entry->connection;
650   backup_router->protocol = NULL;
651 }
652
653 /* Resume protocol with RESUME_ROUTER packet: 
654
655    SILC_PACKET_RESUME_ROUTER:
656
657    <uint8 type> <uint8 Session ID>
658
659    <type>          = the protocol opcode
660    <Session ID>    = Identifier for this packet and any subsequent reply
661                      packets must include this identifier.
662
663    Types:
664
665      1    = To router: Comensing backup resuming protocol. This will
666             indicate that the sender is backup router acting as primary
667             and the receiver is primary router that has been replaced by
668             the backup router.
669
670             To server. Comensing backup resuming protocol. This will
671             indicate that the sender is backup router and the receiver
672             must reconnect to the real primary router of the cell.
673
674      2    = To Router: Comesning backup resuming protocol in another
675             cell.  The receiver will connect to its primary router 
676             (the router that is now online again) but will not use
677             the link.  If the receiver is not configured to connect
678             to any router it does as locally configured.  The sender
679             is always backup router.
680
681             To server: this is never sent to server.
682
683      3    = To backup router: Sender is normal server or router and it
684             tells to backup router that they have connected to the
685             primary router.  Backup router never sends this type.
686
687      4    = To router: Ending backup resuming protocol. This is sent
688             to the real primary router to tell that it can take over
689             the task as being primary router.
690
691             To server: same as sending for router.
692
693             Backup router sends this also to the primary route but only
694             after it has sent them to normal servers and has purged all
695             traffic coming from normal servers.
696
697      5    = To router: Sender is the real primary router after it has
698             received type 4 from backup router. To tell that it is again
699             primary router of the cell.
700
701      20   = To router: This is sent only when router is connecting to
702             another router and has been replaced by an backup router.
703             The sender knows that the connectee has been replaced.
704
705  */
706
707 /* Backup resuming protocol. This protocol is executed when the primary
708    router wants to resume its position as being primary router. */
709
710 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
711 {
712   SilcProtocol protocol = (SilcProtocol)context;
713   SilcServerBackupProtocolContext ctx = protocol->context;
714   SilcServer server = ctx->server;
715   SilcBuffer packet;
716   SilcIDCacheList list;
717   SilcIDCacheEntry id_cache;
718   SilcServerEntry server_entry;
719   int i;
720
721   SILC_LOG_DEBUG(("Start"));
722
723   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
724     protocol->state = SILC_PROTOCOL_STATE_START;
725
726   SILC_LOG_DEBUG(("State=%d", protocol->state));
727
728   switch(protocol->state) {
729   case SILC_PROTOCOL_STATE_START:
730     if (ctx->responder == FALSE) {
731       /* Initiator of the protocol. We are backup router */
732
733       packet = silc_buffer_alloc(2);
734       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
735
736       SILC_LOG_DEBUG(("********************************"));
737       SILC_LOG_DEBUG(("Sending START packets"));
738
739       /* Send the START packet to primary router and normal servers. */
740       if (silc_idcache_get_all(server->local_list->servers, &list)) {
741         if (silc_idcache_list_first(list, &id_cache)) {
742           while (id_cache) {
743             server_entry = (SilcServerEntry)id_cache->context;
744             if ((server_entry == server->id_entry) || 
745                 !server_entry->connection) {
746               if (!silc_idcache_list_next(list, &id_cache))
747                 break;
748               else
749                 continue;
750             }
751
752             ctx->sessions = silc_realloc(ctx->sessions,
753                                          sizeof(*ctx->sessions) *
754                                          (ctx->sessions_count + 1));
755             ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
756             ctx->sessions[ctx->sessions_count].connected = FALSE;
757             ctx->sessions[ctx->sessions_count].server_entry = server_entry;
758
759             SILC_LOG_DEBUG(("********************************"));
760             SILC_LOG_DEBUG(("START for session %d", ctx->sessions_count));
761
762             /* This connection is performing this protocol too now */
763             ((SilcSocketConnection)server_entry->connection)->protocol =
764               protocol;
765
766             if (server_entry->server_type == SILC_ROUTER)
767               packet->data[0] = SILC_SERVER_BACKUP_START;
768             else
769               packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
770             packet->data[1] = ctx->sessions_count;
771             silc_server_packet_send(server, server_entry->connection,
772                                     SILC_PACKET_RESUME_ROUTER, 0, 
773                                     packet->data, packet->len, FALSE);
774             ctx->sessions_count++;
775
776             if (!silc_idcache_list_next(list, &id_cache))
777               break;
778           }
779         }
780
781         silc_idcache_list_free(list);
782       }
783
784       silc_buffer_free(packet);
785
786       /* If we are router then announce our possible servers. */
787       if (server->server_type == SILC_ROUTER)
788         silc_server_announce_servers(server, FALSE, 0, ctx->sock);
789       silc_server_announce_clients(server, 0, ctx->sock);
790       silc_server_announce_channels(server, 0, ctx->sock);
791
792       protocol->state++;
793     } else {
794       /* Responder of the protocol. */
795       SilcServerConfigSectionServerConnection *primary;
796
797       /* We should have received START or START_GLOBAL packet */
798       if (ctx->type != SILC_SERVER_BACKUP_START &&
799           ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
800         SILC_LOG_DEBUG(("Bad resume router packet"));
801         break;
802       }
803
804       SILC_LOG_DEBUG(("********************************"));
805       SILC_LOG_DEBUG(("Received START packet, reconnecting to router"));
806
807       /* Connect to the primary router that was down that is now supposed
808          to be back online. We send the CONNECTED packet after we've
809          established the connection to the primary router. */
810       primary = silc_server_config_get_primary_router(server->config);
811       if (primary && server->backup_primary) {
812         silc_server_backup_reconnect(server,
813                                      primary->host, primary->port,
814                                      silc_server_backup_connect_primary,
815                                      ctx->sock);
816       } else {
817         /* Nowhere to connect just return the CONNECTED packet */
818
819         SILC_LOG_DEBUG(("********************************"));
820         SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
821         
822         /* Send the CONNECTED packet back to the backup router. */
823         packet = silc_buffer_alloc(2);
824         silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
825         silc_buffer_format(packet,
826                            SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
827                            SILC_STR_UI_CHAR(ctx->session),
828                            SILC_STR_END);
829         silc_server_packet_send(server, ctx->sock, 
830                                 SILC_PACKET_RESUME_ROUTER, 0, 
831                                 packet->data, packet->len, FALSE);
832         silc_buffer_free(packet);
833       }
834
835       if (server->server_type == SILC_ROUTER &&
836           (!server->router || 
837            server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
838         protocol->state++;
839       else
840         protocol->state = SILC_PROTOCOL_STATE_END;
841
842       ctx->sessions = silc_realloc(ctx->sessions,
843                                    sizeof(*ctx->sessions) *
844                                    (ctx->sessions_count + 1));
845       ctx->sessions[ctx->sessions_count].session = ctx->session;
846       ctx->sessions_count++;
847     }
848     break;
849
850   case 2:
851     if (ctx->responder == FALSE) {
852       /* Initiator */
853
854       /* We should have received CONNECTED packet */
855       if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
856         SILC_LOG_DEBUG(("Bad resume router packet"));
857         break;
858       }
859
860       SILC_LOG_DEBUG(("********************************"));
861       SILC_LOG_DEBUG(("Received CONNECTED packet, session %d", ctx->session));
862
863       for (i = 0; i < ctx->sessions_count; i++) {
864         if (ctx->sessions[i].session == ctx->session) {
865           ctx->sessions[i].connected = TRUE;
866           break;
867         }
868       }
869
870       for (i = 0; i < ctx->sessions_count; i++) {
871         if (!ctx->sessions[i].connected)
872           return;
873       }
874
875       SILC_LOG_DEBUG(("********************************"));
876       SILC_LOG_DEBUG(("Sending ENDING packet to primary"));
877
878       for (i = 0; i < ctx->sessions_count; i++)
879         if (ctx->sessions[i].server_entry == ctx->sock->user_data)
880           ctx->session = ctx->sessions[i].session;
881
882       /* We've received all the CONNECTED packets and now we'll send the
883          ENDING packet to the new primary router. */
884       packet = silc_buffer_alloc(2);
885       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
886       silc_buffer_format(packet,
887                          SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
888                          SILC_STR_UI_CHAR(ctx->session),
889                          SILC_STR_END);
890       silc_server_packet_send(server, ctx->sock, 
891                               SILC_PACKET_RESUME_ROUTER, 0, 
892                               packet->data, packet->len, FALSE);
893       silc_buffer_free(packet);
894
895       protocol->state = SILC_PROTOCOL_STATE_END;
896     } else {
897       /* Responder */
898
899       /* We should have been received ENDING packet */
900       if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
901         SILC_LOG_DEBUG(("Bad resume router packet"));
902         break;
903       }
904
905       SILC_LOG_DEBUG(("********************************"));
906       SILC_LOG_DEBUG(("Received ENDING packet, sending RESUMED packets"));
907
908       /* This state is received by the primary router but also servers
909          and perhaps other routers so check that if we are the primary
910          router of the cell then start sending RESUMED packets.  If we
911          are normal server or one of those other routers then procede
912          to next state. */
913       if (server->router &&
914           !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
915           silc_server_config_is_primary_route(server->config)) {
916         /* We'll wait for RESUMED packet */
917         protocol->state = SILC_PROTOCOL_STATE_END;
918         break;
919       }
920
921       /* Switch announced informations to our entry instead of using the
922          backup router. */
923       silc_server_update_clients_by_server(server, ctx->sock->user_data,
924                                            server->id_entry, TRUE, FALSE);
925
926       packet = silc_buffer_alloc(2);
927       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
928
929       /* We are the primary router, start sending RESUMED packets. */
930       if (silc_idcache_get_all(server->local_list->servers, &list)) {
931         if (silc_idcache_list_first(list, &id_cache)) {
932           while (id_cache) {
933             server_entry = (SilcServerEntry)id_cache->context;
934             if ((server_entry == server->id_entry) || 
935                 !server_entry->connection) {
936               if (!silc_idcache_list_next(list, &id_cache))
937                 break;
938               else
939                 continue;
940             }
941
942             SILC_LOG_DEBUG(("********************************"));
943             SILC_LOG_DEBUG(("RESUMED packet"));
944
945             server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
946
947             /* This connection is performing this protocol too now */
948             ((SilcSocketConnection)server_entry->connection)->protocol =
949               protocol;
950
951             if (server_entry->server_type == SILC_ROUTER)
952               packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
953             else
954               packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
955             silc_server_packet_send(server, server_entry->connection,
956                                     SILC_PACKET_RESUME_ROUTER, 0, 
957                                     packet->data, packet->len, FALSE);
958
959             if (!silc_idcache_list_next(list, &id_cache))
960               break;
961           }
962         }
963
964         silc_idcache_list_free(list);
965       }
966
967       silc_buffer_free(packet);
968
969       SILC_LOG_INFO(("We are now the primary router of our cell again"));
970
971       /* For us this is the end of this protocol. */
972       if (protocol->final_callback)
973         silc_protocol_execute_final(protocol, server->schedule);
974       else
975         silc_protocol_free(protocol);
976     }
977     break;
978
979   case SILC_PROTOCOL_STATE_END:
980     {
981       SilcIDListData idata;
982       SilcServerEntry router, backup_router;
983
984       /* We should have been received RESUMED packet from our primary
985          router. */
986       if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
987           ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
988         SILC_LOG_DEBUG(("Bad resume router packet"));
989         break;
990       }
991
992       SILC_LOG_DEBUG(("********************************"));
993       SILC_LOG_DEBUG(("Received RESUMED packet"));
994
995       /* We have now new primary router. All traffic goes there from now on. */
996       if (server->backup_router)
997         server->server_type = SILC_BACKUP_ROUTER;
998
999       router = (SilcServerEntry)ctx->sock->user_data;
1000       if (silc_server_backup_replaced_get(server, router->id, 
1001                                           &backup_router)) {
1002
1003         if (backup_router == server->router) {
1004           SILC_LOG_INFO(("Switching back to primary router %s",
1005                          server->router->server_name));
1006           SILC_LOG_DEBUG(("Switching back to primary router %s",
1007                           server->router->server_name));
1008           server->id_entry->router = router;
1009           server->router = router;
1010         } else {
1011           SILC_LOG_INFO(("Resuming the use of router %s",
1012                          router->server_name));
1013           SILC_LOG_DEBUG(("Resuming the use of router %s",
1014                           router->server_name));
1015         }
1016
1017         idata = (SilcIDListData)server->router;
1018         idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
1019
1020         /* Update the client entries of the backup router to the new router */
1021         silc_server_update_clients_by_server(server, backup_router,
1022                                              router, FALSE, FALSE);
1023         silc_server_backup_replaced_del(server, backup_router);
1024         silc_server_backup_add(server, backup_router, 
1025                                ctx->sock->ip, ctx->sock->port,
1026                                backup_router->server_type != SILC_ROUTER ?
1027                                TRUE : FALSE);
1028
1029         /* Announce all of our information to the router. */
1030         if (server->server_type == SILC_ROUTER)
1031           silc_server_announce_servers(server, FALSE, 0, router->connection);
1032         
1033         /* Announce our clients and channels to the router */
1034         silc_server_announce_clients(server, 0, router->connection);
1035         silc_server_announce_channels(server, 0, router->connection);
1036       }
1037
1038       /* Protocol has ended, call the final callback */
1039       if (protocol->final_callback)
1040         silc_protocol_execute_final(protocol, server->schedule);
1041       else
1042         silc_protocol_free(protocol);
1043     }
1044     break;
1045
1046   case SILC_PROTOCOL_STATE_ERROR:
1047     /* Protocol has ended, call the final callback */
1048     if (protocol->final_callback)
1049       silc_protocol_execute_final(protocol, server->schedule);
1050     else
1051       silc_protocol_free(protocol);
1052     break;
1053
1054   case SILC_PROTOCOL_STATE_FAILURE:
1055     /* Protocol has ended, call the final callback */
1056     if (protocol->final_callback)
1057       silc_protocol_execute_final(protocol, server->schedule);
1058     else
1059       silc_protocol_free(protocol);
1060     break;
1061
1062   case SILC_PROTOCOL_STATE_UNKNOWN:
1063     break;
1064   }
1065 }
1066
1067 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1068 {
1069   SilcProtocol protocol = (SilcProtocol)context;
1070   SilcServerBackupProtocolContext ctx = protocol->context;
1071   SilcServer server = ctx->server;
1072   SilcServerEntry server_entry;
1073   SilcSocketConnection sock;
1074   SilcIDCacheList list;
1075   SilcIDCacheEntry id_cache;
1076
1077   SILC_LOG_DEBUG(("Start"));
1078
1079   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1080       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1081     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1082   }
1083
1084   /* Remove this protocol from all server entries that has it */
1085   if (silc_idcache_get_all(server->local_list->servers, &list)) {
1086     if (silc_idcache_list_first(list, &id_cache)) {
1087       while (id_cache) {
1088         server_entry = (SilcServerEntry)id_cache->context;
1089         sock = (SilcSocketConnection)server_entry->connection;
1090
1091         if (sock->protocol == protocol) {
1092           sock->protocol = NULL;
1093
1094           if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1095             server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1096         }
1097         
1098         if (!silc_idcache_list_next(list, &id_cache))
1099           break;
1100       }
1101     }
1102     silc_idcache_list_free(list);
1103   }
1104
1105   if (ctx->sock->protocol)
1106     ctx->sock->protocol = NULL;
1107   silc_protocol_free(protocol);
1108   silc_free(ctx->sessions);
1109   silc_free(ctx);
1110 }