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