5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2002 Pekka Riikonen
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.
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.
21 #include "serverincludes.h"
22 #include "server_internal.h"
24 SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
25 static void silc_server_backup_connect_primary(SilcServer server,
26 SilcServerEntry server_entry,
31 SilcServerEntry server;
35 } SilcServerBackupEntry;
37 /* Holds IP address and port of the primary router that was replaced
42 SilcServerEntry server; /* Backup router that replaced the primary */
43 } SilcServerBackupReplaced;
46 struct SilcServerBackupStruct {
47 SilcServerBackupEntry *servers;
48 SilcUInt32 servers_count;
49 SilcServerBackupReplaced **replaced;
50 SilcUInt32 replaced_count;
56 SilcServerEntry server_entry;
57 } SilcServerBackupProtocolSession;
59 /* Backup resuming protocol context */
62 SilcSocketConnection sock;
66 SilcServerBackupProtocolSession *sessions;
67 SilcUInt32 sessions_count;
69 } *SilcServerBackupProtocolContext;
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. */
77 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
78 const char *ip, int port, bool local)
85 if (!server->backup) {
86 server->backup = silc_calloc(1, sizeof(*server->backup));
91 SILC_LOG_DEBUG(("Backup router %s will replace %s",
92 ((SilcSocketConnection)backup_server->connection)->ip,
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));
108 i = server->backup->servers_count;
109 server->backup->servers = silc_realloc(server->backup->servers,
110 sizeof(*server->backup->servers) *
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++;
122 /* Returns backup router for IP and port in `replacing' or NULL if there
123 does not exist backup router. */
125 SilcServerEntry silc_server_backup_get(SilcServer server,
126 SilcServerID *server_id)
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;
148 /* Deletes the backup server `server_entry'. */
150 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
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,
162 server->backup->servers[i].server = NULL;
163 memset(server->backup->servers[i].ip.data, 0,
164 sizeof(server->backup->servers[i].ip.data));
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. */
173 void silc_server_backup_free(SilcServer server)
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);
186 silc_free(server->backup->servers);
187 silc_free(server->backup);
188 server->backup = NULL;
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
196 void silc_server_backup_replaced_add(SilcServer server,
197 SilcServerID *server_id,
198 SilcServerEntry server_entry)
201 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
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;
211 SILC_LOG_DEBUG(("Replacing router %s with %s",
212 silc_id_render(server_id, SILC_ID_SERVER),
213 server_entry->server_name));
215 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
216 r->server = server_entry;
218 for (i = 0; i < server->backup->replaced_count; i++) {
219 if (!server->backup->replaced[i]) {
220 server->backup->replaced[i] = r;
225 i = server->backup->replaced_count;
226 server->backup->replaced = silc_realloc(server->backup->replaced,
227 sizeof(*server->backup->replaced) *
229 server->backup->replaced[i] = r;
230 server->backup->replaced_count++;
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. */
238 bool silc_server_backup_replaced_get(SilcServer server,
239 SilcServerID *server_id,
240 SilcServerEntry *server_entry)
244 if (!server->backup || !server->backup->replaced)
247 for (i = 0; i < server->backup->replaced_count; i++) {
248 if (!server->backup->replaced[i])
250 if (!memcmp(server->backup->replaced[i]->ip.data, server_id->ip.data,
251 sizeof(server_id->ip.data))) {
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));
261 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
262 silc_id_render(server_id, SILC_ID_SERVER)));
266 /* Deletes a replaced host by the set `server_entry. */
268 void silc_server_backup_replaced_del(SilcServer server,
269 SilcServerEntry server_entry)
273 if (!server->backup || !server->backup->replaced)
276 for (i = 0; i < server->backup->replaced_count; i++) {
277 if (!server->backup->replaced[i])
279 if (server->backup->replaced[i]->server == server_entry) {
280 silc_free(server->backup->replaced[i]);
281 server->backup->replaced[i] = NULL;
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. */
292 void silc_server_backup_broadcast(SilcServer server,
293 SilcSocketConnection sender,
294 SilcPacketContext *packet)
296 SilcServerEntry backup;
297 SilcSocketConnection sock;
299 const SilcBufferStruct p;
300 SilcIDListData idata;
303 if (!server->backup || server->server_type != SILC_ROUTER)
306 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
308 buffer = packet->buffer;
309 silc_buffer_push(buffer, buffer->data - buffer->head);
311 for (i = 0; i < server->backup->servers_count; i++) {
312 backup = server->backup->servers[i].server;
314 if (!backup || backup->connection == sender ||
315 server->backup->servers[i].local == FALSE)
317 if (server->backup->servers[i].server == server->id_entry)
320 idata = (SilcIDListData)backup;
321 sock = backup->connection;
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"));
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);
332 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
334 /* Now actually send the packet */
335 silc_server_packet_send_real(server, sock, FALSE);
337 /* Check for mandatory rekey */
338 if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
339 silc_schedule_task_add(server->schedule, sender->sock,
340 silc_server_rekey_callback, sender, 0, 1,
341 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
345 /* A generic routine to send data to all backup routers. If the `sender'
346 is provided it will indicate the original sender of the packet and the
347 packet won't be resent to that entity. The `data' is the data that will
348 be assembled to packet context before sending. The packet will be
349 encrypted this function. If the `force_send' is TRUE the data is sent
350 immediately and not put to queue. If `local' is TRUE then the packet
351 will be sent only to local backup routers inside the cell. If false the
352 packet can go from one cell to the other. This function has no effect
353 if there are no any backup routers. */
355 void silc_server_backup_send(SilcServer server,
356 SilcServerEntry sender,
358 SilcPacketFlags flags,
364 SilcServerEntry backup;
365 SilcSocketConnection sock;
368 if (!server->backup || server->server_type != SILC_ROUTER)
371 for (i = 0; i < server->backup->servers_count; i++) {
372 backup = server->backup->servers[i].server;
373 if (!backup || sender == backup)
375 if (local && server->backup->servers[i].local == FALSE)
377 if (server->backup->servers[i].server == server->id_entry)
380 sock = backup->connection;
382 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
383 silc_get_packet_name(type), sock->hostname, sock->ip));
385 silc_server_packet_send(server, backup->connection, type, flags,
386 data, data_len, force_send);
390 /* Same as silc_server_backup_send but sets a specific Destination ID to
391 the packet. The Destination ID is indicated by the `dst_id' and the
392 ID type `dst_id_type'. For example, packets destined to channels must
393 be sent using this function. */
395 void silc_server_backup_send_dest(SilcServer server,
396 SilcServerEntry sender,
398 SilcPacketFlags flags,
400 SilcIdType dst_id_type,
406 SilcServerEntry backup;
407 SilcSocketConnection sock;
410 if (!server->backup || server->server_type != SILC_ROUTER)
413 for (i = 0; i < server->backup->servers_count; i++) {
414 backup = server->backup->servers[i].server;
415 if (!backup || sender == backup)
417 if (local && server->backup->servers[i].local == FALSE)
419 if (server->backup->servers[i].server == server->id_entry)
422 sock = backup->connection;
424 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
425 silc_get_packet_name(type), sock->hostname, sock->ip));
427 silc_server_packet_send_dest(server, backup->connection, type, flags,
428 dst_id, dst_id_type, data, data_len,
433 SILC_TASK_CALLBACK(silc_server_backup_timeout)
435 SilcProtocol protocol = context;
436 SilcServer server = app_context;
438 SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
439 silc_protocol_cancel(protocol, server->schedule);
440 protocol->state = SILC_PROTOCOL_STATE_ERROR;
441 silc_protocol_execute_final(protocol, server->schedule);
444 /* Processes incoming RESUME_ROUTER packet. This can give the packet
445 for processing to the protocol handler or allocate new protocol if
446 start command is received. */
448 void silc_server_backup_resume_router(SilcServer server,
449 SilcSocketConnection sock,
450 SilcPacketContext *packet)
452 SilcUInt8 type, session;
453 SilcServerBackupProtocolContext ctx;
456 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
457 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
458 SILC_LOG_DEBUG(("Bad packet received"));
462 ret = silc_buffer_unformat(packet->buffer,
463 SILC_STR_UI_CHAR(&type),
464 SILC_STR_UI_CHAR(&session),
467 SILC_LOG_ERROR(("Malformed resume router packet received"));
471 /* Activate the protocol for this socket if necessary */
472 if ((type == SILC_SERVER_BACKUP_RESUMED ||
473 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
474 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
475 ((SilcIDListData)sock->user_data)->status &
476 SILC_IDLIST_STATUS_DISABLED) {
477 SilcServerEntry backup_router;
479 if (silc_server_backup_replaced_get(server,
480 ((SilcServerEntry)sock->
483 SilcSocketConnection bsock =
484 (SilcSocketConnection)backup_router->connection;
485 if (bsock->protocol && bsock->protocol->protocol &&
486 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
487 sock->protocol = bsock->protocol;
488 ctx = sock->protocol->context;
494 /* If the backup resuming protocol is active then process the packet
496 if (sock->protocol && sock->protocol->protocol &&
497 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
498 ctx = sock->protocol->context;
501 if (type != SILC_SERVER_BACKUP_RESUMED &&
502 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
503 for (i = 0; i < ctx->sessions_count; i++) {
504 if (session == ctx->sessions[i].session) {
505 ctx->session = session;
506 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
511 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
515 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
519 /* We don't have protocol active. If we are router and the packet is
520 coming from our primary router then lets check whether it means we've
521 been replaced by an backup router in my cell. This is usually received
522 immediately after we've connected to our primary router. */
524 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
525 sock && SILC_PRIMARY_ROUTE(server) == sock &&
526 type == SILC_SERVER_BACKUP_REPLACED) {
527 /* We have been replaced by an backup router in our cell. We must
528 mark our primary router connection disabled since we are not allowed
529 to use it at this moment. */
530 SilcIDListData idata = (SilcIDListData)sock->user_data;
531 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
532 "wait until backup resuming protocol is executed"));
533 idata->status |= SILC_IDLIST_STATUS_DISABLED;
537 if (type == SILC_SERVER_BACKUP_START ||
538 type == SILC_SERVER_BACKUP_START_GLOBAL) {
539 /* We have received a start for resuming protocol. */
540 SilcServerBackupProtocolContext proto_ctx;
542 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
543 proto_ctx->server = server;
544 proto_ctx->sock = sock;
545 proto_ctx->responder = TRUE;
546 proto_ctx->type = type;
547 proto_ctx->session = session;
548 proto_ctx->start = time(0);
550 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
551 SILC_LOG_INFO(("Starting backup resuming protocol"));
553 /* Run the backup resuming protocol */
554 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
555 &sock->protocol, proto_ctx,
556 silc_server_protocol_backup_done);
557 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
558 silc_schedule_task_add(server->schedule, sock->sock,
559 silc_server_backup_timeout,
560 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
561 SILC_TASK_PRI_NORMAL);
565 /* Timeout task callback to connect to remote router */
567 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
569 SilcServer server = app_context;
570 SilcServerConnection sconn = (SilcServerConnection)context;
572 const char *server_ip;
574 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
575 sconn->remote_port));
577 /* Connect to remote host */
578 server_ip = server->config->server_info->primary == NULL ? NULL :
579 server->config->server_info->primary->server_ip;
580 sock = silc_net_create_connection(server_ip, sconn->remote_port,
583 silc_schedule_task_add(server->schedule, 0,
584 silc_server_backup_connect_to_router,
585 context, 5, 0, SILC_TASK_TIMEOUT,
586 SILC_TASK_PRI_NORMAL);
590 /* Continue with key exchange protocol */
591 silc_server_start_key_exchange(server, sconn, sock);
594 /* Constantly tries to reconnect to a primary router indicated by the
595 `ip' and `port'. The `connected' callback will be called when the
596 connection is created. */
598 void silc_server_backup_reconnect(SilcServer server,
599 const char *ip, SilcUInt16 port,
600 SilcServerConnectRouterCallback callback,
603 SilcServerConnection sconn;
605 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
607 sconn = silc_calloc(1, sizeof(*sconn));
608 sconn->remote_host = strdup(ip);
609 sconn->remote_port = port;
610 sconn->callback = callback;
611 sconn->callback_context = context;
612 sconn->no_reconnect = TRUE;
613 silc_schedule_task_add(server->schedule, 0,
614 silc_server_backup_connect_to_router,
615 sconn, 1, 0, SILC_TASK_TIMEOUT,
616 SILC_TASK_PRI_NORMAL);
619 /* Task that is called after backup router has connected back to
620 primary router and we are starting the resuming protocol */
622 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
624 SilcServerBackupProtocolContext proto_ctx =
625 (SilcServerBackupProtocolContext)context;
626 SilcServer server = proto_ctx->server;
627 SilcSocketConnection sock = proto_ctx->sock;
629 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
630 SILC_LOG_INFO(("Starting backup resuming protocol"));
632 /* Run the backup resuming protocol */
633 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
634 &sock->protocol, proto_ctx,
635 silc_server_protocol_backup_done);
636 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
638 silc_schedule_task_add(server->schedule, sock->sock,
639 silc_server_backup_timeout,
640 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
641 SILC_TASK_PRI_NORMAL);
644 /* Called when we've established connection back to our primary router
645 when we've acting as backup router and have replaced the primary router
646 in the cell. This function will start the backup resuming protocol. */
648 void silc_server_backup_connected(SilcServer server,
649 SilcServerEntry server_entry,
652 SilcServerBackupProtocolContext proto_ctx;
653 SilcSocketConnection sock;
657 SilcServerConfigRouter *primary;
658 primary = silc_server_config_get_primary_router(server);
660 silc_server_backup_reconnect(server,
661 primary->host, primary->port,
662 silc_server_backup_connected,
667 sock = (SilcSocketConnection)server_entry->connection;
668 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
669 proto_ctx->server = server;
670 proto_ctx->sock = sock;
671 proto_ctx->responder = FALSE;
672 proto_ctx->type = SILC_SERVER_BACKUP_START;
673 proto_ctx->start = time(0);
675 /* Start through scheduler */
676 silc_schedule_task_add(server->schedule, 0,
677 silc_server_backup_connected_later,
680 SILC_TASK_PRI_NORMAL);
683 /* Called when normal server has connected to its primary router after
684 backup router has sent the START packet in reusming protocol. We will
685 move the protocol context from the backup router connection to the
688 static void silc_server_backup_connect_primary(SilcServer server,
689 SilcServerEntry server_entry,
692 SilcSocketConnection backup_router = (SilcSocketConnection)context;
693 SilcServerBackupProtocolContext ctx;
694 SilcSocketConnection sock;
695 SilcIDListData idata;
700 SilcServerConfigRouter *primary;
701 primary = silc_server_config_get_primary_router(server);
703 silc_server_backup_reconnect(server,
704 primary->host, primary->port,
705 silc_server_backup_connect_primary,
710 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
711 sock = (SilcSocketConnection)server_entry->connection;
712 idata = (SilcIDListData)server_entry;
714 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
715 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
718 /* Send the CONNECTED packet back to the backup router. */
719 buffer = silc_buffer_alloc(2);
720 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
721 silc_buffer_format(buffer,
722 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
723 SILC_STR_UI_CHAR(ctx->session),
725 silc_server_packet_send(server, backup_router,
726 SILC_PACKET_RESUME_ROUTER, 0,
727 buffer->data, buffer->len, FALSE);
728 silc_buffer_free(buffer);
730 /* The primary connection is disabled until it sends the RESUMED packet
732 idata->status |= SILC_IDLIST_STATUS_DISABLED;
734 /* Move this protocol context from this backup router connection to
735 the primary router connection since it will send the subsequent
736 packets in this protocol. We don't talk with backup router
738 sock->protocol = backup_router->protocol;
739 ctx->sock = (SilcSocketConnection)server_entry->connection;
740 backup_router->protocol = NULL;
743 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
745 SilcProtocol protocol = (SilcProtocol)context;
746 SilcServerBackupProtocolContext ctx = protocol->context;
747 SilcServer server = ctx->server;
751 for (i = 0; i < ctx->sessions_count; i++)
752 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
753 ctx->session = ctx->sessions[i].session;
755 /* We've received all the CONNECTED packets and now we'll send the
756 ENDING packet to the new primary router. */
757 packet = silc_buffer_alloc(2);
758 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
759 silc_buffer_format(packet,
760 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
761 SILC_STR_UI_CHAR(ctx->session),
763 silc_server_packet_send(server, ctx->sock,
764 SILC_PACKET_RESUME_ROUTER, 0,
765 packet->data, packet->len, FALSE);
766 silc_buffer_free(packet);
768 protocol->state = SILC_PROTOCOL_STATE_END;
771 /* Backup resuming protocol. This protocol is executed when the primary
772 router wants to resume its position as being primary router. */
774 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
776 SilcProtocol protocol = (SilcProtocol)context;
777 SilcServerBackupProtocolContext ctx = protocol->context;
778 SilcServer server = ctx->server;
780 SilcIDCacheList list;
781 SilcIDCacheEntry id_cache;
782 SilcServerEntry server_entry;
785 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
786 protocol->state = SILC_PROTOCOL_STATE_START;
788 switch(protocol->state) {
789 case SILC_PROTOCOL_STATE_START:
790 if (ctx->responder == FALSE) {
791 /* Initiator of the protocol. We are backup router */
793 packet = silc_buffer_alloc(2);
794 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
796 /* Send the START packet to primary router and normal servers. */
797 if (silc_idcache_get_all(server->local_list->servers, &list)) {
798 if (silc_idcache_list_first(list, &id_cache)) {
800 server_entry = (SilcServerEntry)id_cache->context;
801 if (!server_entry || (server_entry == server->id_entry) ||
802 !server_entry->connection || !server_entry->data.send_key ||
803 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
804 if (!silc_idcache_list_next(list, &id_cache))
810 ctx->sessions = silc_realloc(ctx->sessions,
811 sizeof(*ctx->sessions) *
812 (ctx->sessions_count + 1));
813 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
814 ctx->sessions[ctx->sessions_count].connected = FALSE;
815 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
817 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
818 server_entry->server_name, ctx->sessions_count));
819 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
820 server_entry->server_name, ctx->sessions_count));
822 /* This connection is performing this protocol too now */
823 ((SilcSocketConnection)server_entry->connection)->protocol =
826 if (server_entry->server_type == SILC_ROUTER)
827 packet->data[0] = SILC_SERVER_BACKUP_START;
829 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
830 packet->data[1] = ctx->sessions_count;
831 silc_server_packet_send(server, server_entry->connection,
832 SILC_PACKET_RESUME_ROUTER, 0,
833 packet->data, packet->len, FALSE);
834 ctx->sessions_count++;
836 if (!silc_idcache_list_next(list, &id_cache))
841 silc_idcache_list_free(list);
844 if (silc_idcache_get_all(server->global_list->servers, &list)) {
845 if (silc_idcache_list_first(list, &id_cache)) {
847 server_entry = (SilcServerEntry)id_cache->context;
848 if (!server_entry || (server_entry == server->id_entry) ||
849 !server_entry->connection || !server_entry->data.send_key ||
850 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
851 if (!silc_idcache_list_next(list, &id_cache))
857 ctx->sessions = silc_realloc(ctx->sessions,
858 sizeof(*ctx->sessions) *
859 (ctx->sessions_count + 1));
860 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
861 ctx->sessions[ctx->sessions_count].connected = FALSE;
862 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
864 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
865 server_entry->server_name, ctx->sessions_count));
866 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
867 server_entry->server_name, ctx->sessions_count));
869 /* This connection is performing this protocol too now */
870 ((SilcSocketConnection)server_entry->connection)->protocol =
873 if (server_entry->server_type == SILC_ROUTER)
874 packet->data[0] = SILC_SERVER_BACKUP_START;
876 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
877 packet->data[1] = ctx->sessions_count;
878 silc_server_packet_send(server, server_entry->connection,
879 SILC_PACKET_RESUME_ROUTER, 0,
880 packet->data, packet->len, FALSE);
881 ctx->sessions_count++;
883 if (!silc_idcache_list_next(list, &id_cache))
888 silc_idcache_list_free(list);
891 silc_buffer_free(packet);
893 /* If we are not standalone and our primary is not the one we've
894 talking to now, then announce our information to it since we
895 haven't done that yet. Standalone backup router announces
896 these during connecting to the primary. */
897 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
898 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
899 silc_server_announce_clients(server, 0, ctx->sock);
900 silc_server_announce_channels(server, 0, ctx->sock);
905 /* Responder of the protocol. */
906 SilcServerConfigRouter *primary;
908 /* We should have received START or START_GLOBAL packet */
909 if (ctx->type != SILC_SERVER_BACKUP_START &&
910 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
911 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
915 /* Connect to the primary router that was down that is now supposed
916 to be back online. We send the CONNECTED packet after we've
917 established the connection to the primary router. */
918 primary = silc_server_config_get_primary_router(server);
919 if (primary && server->backup_primary &&
920 !silc_server_num_sockets_by_remote(server,
921 silc_net_is_ip(primary->host) ?
922 primary->host : NULL,
923 silc_net_is_ip(primary->host) ?
924 NULL : primary->host,
926 SILC_SOCKET_TYPE_ROUTER)) {
927 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
929 silc_server_backup_reconnect(server,
930 primary->host, primary->port,
931 silc_server_backup_connect_primary,
934 /* Nowhere to connect just return the CONNECTED packet */
935 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
937 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
940 /* Send the CONNECTED packet back to the backup router. */
941 packet = silc_buffer_alloc(2);
942 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
943 silc_buffer_format(packet,
944 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
945 SILC_STR_UI_CHAR(ctx->session),
947 silc_server_packet_send(server, ctx->sock,
948 SILC_PACKET_RESUME_ROUTER, 0,
949 packet->data, packet->len, FALSE);
950 silc_buffer_free(packet);
953 if (server->server_type == SILC_ROUTER &&
955 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
958 protocol->state = SILC_PROTOCOL_STATE_END;
960 ctx->sessions = silc_realloc(ctx->sessions,
961 sizeof(*ctx->sessions) *
962 (ctx->sessions_count + 1));
963 ctx->sessions[ctx->sessions_count].session = ctx->session;
964 ctx->sessions_count++;
969 if (ctx->responder == FALSE) {
972 /* We should have received CONNECTED packet */
973 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
974 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
978 for (i = 0; i < ctx->sessions_count; i++) {
979 if (ctx->sessions[i].session == ctx->session) {
980 ctx->sessions[i].connected = TRUE;
981 SILC_LOG_INFO(("Received CONNECTED from %s (session %d)",
982 ctx->sessions[i].server_entry->server_name,
984 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
989 for (i = 0; i < ctx->sessions_count; i++) {
990 if (!ctx->sessions[i].connected)
994 SILC_LOG_INFO(("All sessions have returned CONNECTED packets, "
996 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
998 /* Send with a timeout */
999 silc_schedule_task_add(server->schedule, 0,
1000 silc_server_backup_send_resumed,
1001 protocol, 1, 0, SILC_TASK_TIMEOUT,
1002 SILC_TASK_PRI_NORMAL);
1007 /* We should have been received ENDING packet */
1008 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
1009 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
1013 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
1015 /* This state is received by the primary router but also servers
1016 and perhaps other routers so check that if we are the primary
1017 router of the cell then start sending RESUMED packets. If we
1018 are normal server or one of those other routers then procede
1020 if (server->router &&
1021 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
1022 silc_server_config_is_primary_route(server)) {
1023 /* We'll wait for RESUMED packet */
1024 protocol->state = SILC_PROTOCOL_STATE_END;
1028 /* Switch announced informations to our primary router of using the
1030 silc_server_local_servers_toggle_enabled(server, TRUE);
1031 silc_server_update_servers_by_server(server, ctx->sock->user_data,
1033 silc_server_update_clients_by_server(server, ctx->sock->user_data,
1034 server->router, TRUE);
1035 if (server->server_type == SILC_SERVER)
1036 silc_server_update_channels_by_server(server, ctx->sock->user_data,
1039 packet = silc_buffer_alloc(2);
1040 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1042 /* We are the primary router, start sending RESUMED packets. */
1043 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1044 if (silc_idcache_list_first(list, &id_cache)) {
1046 server_entry = (SilcServerEntry)id_cache->context;
1047 if (!server_entry || (server_entry == server->id_entry) ||
1048 !server_entry->connection || !server_entry->data.send_key) {
1049 if (!silc_idcache_list_next(list, &id_cache))
1055 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1056 server_entry->server_name));
1058 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1060 /* This connection is performing this protocol too now */
1061 ((SilcSocketConnection)server_entry->connection)->protocol =
1064 if (server_entry->server_type == SILC_ROUTER)
1065 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1067 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1068 silc_server_packet_send(server, server_entry->connection,
1069 SILC_PACKET_RESUME_ROUTER, 0,
1070 packet->data, packet->len, FALSE);
1072 if (!silc_idcache_list_next(list, &id_cache))
1077 silc_idcache_list_free(list);
1080 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1081 if (silc_idcache_list_first(list, &id_cache)) {
1083 server_entry = (SilcServerEntry)id_cache->context;
1084 if (!server_entry || (server_entry == server->id_entry) ||
1085 !server_entry->connection || !server_entry->data.send_key) {
1086 if (!silc_idcache_list_next(list, &id_cache))
1092 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1093 server_entry->server_name));
1095 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1097 /* This connection is performing this protocol too now */
1098 ((SilcSocketConnection)server_entry->connection)->protocol =
1101 if (server_entry->server_type == SILC_ROUTER)
1102 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1104 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1105 silc_server_packet_send(server, server_entry->connection,
1106 SILC_PACKET_RESUME_ROUTER, 0,
1107 packet->data, packet->len, FALSE);
1109 if (!silc_idcache_list_next(list, &id_cache))
1114 silc_idcache_list_free(list);
1117 silc_buffer_free(packet);
1119 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1120 server->wait_backup = FALSE;
1122 /* For us this is the end of this protocol. */
1123 if (protocol->final_callback)
1124 silc_protocol_execute_final(protocol, server->schedule);
1126 silc_protocol_free(protocol);
1130 case SILC_PROTOCOL_STATE_END:
1132 SilcServerEntry router, backup_router;
1134 /* We should have been received RESUMED packet from our primary
1136 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1137 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1138 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1142 SILC_LOG_INFO(("Received RESUMED from new primary router"));
1144 if (server->backup_router)
1145 server->server_type = SILC_BACKUP_ROUTER;
1147 /* We have now new primary router. All traffic goes there from now on. */
1148 router = (SilcServerEntry)ctx->sock->user_data;
1149 if (silc_server_backup_replaced_get(server, router->id,
1152 if (backup_router == server->router) {
1153 /* We have new primary router now */
1154 server->id_entry->router = router;
1155 server->router = router;
1156 SILC_LOG_INFO(("Switching back to primary router %s",
1157 server->router->server_name));
1159 /* We are connected to new primary and now continue using it */
1160 SILC_LOG_INFO(("Resuming the use of primary router %s",
1161 router->server_name));
1163 server->backup_primary = FALSE;
1165 /* Update the client entries of the backup router to the new
1167 silc_server_local_servers_toggle_enabled(server, FALSE);
1168 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1169 silc_server_update_servers_by_server(server, backup_router, router);
1170 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1171 if (server->server_type == SILC_SERVER)
1172 silc_server_update_channels_by_server(server, backup_router, router);
1173 silc_server_backup_replaced_del(server, backup_router);
1175 /* Announce all of our information to the router. */
1176 if (server->server_type == SILC_ROUTER)
1177 silc_server_announce_servers(server, FALSE, ctx->start,
1178 router->connection);
1180 /* Announce our clients and channels to the router */
1181 silc_server_announce_clients(server, ctx->start,
1182 router->connection);
1183 silc_server_announce_channels(server, ctx->start,
1184 router->connection);
1187 /* Send notify about primary router going down to local operators */
1188 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1189 SILC_NOTIFY_TYPE_NONE,
1190 ("%s resumed the use of primary router %s",
1191 server->server_name,
1192 server->router->server_name));
1194 /* Protocol has ended, call the final callback */
1195 if (protocol->final_callback)
1196 silc_protocol_execute_final(protocol, server->schedule);
1198 silc_protocol_free(protocol);
1202 case SILC_PROTOCOL_STATE_ERROR:
1203 /* Protocol has ended, call the final callback */
1204 if (protocol->final_callback)
1205 silc_protocol_execute_final(protocol, server->schedule);
1207 silc_protocol_free(protocol);
1210 case SILC_PROTOCOL_STATE_FAILURE:
1211 /* Protocol has ended, call the final callback */
1212 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1213 if (protocol->final_callback)
1214 silc_protocol_execute_final(protocol, server->schedule);
1216 silc_protocol_free(protocol);
1219 case SILC_PROTOCOL_STATE_UNKNOWN:
1224 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1226 SilcProtocol protocol = (SilcProtocol)context;
1227 SilcServerBackupProtocolContext ctx = protocol->context;
1228 SilcServer server = ctx->server;
1229 SilcServerEntry server_entry;
1230 SilcSocketConnection sock;
1231 SilcIDCacheList list;
1232 SilcIDCacheEntry id_cache;
1234 silc_schedule_task_del_by_context(server->schedule, protocol);
1236 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1237 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1238 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1241 if (server->server_shutdown)
1244 /* Remove this protocol from all server entries that has it */
1245 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1246 if (silc_idcache_list_first(list, &id_cache)) {
1248 server_entry = (SilcServerEntry)id_cache->context;
1249 sock = (SilcSocketConnection)server_entry->connection;
1251 if (sock->protocol == protocol) {
1252 sock->protocol = NULL;
1254 /* Backup closes connection and reconnects if error occurred */
1255 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1256 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1257 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1258 server->backup_noswitch = TRUE;
1259 server->server_type = SILC_BACKUP_ROUTER;
1261 if (sock->user_data)
1262 silc_server_free_sock_user_data(server, sock, NULL);
1263 silc_server_close_connection(server, sock);
1265 silc_schedule_task_add(server->schedule, 0,
1266 silc_server_connect_to_router,
1269 SILC_TASK_PRI_NORMAL);
1271 if (!silc_idcache_list_next(list, &id_cache))
1277 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1278 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1281 if (!silc_idcache_list_next(list, &id_cache))
1285 silc_idcache_list_free(list);
1288 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1289 if (silc_idcache_list_first(list, &id_cache)) {
1291 server_entry = (SilcServerEntry)id_cache->context;
1292 sock = (SilcSocketConnection)server_entry->connection;
1294 if (sock->protocol == protocol) {
1295 sock->protocol = NULL;
1297 /* Backup closes connection and reconnects if error occurred */
1298 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1299 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1300 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1301 server->backup_noswitch = TRUE;
1302 server->server_type = SILC_BACKUP_ROUTER;
1304 if (sock->user_data)
1305 silc_server_free_sock_user_data(server, sock, NULL);
1306 silc_server_close_connection(server, sock);
1308 silc_schedule_task_add(server->schedule, 0,
1309 silc_server_connect_to_router,
1312 SILC_TASK_PRI_NORMAL);
1314 if (!silc_idcache_list_next(list, &id_cache))
1320 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1321 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1324 if (!silc_idcache_list_next(list, &id_cache))
1328 silc_idcache_list_free(list);
1331 if (protocol->state != SILC_PROTOCOL_STATE_ERROR &&
1332 protocol->state != SILC_PROTOCOL_STATE_FAILURE)
1333 SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
1335 if (ctx->sock->protocol)
1336 ctx->sock->protocol = NULL;
1337 silc_protocol_free(protocol);
1338 silc_free(ctx->sessions);