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