1 /*
2
3 server_backup.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2001 - 2005 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: server_backup.c,v 1.37 2005/04/23 13:32:24 priikone Exp $ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
24 SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
25 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router);
26 SILC_TASK_CALLBACK(silc_server_backup_announce_watches);
27
28 static void silc_server_backup_connect_primary(SilcServer server,
29 SilcServerEntry server_entry,
30 void *context);
31
32
33 /************************** Types and Definitions ***************************/
34
35 /* Backup router */
36 typedef struct {
37 SilcServerEntry server;
38 SilcIDIP ip;
39 SilcUInt16 port;
40 bool local;
41 } SilcServerBackupEntry;
42
43 /* Holds IP address and port of the primary router that was replaced
44 by backup router. */
45 typedef struct {
46 SilcIDIP ip;
47 SilcUInt16 port;
48 SilcServerEntry server; /* Backup router that replaced the primary */
49 } SilcServerBackupReplaced;
50
51 /* Backup context */
52 struct SilcServerBackupStruct {
53 SilcServerBackupEntry *servers;
54 SilcUInt32 servers_count;
55 SilcServerBackupReplaced **replaced;
56 SilcUInt32 replaced_count;
57 };
58
59 typedef struct {
60 SilcUInt8 session;
61 bool connected;
62 SilcServerEntry server_entry;
63 } SilcServerBackupProtocolSession;
64
65 /* Backup resuming protocol context */
66 typedef struct {
67 SilcServer server;
68 SilcSocketConnection sock;
69 SilcUInt8 type;
70 SilcUInt8 session;
71 SilcServerBackupProtocolSession *sessions;
72 SilcUInt32 sessions_count;
73 SilcUInt32 initiator_restart;
74 long start;
75 unsigned int responder : 1;
76 unsigned int received_failure : 1;
77 unsigned int timeout : 1;
78 } *SilcServerBackupProtocolContext;
79
80
81 /********************* Backup Configuration Routines ************************/
82
83 /* Adds the `backup_server' to be one of our backup router. This can be
84 called multiple times to set multiple backup routers. The `ip' and `port'
85 is the IP and port that the `backup_router' will replace if the `ip'
86 will become unresponsive. If `local' is TRUE then the `backup_server' is
87 in the local cell, if FALSE it is in some other cell. */
88
89 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
90 const char *ip, int port, bool local)
91 {
92 int i;
93
94 if (!ip)
95 return;
96
97 if (!server->backup) {
98 server->backup = silc_calloc(1, sizeof(*server->backup));
99 if (!server->backup)
100 return;
101 }
102
103 /* See if already added */
104 for (i = 0; i < server->backup->servers_count; i++) {
105 if (server->backup->servers[i].server == backup_server)
106 return;
107 }
108
109 SILC_LOG_DEBUG(("Backup router %s will replace %s",
110 ((SilcSocketConnection)backup_server->connection)->ip,
111 ip, port));
112
113 for (i = 0; i < server->backup->servers_count; i++) {
114 if (!server->backup->servers[i].server) {
115 server->backup->servers[i].server = backup_server;
116 server->backup->servers[i].local = local;
117 server->backup->servers[i].port = SILC_SWAB_16(port);
118 memset(server->backup->servers[i].ip.data, 0,
119 sizeof(server->backup->servers[i].ip.data));
120 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
121 sizeof(server->backup->servers[i].ip.data));
122 return;
123 }
124 }
125
126 i = server->backup->servers_count;
127 server->backup->servers = silc_realloc(server->backup->servers,
128 sizeof(*server->backup->servers) *
129 (i + 1));
130 server->backup->servers[i].server = backup_server;
131 server->backup->servers[i].local = local;
132 server->backup->servers[i].port = SILC_SWAB_16(port);
133 memset(server->backup->servers[i].ip.data, 0,
134 sizeof(server->backup->servers[i].ip.data));
135 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
136 sizeof(server->backup->servers[i].ip.data));
137 server->backup->servers_count++;
138 }
139
140 /* Returns backup router for IP and port in `server_id' or NULL if there
141 does not exist backup router. */
142
143 SilcServerEntry silc_server_backup_get(SilcServer server,
144 SilcServerID *server_id)
145 {
146 int i;
147
148 if (!server->backup)
149 return NULL;
150
151 for (i = 0; i < server->backup->servers_count; i++) {
152 if (server->backup->servers[i].server &&
153 server->backup->servers[i].port == server_id->port &&
154 !memcmp(server->backup->servers[i].ip.data, server_id->ip.data,
155 sizeof(server_id->ip.data))) {
156 SILC_LOG_DEBUG(("Found backup router %s for %s",
157 server->backup->servers[i].server->server_name,
158 silc_id_render(server_id, SILC_ID_SERVER)));
159 return server->backup->servers[i].server;
160 }
161 }
162
163 return NULL;
164 }
165
166 /* Deletes the backup server `server_entry'. */
167
168 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
169 {
170 int i;
171
172 if (!server->backup)
173 return;
174
175 for (i = 0; i < server->backup->servers_count; i++) {
176 if (server->backup->servers[i].server == server_entry) {
177 SILC_LOG_DEBUG(("Removing %s as backup router",
178 silc_id_render(server->backup->servers[i].server->id,
179 SILC_ID_SERVER)));
180 server->backup->servers[i].server = NULL;
181 memset(server->backup->servers[i].ip.data, 0,
182 sizeof(server->backup->servers[i].ip.data));
183 }
184 }
185 }
186
187 /* Frees all data allocated for backup routers. Call this after deleting
188 all backup routers and when new routers are added no more, for example
189 when shutting down the server. */
190
191 void silc_server_backup_free(SilcServer server)
192 {
193 int i;
194
195 if (!server->backup)
196 return;
197
198 /* Delete existing servers if caller didn't do it */
199 for (i = 0; i < server->backup->servers_count; i++) {
200 if (server->backup->servers[i].server)
201 silc_server_backup_del(server, server->backup->servers[i].server);
202 }
203
204 silc_free(server->backup->servers);
205 silc_free(server->backup);
206 server->backup = NULL;
207 }
208
209 /* Marks the IP address and port from the `server_id' as being replaced
210 by backup router indicated by the `server'. If the router connects at
211 a later time we can check whether it has been replaced by an backup
212 router. */
213
214 void silc_server_backup_replaced_add(SilcServer server,
215 SilcServerID *server_id,
216 SilcServerEntry server_entry)
217 {
218 int i;
219 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
220
221 if (!server->backup)
222 server->backup = silc_calloc(1, sizeof(*server->backup));
223 if (!server->backup->replaced) {
224 server->backup->replaced =
225 silc_calloc(1, sizeof(*server->backup->replaced));
226 server->backup->replaced_count = 1;
227 }
228
229 SILC_LOG_DEBUG(("Replacing router %s with %s",
230 silc_id_render(server_id, SILC_ID_SERVER),
231 server_entry->server_name));
232
233 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
234 r->server = server_entry;
235
236 for (i = 0; i < server->backup->replaced_count; i++) {
237 if (!server->backup->replaced[i]) {
238 server->backup->replaced[i] = r;
239 return;
240 }
241 }
242
243 i = server->backup->replaced_count;
244 server->backup->replaced = silc_realloc(server->backup->replaced,
245 sizeof(*server->backup->replaced) *
246 (i + 1));
247 server->backup->replaced[i] = r;
248 server->backup->replaced_count++;
249 }
250
251 /* Checks whether the IP address and port from the `server_id' has been
252 replaced by an backup router. If it has been then this returns TRUE
253 and the bacup router entry to the `server' pointer if non-NULL. Returns
254 FALSE if the router is not replaced by backup router. */
255
256 bool silc_server_backup_replaced_get(SilcServer server,
257 SilcServerID *server_id,
258 SilcServerEntry *server_entry)
259 {
260 int i;
261
262 if (!server->backup || !server->backup->replaced)
263 return FALSE;
264
265 for (i = 0; i < server->backup->replaced_count; i++) {
266 if (!server->backup->replaced[i])
267 continue;
268 if (!memcmp(server->backup->replaced[i]->ip.data, server_id->ip.data,
269 sizeof(server_id->ip.data))) {
270 if (server_entry)
271 *server_entry = server->backup->replaced[i]->server;
272 SILC_LOG_DEBUG(("Router %s is replaced by %s",
273 silc_id_render(server_id, SILC_ID_SERVER),
274 server->backup->replaced[i]->server->server_name));
275 return TRUE;
276 }
277 }
278
279 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
280 silc_id_render(server_id, SILC_ID_SERVER)));
281 return FALSE;
282 }
283
284 /* Deletes a replaced host by the set `server_entry. */
285
286 void silc_server_backup_replaced_del(SilcServer server,
287 SilcServerEntry server_entry)
288 {
289 int i;
290
291 if (!server->backup || !server->backup->replaced)
292 return;
293
294 for (i = 0; i < server->backup->replaced_count; i++) {
295 if (!server->backup->replaced[i])
296 continue;
297 if (server->backup->replaced[i]->server == server_entry) {
298 silc_free(server->backup->replaced[i]);
299 server->backup->replaced[i] = NULL;
300 }
301 }
302 }
303
304 /* Broadcast the received packet indicated by `packet' to all of our backup
305 routers. All router wide information is passed using broadcast packets.
306 That is why all backup routers need to get this data too. It is expected
307 that the caller already knows that the `packet' is broadcast packet. */
308
309 void silc_server_backup_broadcast(SilcServer server,
310 SilcSocketConnection sender,
311 SilcPacketContext *packet)
312 {
313 SilcServerEntry backup;
314 SilcSocketConnection sock;
315 SilcBuffer buffer;
316 const SilcBufferStruct p;
317 SilcIDListData idata;
318 int i;
319
320 if (!server->backup || server->server_type != SILC_ROUTER)
321 return;
322
323 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
324
325 buffer = packet->buffer;
326 silc_buffer_push(buffer, buffer->data - buffer->head);
327
328 for (i = 0; i < server->backup->servers_count; i++) {
329 backup = server->backup->servers[i].server;
330
331 if (!backup || backup->connection == sender ||
332 server->backup->servers[i].local == FALSE)
333 continue;
334 if (server->backup->servers[i].server == server->id_entry)
335 continue;
336
337 idata = (SilcIDListData)backup;
338 sock = backup->connection;
339
340 if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
341 (const SilcBuffer)&p)) {
342 SILC_LOG_ERROR(("Cannot send packet"));
343 return;
344 }
345 silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
346 silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
347 (SilcBuffer)&p, p.len);
348
349 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
350
351 /* Now actually send the packet */
352 silc_server_packet_send_real(server, sock, FALSE);
353
354 /* Check for mandatory rekey */
355 if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
356 silc_schedule_task_add(server->schedule, sender->sock,
357 silc_server_rekey_callback, sender, 0, 1,
358 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
359 }
360 }
361
362 /* A generic routine to send data to all backup routers. If the `sender'
363 is provided it will indicate the original sender of the packet and the
364 packet won't be resent to that entity. The `data' is the data that will
365 be assembled to packet context before sending. The packet will be
366 encrypted this function. If the `force_send' is TRUE the data is sent
367 immediately and not put to queue. If `local' is TRUE then the packet
368 will be sent only to local backup routers inside the cell. If false the
369 packet can go from one cell to the other. This function has no effect
370 if there are no any backup routers. */
371
372 void silc_server_backup_send(SilcServer server,
373 SilcServerEntry sender,
374 SilcPacketType type,
375 SilcPacketFlags flags,
376 unsigned char *data,
377 SilcUInt32 data_len,
378 bool force_send,
379 bool local)
380 {
381 SilcServerEntry backup;
382 SilcSocketConnection sock;
383 int i;
384
385 if (!server->backup || server->server_type != SILC_ROUTER)
386 return;
387
388 for (i = 0; i < server->backup->servers_count; i++) {
389 backup = server->backup->servers[i].server;
390 if (!backup || sender == backup)
391 continue;
392 if (local && server->backup->servers[i].local == FALSE)
393 continue;
394 if (server->backup->servers[i].server == server->id_entry)
395 continue;
396
397 sock = backup->connection;
398
399 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
400 silc_get_packet_name(type), sock->hostname, sock->ip));
401
402 silc_server_packet_send(server, backup->connection, type, flags,
403 data, data_len, force_send);
404 }
405 }
406
407 /* Same as silc_server_backup_send but sets a specific Destination ID to
408 the packet. The Destination ID is indicated by the `dst_id' and the
409 ID type `dst_id_type'. For example, packets destined to channels must
410 be sent using this function. */
411
412 void silc_server_backup_send_dest(SilcServer server,
413 SilcServerEntry sender,
414 SilcPacketType type,
415 SilcPacketFlags flags,
416 void *dst_id,
417 SilcIdType dst_id_type,
418 unsigned char *data,
419 SilcUInt32 data_len,
420 bool force_send,
421 bool local)
422 {
423 SilcServerEntry backup;
424 SilcSocketConnection sock;
425 int i;
426
427 if (!server->backup || server->server_type != SILC_ROUTER)
428 return;
429
430 for (i = 0; i < server->backup->servers_count; i++) {
431 backup = server->backup->servers[i].server;
432 if (!backup || sender == backup)
433 continue;
434 if (local && server->backup->servers[i].local == FALSE)
435 continue;
436 if (server->backup->servers[i].server == server->id_entry)
437 continue;
438
439 sock = backup->connection;
440
441 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
442 silc_get_packet_name(type), sock->hostname, sock->ip));
443
444 silc_server_packet_send_dest(server, backup->connection, type, flags,
445 dst_id, dst_id_type, data, data_len,
446 force_send);
447 }
448 }
449
450 /* Send the START_USE indication to remote connection. If `failure' is
451 TRUE then this sends SILC_PACKET_FAILURE. Otherwise it sends
452 SILC_PACKET_RESUME_ROUTER. */
453
454 void silc_server_backup_send_start_use(SilcServer server,
455 SilcSocketConnection sock,
456 bool failure)
457 {
458 unsigned char data[4];
459
460 SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
461 failure ? "failure" : "success", sock->ip));
462
463 if (failure) {
464 SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
465 silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
466 data, 4, FALSE);
467 } else {
468 data[0] = SILC_SERVER_BACKUP_START_USE;
469 data[1] = 0;
470 silc_server_packet_send(server, sock,
471 SILC_PACKET_RESUME_ROUTER, 0,
472 data, 2, FALSE);
473 }
474 }
475
476 /* Send the REPLACED indication to remote router. This is send by the
477 primary router (remote router) of the primary router that came back
478 online. This is not sent by backup router or any other server. */
479
480 void silc_server_backup_send_replaced(SilcServer server,
481 SilcSocketConnection sock)
482 {
483 unsigned char data[4];
484
485 SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
486
487 data[0] = SILC_SERVER_BACKUP_REPLACED;
488 data[1] = 0;
489 silc_server_packet_send(server, sock,
490 SILC_PACKET_RESUME_ROUTER, 0,
491 data, 2, FALSE);
492 }
493
494
495 /************************ Backup Resuming Protocol **************************/
496
497 /* Timeout callback for protocol */
498
499 SILC_TASK_CALLBACK(silc_server_backup_timeout)
500 {
501 SilcProtocol protocol = context;
502 SilcServerBackupProtocolContext ctx = protocol->context;
503 SilcServer server = app_context;
504
505 SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
506 ctx->timeout = TRUE;
507 silc_protocol_cancel(protocol, server->schedule);
508 protocol->state = SILC_PROTOCOL_STATE_ERROR;
509 silc_protocol_execute_final(protocol, server->schedule);
510 }
511
512 /* Callback to start the protocol as responder */
513
514 SILC_TASK_CALLBACK(silc_server_backup_responder_start)
515 {
516 SilcServerBackupProtocolContext proto_ctx = context;
517 SilcSocketConnection sock = proto_ctx->sock;
518 SilcServer server = app_context;
519
520 /* If other protocol is executing at the same time, start with timeout. */
521 if (sock->protocol) {
522 SILC_LOG_DEBUG(("Other protocol is executing, wait for it to finish"));
523 silc_schedule_task_add(server->schedule, sock->sock,
524 silc_server_backup_responder_start,
525 proto_ctx, 2, 0,
526 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
527 return;
528 }
529
530 /* Run the backup resuming protocol */
531 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
532 &sock->protocol, proto_ctx,
533 silc_server_protocol_backup_done);
534 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
535 silc_schedule_task_add(server->schedule, sock->sock,
536 silc_server_backup_timeout,
537 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
538 SILC_TASK_PRI_NORMAL);
539 }
540
541 /* Callback to send START_USE to backup to check whether using backup
542 is ok. */
543
544 SILC_TASK_CALLBACK(silc_server_backup_check_status)
545 {
546 SilcSocketConnection sock = context;
547 SilcServer server = app_context;
548
549 /* Check whether we are still using backup */
550 if (!server->backup_primary)
551 return;
552
553 silc_server_backup_send_start_use(server, sock, FALSE);
554 silc_socket_free(sock); /* unref */
555 }
556
557 typedef struct {
558 SilcServer server;
559 SilcSocketConnection sock;
560 SilcPacketContext *packet;
561 } *SilcServerBackupPing;
562
563 /* PING command reply callback */
564
565 void silc_server_backup_ping_reply(void *context, void *reply)
566 {
567 SilcServerBackupPing pc = context;
568 SilcServerCommandReplyContext cmdr = reply;
569
570 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
571 /* Timeout error occurred, the primary is really down. */
572 SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
573
574 SILC_LOG_DEBUG(("PING timeout, primary is down"));
575
576 if (primary) {
577 if (primary->user_data)
578 silc_server_free_sock_user_data(pc->server, primary, NULL);
579 SILC_SET_DISCONNECTING(primary);
580 silc_server_close_connection(pc->server, primary);
581 }
582
583 /* Reprocess the RESUME_ROUTER packet */
584 silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
585 } else {
586 /* The primary is not down, refuse to serve the server as primary */
587 SILC_LOG_DEBUG(("PING received, primary is up"));
588 silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
589 }
590
591 silc_socket_free(pc->sock);
592 silc_packet_context_free(pc->packet);
593 silc_free(pc);
594 }
595
596 /* Processes incoming RESUME_ROUTER packet. This can give the packet
597 for processing to the protocol handler or allocate new protocol if
598 start command is received. */
599
600 void silc_server_backup_resume_router(SilcServer server,
601 SilcSocketConnection sock,
602 SilcPacketContext *packet)
603 {
604 SilcUInt8 type, session;
605 SilcServerBackupProtocolContext ctx;
606 SilcIDListData idata;
607 int i, ret;
608
609 SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
610
611 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
612 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
613 SILC_LOG_DEBUG(("Bad packet received"));
614 return;
615 }
616
617 idata = (SilcIDListData)sock->user_data;
618
619 ret = silc_buffer_unformat(packet->buffer,
620 SILC_STR_UI_CHAR(&type),
621 SILC_STR_UI_CHAR(&session),
622 SILC_STR_END);
623 if (ret < 0) {
624 SILC_LOG_ERROR(("Malformed resume router packet received"));
625 return;
626 }
627
628 /* Check whether this packet is used to tell us that server will start
629 using us as primary router. */
630 if (type == SILC_SERVER_BACKUP_START_USE) {
631 SilcBuffer idp;
632 SilcServerBackupPing pc;
633
634 /* If we are normal server then backup router has sent us back
635 this reply and we use the backup as primary router now. */
636 if (server->server_type == SILC_SERVER) {
637 /* Nothing to do here actually, since we have switched already. */
638 SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
639 return;
640 }
641
642 /* Backup router following. */
643
644 /* If we are marked as router then the primary is down and we send
645 success START_USE back to the server. */
646 if (server->server_type == SILC_ROUTER) {
647 SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
648 silc_server_backup_send_start_use(server, sock, FALSE);
649 return;
650 }
651
652 /* We have just lost primary, send success START_USE back */
653 if (server->standalone) {
654 SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
655 sock->ip));
656 silc_server_backup_send_start_use(server, sock, FALSE);
657 return;
658 }
659
660 /* We are backup router. This server claims that our primary is down.
661 We will check this ourselves by sending PING command to the primary. */
662 SILC_LOG_DEBUG(("Sending PING to detect status of primary router"));
663 idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
664 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
665 SILC_COMMAND_PING, ++server->cmd_ident, 1,
666 1, idp->data, idp->len);
667 silc_buffer_free(idp);
668
669 /* Reprocess this packet after received reply from router */
670 pc = silc_calloc(1, sizeof(*pc));
671 pc->server = server;
672 pc->sock = silc_socket_dup(sock);
673 pc->packet = silc_packet_context_dup(packet);
674 silc_server_command_pending_timed(server, SILC_COMMAND_PING,
675 server->cmd_ident,
676 silc_server_backup_ping_reply, pc, 15);
677 return;
678 }
679
680
681 /* Start the resuming protocol if requested. */
682 if (type == SILC_SERVER_BACKUP_START) {
683 /* We have received a start for resuming protocol. We are either
684 primary router that came back online or normal server. */
685 SilcServerBackupProtocolContext proto_ctx;
686
687 /* If backup had closed the connection earlier we won't allow resuming
688 since we (primary router) have never gone away. */
689 if (server->server_type == SILC_ROUTER && !server->backup_router &&
690 server->backup_closed) {
691 unsigned char data[4];
692 SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
693 "primary router"));
694 SILC_LOG_INFO(("Backup resuming not allowed since we are still "
695 "primary router"));
696 SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
697 silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
698 data, 4, FALSE);
699 server->backup_closed = FALSE;
700 return;
701 }
702
703 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
704 proto_ctx->server = server;
705 proto_ctx->sock = silc_socket_dup(sock);
706 proto_ctx->responder = TRUE;
707 proto_ctx->type = type;
708 proto_ctx->session = session;
709 proto_ctx->start = time(0);
710
711 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
712 SILC_LOG_INFO(("Starting backup resuming protocol"));
713
714 /* Start protocol immediately */
715 silc_schedule_task_add(server->schedule, sock->sock,
716 silc_server_backup_responder_start,
717 proto_ctx, 0, 1,
718 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
719 return;
720 }
721
722
723 /* If we are router and the packet is coming from our primary router
724 then it means we have been replaced by an backup router in our cell. */
725 if (type == SILC_SERVER_BACKUP_REPLACED &&
726 server->server_type == SILC_ROUTER &&
727 sock->type == SILC_SOCKET_TYPE_ROUTER &&
728 SILC_PRIMARY_ROUTE(server) == sock) {
729 /* We have been replaced by an backup router in our cell. We must
730 mark our primary router connection disabled since we are not allowed
731 to use it at this moment. */
732 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
733 "wait until backup resuming protocol is executed"));
734 idata->status |= SILC_IDLIST_STATUS_DISABLED;
735 return;
736 }
737
738
739 /* Activate the shared protocol context for this socket connection
740 if necessary */
741 if (type == SILC_SERVER_BACKUP_RESUMED &&
742 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
743 idata->status & SILC_IDLIST_STATUS_DISABLED) {
744 SilcServerEntry backup_router;
745
746 if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->id,
747 &backup_router)) {
748 SilcSocketConnection bsock =
749 (SilcSocketConnection)backup_router->connection;
750 if (bsock->protocol && bsock->protocol->protocol &&
751 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
752 sock->protocol = bsock->protocol;
753 ctx = sock->protocol->context;
754 if (ctx->sock)
755 silc_socket_free(ctx->sock); /* unref */
756 ctx->sock = silc_socket_dup(sock);
757 }
758 }
759 }
760
761
762 /* Call the resuming protocol if the protocol is active. */
763 if (SILC_SERVER_IS_BACKUP(sock)) {
764 ctx = sock->protocol->context;
765 ctx->type = type;
766
767 for (i = 0; i < ctx->sessions_count; i++) {
768 if (session == ctx->sessions[i].session) {
769 ctx->session = session;
770 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
771 return;
772 }
773 }
774
775 /* If RESUMED received the session ID is zero, execute the protocol. */
776 if (type == SILC_SERVER_BACKUP_RESUMED) {
777 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
778 return;
779 }
780
781 SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
782 return;
783 }
784 }
785
786 /* callback for async connection to remote router */
787
788 SILC_TASK_CALLBACK(silc_server_backup_connection_established)
789 {
790 SilcServer server = app_context;
791 SilcServerConnection sconn = (SilcServerConnection)context;
792 int sock = fd;
793 int opt = EINVAL, optlen = sizeof(opt);
794
795 silc_schedule_task_del_by_fd(server->schedule, sock);
796 silc_schedule_unset_listen_fd(server->schedule, sock);
797
798 if (silc_net_get_socket_opt(sock, SOL_SOCKET, SO_ERROR, &opt, &optlen) ||
799 (opt != 0)) {
800 SILC_LOG_DEBUG(("Could not connect to router %s:%d: %s", sconn->remote_host,
801 sconn->remote_port, strerror(opt)));
802
803 if (server->server_type == SILC_SERVER) {
804 sconn->retry_count++;
805 if (sconn->retry_count > 3) {
806 silc_free(sconn->remote_host);
807 silc_free(sconn);
808 return;
809 }
810 }
811 silc_schedule_task_add(server->schedule, 0,
812 silc_server_backup_connect_to_router,
813 context, 10, 0, SILC_TASK_TIMEOUT,
814 SILC_TASK_PRI_NORMAL);
815 return;
816 }
817
818 SILC_LOG_DEBUG(("Connection to router %s:%d established", sconn->remote_host,
819 sconn->remote_port));
820
821 /* Continue with key exchange protocol */
822 silc_server_start_key_exchange(server, sconn, sock);
823 }
824
825
826 /* Timeout task callback to connect to remote router */
827
828 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
829 {
830 SilcServer server = app_context;
831 SilcServerConnection sconn = (SilcServerConnection)context;
832 int sock;
833 const char *server_ip;
834
835 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
836 sconn->remote_port));
837
838 /* Connect to remote host */
839 server_ip = server->config->server_info->primary == NULL ? NULL :
840 server->config->server_info->primary->server_ip;
841 sock = silc_net_create_connection_async(server_ip, sconn->remote_port,
842 sconn->remote_host);
843 if (sock < 0) {
844 if (server->server_type == SILC_SERVER) {
845 sconn->retry_count++;
846 if (sconn->retry_count > 3) {
847 silc_free(sconn->remote_host);
848 silc_free(sconn);
849 return;
850 }
851 }
852 silc_schedule_task_add(server->schedule, 0,
853 silc_server_backup_connect_to_router,
854 context, 10, 0, SILC_TASK_TIMEOUT,
855 SILC_TASK_PRI_NORMAL);
856 return;
857 }
858
859 /* wait for the connection to be established */
860 silc_schedule_task_add(server->schedule, sock,
861 silc_server_backup_connection_established,
862 context, 0, 0, SILC_TASK_FD,
863 SILC_TASK_PRI_NORMAL);
864 silc_schedule_set_listen_fd(server->schedule, sock,
865 SILC_TASK_WRITE, FALSE);
866 }
867
868 /* Constantly tries to reconnect to a primary router indicated by the
869 `ip' and `port'. The `connected' callback will be called when the
870 connection is created. */
871
872 void silc_server_backup_reconnect(SilcServer server,
873 const char *ip, SilcUInt16 port,
874 SilcServerConnectRouterCallback callback,
875 void *context)
876 {
877 SilcServerConnection sconn;
878
879 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
880
881 sconn = silc_calloc(1, sizeof(*sconn));
882 sconn->remote_host = strdup(ip);
883 sconn->remote_port = port;
884 sconn->callback = callback;
885 sconn->callback_context = context;
886 sconn->no_reconnect = TRUE;
887 sconn->retry_count = 0;
888 silc_schedule_task_add(server->schedule, 0,
889 silc_server_backup_connect_to_router,
890 sconn, 1, 0, SILC_TASK_TIMEOUT,
891 SILC_TASK_PRI_NORMAL);
892 }
893
894 /* Task that is called after backup router has connected back to
895 primary router and we are starting the resuming protocol */
896
897 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
898 {
899 SilcServerBackupProtocolContext proto_ctx =
900 (SilcServerBackupProtocolContext)context;
901 SilcServer server = proto_ctx->server;
902 SilcSocketConnection sock = proto_ctx->sock;
903
904 /* If running other protocol already run this one a bit later. */
905 if (sock->protocol) {
906 SILC_LOG_DEBUG(("Other protocol is running, wait for it to finish"));
907 silc_schedule_task_add(server->schedule, 0,
908 silc_server_backup_connected_later,
909 proto_ctx, 15, 0,
910 SILC_TASK_TIMEOUT,
911 SILC_TASK_PRI_NORMAL);
912 return;
913 }
914
915 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
916 SILC_LOG_INFO(("Starting backup resuming protocol"));
917
918 /* Run the backup resuming protocol */
919 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
920 &sock->protocol, proto_ctx,
921 silc_server_protocol_backup_done);
922 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
923
924 silc_schedule_task_add(server->schedule, sock->sock,
925 silc_server_backup_timeout,
926 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
927 SILC_TASK_PRI_NORMAL);
928 }
929
930 /* Called when we've established connection back to our primary router
931 when we've acting as backup router and have replaced the primary router
932 in the cell. This function will start the backup resuming protocol. */
933
934 void silc_server_backup_connected(SilcServer server,
935 SilcServerEntry server_entry,
936 void *context)
937 {
938 SilcServerBackupProtocolContext proto_ctx;
939 SilcSocketConnection sock;
940
941 if (!server_entry) {
942 /* Try again */
943 SilcServerConfigRouter *primary;
944 primary = silc_server_config_get_primary_router(server);
945 if (primary) {
946 if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
947 primary->host, primary->port))
948 silc_server_backup_reconnect(server,
949 primary->host, primary->port,
950 silc_server_backup_connected,
951 context);
952 }
953 return;
954 }
955
956 sock = (SilcSocketConnection)server_entry->connection;
957 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
958 proto_ctx->server = server;
959 proto_ctx->sock = silc_socket_dup(sock);
960 proto_ctx->responder = FALSE;
961 proto_ctx->type = SILC_SERVER_BACKUP_START;
962 proto_ctx->start = time(0);
963
964 /* Start through scheduler */
965 silc_schedule_task_add(server->schedule, 0,
966 silc_server_backup_connected_later,
967 proto_ctx, 0, 1,
968 SILC_TASK_TIMEOUT,
969 SILC_TASK_PRI_NORMAL);
970 }
971
972 /* Called when normal server has connected to its primary router after
973 backup router has sent the START packet in reusming protocol. We will
974 move the protocol context from the backup router connection to the
975 primary router. */
976
977 static void silc_server_backup_connect_primary(SilcServer server,
978 SilcServerEntry server_entry,
979 void *context)
980 {
981 SilcSocketConnection backup_router = (SilcSocketConnection)context;
982 SilcServerBackupProtocolContext ctx;
983 SilcSocketConnection sock;
984 SilcIDListData idata;
985 unsigned char data[2];
986
987 if (SILC_IS_DISCONNECTING(backup_router) ||
988 SILC_IS_DISCONNECTED(backup_router)) {
989 silc_socket_free(backup_router);
990 return;
991 }
992
993 if (!server_entry) {
994 /* Try again */
995 SilcServerConfigRouter *primary;
996 primary = silc_server_config_get_primary_router(server);
997 if (primary)
998 if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
999 primary->host, primary->port))
1000 silc_server_backup_reconnect(server,
1001 primary->host, primary->port,
1002