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