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