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 /* Processes incoming RESUME_ROUTER packet. This can give the packet
434 for processing to the protocol handler or allocate new protocol if
435 start command is received. */
437 void silc_server_backup_resume_router(SilcServer server,
438 SilcSocketConnection sock,
439 SilcPacketContext *packet)
441 SilcUInt8 type, session;
442 SilcServerBackupProtocolContext ctx;
445 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
446 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
447 SILC_LOG_DEBUG(("Bad packet received"));
451 ret = silc_buffer_unformat(packet->buffer,
452 SILC_STR_UI_CHAR(&type),
453 SILC_STR_UI_CHAR(&session),
456 SILC_LOG_ERROR(("Malformed resume router packet received"));
460 /* Activate the protocol for this socket if necessary */
461 if ((type == SILC_SERVER_BACKUP_RESUMED ||
462 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
463 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
464 ((SilcIDListData)sock->user_data)->status &
465 SILC_IDLIST_STATUS_DISABLED) {
466 SilcServerEntry backup_router;
468 if (silc_server_backup_replaced_get(server,
469 ((SilcServerEntry)sock->
472 SilcSocketConnection bsock =
473 (SilcSocketConnection)backup_router->connection;
474 if (bsock->protocol && bsock->protocol->protocol &&
475 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
476 sock->protocol = bsock->protocol;
477 ctx = sock->protocol->context;
483 /* If the backup resuming protocol is active then process the packet
485 if (sock->protocol && sock->protocol->protocol &&
486 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
487 ctx = sock->protocol->context;
490 if (type != SILC_SERVER_BACKUP_RESUMED &&
491 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
492 for (i = 0; i < ctx->sessions_count; i++) {
493 if (session == ctx->sessions[i].session) {
494 ctx->session = session;
495 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
500 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
504 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
508 /* We don't have protocol active. If we are router and the packet is
509 coming from our primary router then lets check whether it means we've
510 been replaced by an backup router in my cell. This is usually received
511 immediately after we've connected to our primary router. */
513 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
514 sock && SILC_PRIMARY_ROUTE(server) == sock &&
515 type == SILC_SERVER_BACKUP_REPLACED) {
516 /* We have been replaced by an backup router in our cell. We must
517 mark our primary router connection disabled since we are not allowed
518 to use it at this moment. */
519 SilcIDListData idata = (SilcIDListData)sock->user_data;
520 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
521 "wait until backup resuming protocol is executed"));
522 idata->status |= SILC_IDLIST_STATUS_DISABLED;
526 if (type == SILC_SERVER_BACKUP_START ||
527 type == SILC_SERVER_BACKUP_START_GLOBAL) {
528 /* We have received a start for resuming protocol. */
529 SilcServerBackupProtocolContext proto_ctx;
531 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
532 proto_ctx->server = server;
533 proto_ctx->sock = sock;
534 proto_ctx->responder = TRUE;
535 proto_ctx->type = type;
536 proto_ctx->session = session;
537 proto_ctx->start = time(0);
539 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
540 SILC_LOG_INFO(("Starting backup resuming protocol"));
542 /* Run the backup resuming protocol */
543 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
544 &sock->protocol, proto_ctx,
545 silc_server_protocol_backup_done);
546 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
550 /* Timeout task callback to connect to remote router */
552 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
554 SilcServer server = app_context;
555 SilcServerConnection sconn = (SilcServerConnection)context;
557 const char *server_ip;
559 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
560 sconn->remote_port));
562 /* Connect to remote host */
563 server_ip = server->config->server_info->primary == NULL ? NULL :
564 server->config->server_info->primary->server_ip;
565 sock = silc_net_create_connection(server_ip, sconn->remote_port,
568 silc_schedule_task_add(server->schedule, 0,
569 silc_server_backup_connect_to_router,
570 context, 5, 0, SILC_TASK_TIMEOUT,
571 SILC_TASK_PRI_NORMAL);
575 /* Continue with key exchange protocol */
576 silc_server_start_key_exchange(server, sconn, sock);
579 /* Constantly tries to reconnect to a primary router indicated by the
580 `ip' and `port'. The `connected' callback will be called when the
581 connection is created. */
583 void silc_server_backup_reconnect(SilcServer server,
584 const char *ip, SilcUInt16 port,
585 SilcServerConnectRouterCallback callback,
588 SilcServerConnection sconn;
590 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
592 sconn = silc_calloc(1, sizeof(*sconn));
593 sconn->remote_host = strdup(ip);
594 sconn->remote_port = port;
595 sconn->callback = callback;
596 sconn->callback_context = context;
597 sconn->no_reconnect = TRUE;
598 silc_schedule_task_add(server->schedule, 0,
599 silc_server_backup_connect_to_router,
600 sconn, 1, 0, SILC_TASK_TIMEOUT,
601 SILC_TASK_PRI_NORMAL);
604 /* Task that is called after backup router has connected back to
605 primary router and we are starting the resuming protocol */
607 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
609 SilcServerBackupProtocolContext proto_ctx =
610 (SilcServerBackupProtocolContext)context;
611 SilcServer server = proto_ctx->server;
612 SilcSocketConnection sock = proto_ctx->sock;
614 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
615 SILC_LOG_INFO(("Starting backup resuming protocol"));
617 /* Run the backup resuming protocol */
618 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
619 &sock->protocol, proto_ctx,
620 silc_server_protocol_backup_done);
621 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
624 /* Called when we've established connection back to our primary router
625 when we've acting as backup router and have replaced the primary router
626 in the cell. This function will start the backup resuming protocol. */
628 void silc_server_backup_connected(SilcServer server,
629 SilcServerEntry server_entry,
632 SilcServerBackupProtocolContext proto_ctx;
633 SilcSocketConnection sock;
637 SilcServerConfigRouter *primary;
638 primary = silc_server_config_get_primary_router(server);
640 silc_server_backup_reconnect(server,
641 primary->host, primary->port,
642 silc_server_backup_connected,
647 sock = (SilcSocketConnection)server_entry->connection;
648 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
649 proto_ctx->server = server;
650 proto_ctx->sock = sock;
651 proto_ctx->responder = FALSE;
652 proto_ctx->type = SILC_SERVER_BACKUP_START;
653 proto_ctx->start = time(0);
655 /* Start through scheduler */
656 silc_schedule_task_add(server->schedule, 0,
657 silc_server_backup_connected_later,
660 SILC_TASK_PRI_NORMAL);
663 /* Called when normal server has connected to its primary router after
664 backup router has sent the START packet in reusming protocol. We will
665 move the protocol context from the backup router connection to the
668 static void silc_server_backup_connect_primary(SilcServer server,
669 SilcServerEntry server_entry,
672 SilcSocketConnection backup_router = (SilcSocketConnection)context;
673 SilcServerBackupProtocolContext ctx;
674 SilcSocketConnection sock;
675 SilcIDListData idata;
680 SilcServerConfigRouter *primary;
681 primary = silc_server_config_get_primary_router(server);
683 silc_server_backup_reconnect(server,
684 primary->host, primary->port,
685 silc_server_backup_connect_primary,
690 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
691 sock = (SilcSocketConnection)server_entry->connection;
692 idata = (SilcIDListData)server_entry;
694 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
696 /* Send the CONNECTED packet back to the backup router. */
697 buffer = silc_buffer_alloc(2);
698 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
699 silc_buffer_format(buffer,
700 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
701 SILC_STR_UI_CHAR(ctx->session),
703 silc_server_packet_send(server, backup_router,
704 SILC_PACKET_RESUME_ROUTER, 0,
705 buffer->data, buffer->len, FALSE);
706 silc_buffer_free(buffer);
708 /* The primary connection is disabled until it sends the RESUMED packet
710 idata->status |= SILC_IDLIST_STATUS_DISABLED;
712 /* Move this protocol context from this backup router connection to
713 the primary router connection since it will send the subsequent
714 packets in this protocol. We don't talk with backup router
716 sock->protocol = backup_router->protocol;
717 ctx->sock = (SilcSocketConnection)server_entry->connection;
718 backup_router->protocol = NULL;
721 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
723 SilcProtocol protocol = (SilcProtocol)context;
724 SilcServerBackupProtocolContext ctx = protocol->context;
725 SilcServer server = ctx->server;
729 for (i = 0; i < ctx->sessions_count; i++)
730 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
731 ctx->session = ctx->sessions[i].session;
733 /* We've received all the CONNECTED packets and now we'll send the
734 ENDING packet to the new primary router. */
735 packet = silc_buffer_alloc(2);
736 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
737 silc_buffer_format(packet,
738 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
739 SILC_STR_UI_CHAR(ctx->session),
741 silc_server_packet_send(server, ctx->sock,
742 SILC_PACKET_RESUME_ROUTER, 0,
743 packet->data, packet->len, FALSE);
744 silc_buffer_free(packet);
746 protocol->state = SILC_PROTOCOL_STATE_END;
749 /* Backup resuming protocol. This protocol is executed when the primary
750 router wants to resume its position as being primary router. */
752 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
754 SilcProtocol protocol = (SilcProtocol)context;
755 SilcServerBackupProtocolContext ctx = protocol->context;
756 SilcServer server = ctx->server;
758 SilcIDCacheList list;
759 SilcIDCacheEntry id_cache;
760 SilcServerEntry server_entry;
763 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
764 protocol->state = SILC_PROTOCOL_STATE_START;
766 switch(protocol->state) {
767 case SILC_PROTOCOL_STATE_START:
768 if (ctx->responder == FALSE) {
769 /* Initiator of the protocol. We are backup router */
771 packet = silc_buffer_alloc(2);
772 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
774 /* Send the START packet to primary router and normal servers. */
775 if (silc_idcache_get_all(server->local_list->servers, &list)) {
776 if (silc_idcache_list_first(list, &id_cache)) {
778 server_entry = (SilcServerEntry)id_cache->context;
779 if (!server_entry || (server_entry == server->id_entry) ||
780 !server_entry->connection || !server_entry->data.send_key ||
781 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
782 if (!silc_idcache_list_next(list, &id_cache))
788 ctx->sessions = silc_realloc(ctx->sessions,
789 sizeof(*ctx->sessions) *
790 (ctx->sessions_count + 1));
791 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
792 ctx->sessions[ctx->sessions_count].connected = FALSE;
793 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
795 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
796 server_entry->server_name, ctx->sessions_count));
798 /* This connection is performing this protocol too now */
799 ((SilcSocketConnection)server_entry->connection)->protocol =
802 if (server_entry->server_type == SILC_ROUTER)
803 packet->data[0] = SILC_SERVER_BACKUP_START;
805 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
806 packet->data[1] = ctx->sessions_count;
807 silc_server_packet_send(server, server_entry->connection,
808 SILC_PACKET_RESUME_ROUTER, 0,
809 packet->data, packet->len, FALSE);
810 ctx->sessions_count++;
812 if (!silc_idcache_list_next(list, &id_cache))
817 silc_idcache_list_free(list);
820 if (silc_idcache_get_all(server->global_list->servers, &list)) {
821 if (silc_idcache_list_first(list, &id_cache)) {
823 server_entry = (SilcServerEntry)id_cache->context;
824 if (!server_entry || (server_entry == server->id_entry) ||
825 !server_entry->connection || !server_entry->data.send_key ||
826 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
827 if (!silc_idcache_list_next(list, &id_cache))
833 ctx->sessions = silc_realloc(ctx->sessions,
834 sizeof(*ctx->sessions) *
835 (ctx->sessions_count + 1));
836 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
837 ctx->sessions[ctx->sessions_count].connected = FALSE;
838 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
840 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
841 server_entry->server_name, ctx->sessions_count));
843 /* This connection is performing this protocol too now */
844 ((SilcSocketConnection)server_entry->connection)->protocol =
847 if (server_entry->server_type == SILC_ROUTER)
848 packet->data[0] = SILC_SERVER_BACKUP_START;
850 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
851 packet->data[1] = ctx->sessions_count;
852 silc_server_packet_send(server, server_entry->connection,
853 SILC_PACKET_RESUME_ROUTER, 0,
854 packet->data, packet->len, FALSE);
855 ctx->sessions_count++;
857 if (!silc_idcache_list_next(list, &id_cache))
862 silc_idcache_list_free(list);
865 silc_buffer_free(packet);
867 /* If we are not standalone and our primary is not the one we've
868 talking to now, then announce our information to it since we
869 haven't done that yet. Standalone backup router announces
870 these during connecting to the primary. */
871 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
872 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
873 silc_server_announce_clients(server, 0, ctx->sock);
874 silc_server_announce_channels(server, 0, ctx->sock);
879 /* Responder of the protocol. */
880 SilcServerConfigRouter *primary;
882 /* We should have received START or START_GLOBAL packet */
883 if (ctx->type != SILC_SERVER_BACKUP_START &&
884 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
885 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
889 /* Connect to the primary router that was down that is now supposed
890 to be back online. We send the CONNECTED packet after we've
891 established the connection to the primary router. */
892 primary = silc_server_config_get_primary_router(server);
893 if (primary && server->backup_primary) {
894 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
896 silc_server_backup_reconnect(server,
897 primary->host, primary->port,
898 silc_server_backup_connect_primary,
901 /* Nowhere to connect just return the CONNECTED packet */
902 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
905 /* Send the CONNECTED packet back to the backup router. */
906 packet = silc_buffer_alloc(2);
907 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
908 silc_buffer_format(packet,
909 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
910 SILC_STR_UI_CHAR(ctx->session),
912 silc_server_packet_send(server, ctx->sock,
913 SILC_PACKET_RESUME_ROUTER, 0,
914 packet->data, packet->len, FALSE);
915 silc_buffer_free(packet);
918 if (server->server_type == SILC_ROUTER &&
920 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
923 protocol->state = SILC_PROTOCOL_STATE_END;
925 ctx->sessions = silc_realloc(ctx->sessions,
926 sizeof(*ctx->sessions) *
927 (ctx->sessions_count + 1));
928 ctx->sessions[ctx->sessions_count].session = ctx->session;
929 ctx->sessions_count++;
934 if (ctx->responder == FALSE) {
937 /* We should have received CONNECTED packet */
938 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
939 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
943 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
945 for (i = 0; i < ctx->sessions_count; i++) {
946 if (ctx->sessions[i].session == ctx->session) {
947 ctx->sessions[i].connected = TRUE;
952 for (i = 0; i < ctx->sessions_count; i++) {
953 if (!ctx->sessions[i].connected)
957 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
958 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
960 /* Send with a timeout */
961 silc_schedule_task_add(server->schedule, 0,
962 silc_server_backup_send_resumed,
963 protocol, 1, 0, SILC_TASK_TIMEOUT,
964 SILC_TASK_PRI_NORMAL);
969 /* We should have been received ENDING packet */
970 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
971 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
975 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
977 /* This state is received by the primary router but also servers
978 and perhaps other routers so check that if we are the primary
979 router of the cell then start sending RESUMED packets. If we
980 are normal server or one of those other routers then procede
982 if (server->router &&
983 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
984 silc_server_config_is_primary_route(server)) {
985 /* We'll wait for RESUMED packet */
986 protocol->state = SILC_PROTOCOL_STATE_END;
990 /* Switch announced informations to our primary router of using the
992 silc_server_local_servers_toggle_enabled(server, TRUE);
993 silc_server_update_servers_by_server(server, ctx->sock->user_data,
995 silc_server_update_clients_by_server(server, ctx->sock->user_data,
996 server->router, TRUE);
997 if (server->server_type == SILC_SERVER)
998 silc_server_update_channels_by_server(server, ctx->sock->user_data,
1001 packet = silc_buffer_alloc(2);
1002 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1004 /* We are the primary router, start sending RESUMED packets. */
1005 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1006 if (silc_idcache_list_first(list, &id_cache)) {
1008 server_entry = (SilcServerEntry)id_cache->context;
1009 if (!server_entry || (server_entry == server->id_entry) ||
1010 !server_entry->connection || !server_entry->data.send_key) {
1011 if (!silc_idcache_list_next(list, &id_cache))
1017 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1018 server_entry->server_name));
1020 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1022 /* This connection is performing this protocol too now */
1023 ((SilcSocketConnection)server_entry->connection)->protocol =
1026 if (server_entry->server_type == SILC_ROUTER)
1027 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1029 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1030 silc_server_packet_send(server, server_entry->connection,
1031 SILC_PACKET_RESUME_ROUTER, 0,
1032 packet->data, packet->len, FALSE);
1034 if (!silc_idcache_list_next(list, &id_cache))
1039 silc_idcache_list_free(list);
1042 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1043 if (silc_idcache_list_first(list, &id_cache)) {
1045 server_entry = (SilcServerEntry)id_cache->context;
1046 if (!server_entry || (server_entry == server->id_entry) ||
1047 !server_entry->connection || !server_entry->data.send_key) {
1048 if (!silc_idcache_list_next(list, &id_cache))
1054 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1055 server_entry->server_name));
1057 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1059 /* This connection is performing this protocol too now */
1060 ((SilcSocketConnection)server_entry->connection)->protocol =
1063 if (server_entry->server_type == SILC_ROUTER)
1064 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1066 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1067 silc_server_packet_send(server, server_entry->connection,
1068 SILC_PACKET_RESUME_ROUTER, 0,
1069 packet->data, packet->len, FALSE);
1071 if (!silc_idcache_list_next(list, &id_cache))
1076 silc_idcache_list_free(list);
1079 silc_buffer_free(packet);
1081 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1082 server->wait_backup = FALSE;
1084 /* For us this is the end of this protocol. */
1085 if (protocol->final_callback)
1086 silc_protocol_execute_final(protocol, server->schedule);
1088 silc_protocol_free(protocol);
1092 case SILC_PROTOCOL_STATE_END:
1094 SilcServerEntry router, backup_router;
1096 /* We should have been received RESUMED packet from our primary
1098 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1099 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1100 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1104 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1106 if (server->backup_router)
1107 server->server_type = SILC_BACKUP_ROUTER;
1109 /* We have now new primary router. All traffic goes there from now on. */
1110 router = (SilcServerEntry)ctx->sock->user_data;
1111 if (silc_server_backup_replaced_get(server, router->id,
1114 if (backup_router == server->router) {
1115 /* We have new primary router now */
1116 server->id_entry->router = router;
1117 server->router = router;
1118 SILC_LOG_INFO(("Switching back to primary router %s",
1119 server->router->server_name));
1121 /* We are connected to new primary and now continue using it */
1122 SILC_LOG_INFO(("Resuming the use of primary router %s",
1123 router->server_name));
1126 /* Update the client entries of the backup router to the new
1128 silc_server_local_servers_toggle_enabled(server, FALSE);
1129 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1130 silc_server_update_servers_by_server(server, backup_router, router);
1131 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1132 if (server->server_type == SILC_SERVER)
1133 silc_server_update_channels_by_server(server, backup_router, router);
1134 silc_server_backup_replaced_del(server, backup_router);
1136 /* Announce all of our information to the router. */
1137 if (server->server_type == SILC_ROUTER)
1138 silc_server_announce_servers(server, FALSE, ctx->start,
1139 router->connection);
1141 /* Announce our clients and channels to the router */
1142 silc_server_announce_clients(server, ctx->start,
1143 router->connection);
1144 silc_server_announce_channels(server, ctx->start,
1145 router->connection);
1148 /* Send notify about primary router going down to local operators */
1149 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1150 SILC_NOTIFY_TYPE_NONE,
1151 ("%s resumed the use of primary router %s",
1152 server->server_name,
1153 server->router->server_name));
1155 /* Protocol has ended, call the final callback */
1156 if (protocol->final_callback)
1157 silc_protocol_execute_final(protocol, server->schedule);
1159 silc_protocol_free(protocol);
1163 case SILC_PROTOCOL_STATE_ERROR:
1164 /* Protocol has ended, call the final callback */
1165 if (protocol->final_callback)
1166 silc_protocol_execute_final(protocol, server->schedule);
1168 silc_protocol_free(protocol);
1171 case SILC_PROTOCOL_STATE_FAILURE:
1172 /* Protocol has ended, call the final callback */
1173 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1174 if (protocol->final_callback)
1175 silc_protocol_execute_final(protocol, server->schedule);
1177 silc_protocol_free(protocol);
1180 case SILC_PROTOCOL_STATE_UNKNOWN:
1185 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1187 SilcProtocol protocol = (SilcProtocol)context;
1188 SilcServerBackupProtocolContext ctx = protocol->context;
1189 SilcServer server = ctx->server;
1190 SilcServerEntry server_entry;
1191 SilcSocketConnection sock;
1192 SilcIDCacheList list;
1193 SilcIDCacheEntry id_cache;
1195 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1196 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1197 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1200 /* Remove this protocol from all server entries that has it */
1201 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1202 if (silc_idcache_list_first(list, &id_cache)) {
1204 server_entry = (SilcServerEntry)id_cache->context;
1205 sock = (SilcSocketConnection)server_entry->connection;
1207 if (sock->protocol == protocol) {
1208 sock->protocol = NULL;
1210 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1211 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1214 if (!silc_idcache_list_next(list, &id_cache))
1218 silc_idcache_list_free(list);
1221 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1222 if (silc_idcache_list_first(list, &id_cache)) {
1224 server_entry = (SilcServerEntry)id_cache->context;
1225 sock = (SilcSocketConnection)server_entry->connection;
1227 if (sock->protocol == protocol) {
1228 sock->protocol = NULL;
1230 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1231 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1234 if (!silc_idcache_list_next(list, &id_cache))
1238 silc_idcache_list_free(list);
1241 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1243 if (ctx->sock->protocol)
1244 ctx->sock->protocol = NULL;
1245 silc_protocol_free(protocol);
1246 silc_free(ctx->sessions);