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