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 memset(server->backup->servers[i].ip.data, 0,
100 sizeof(server->backup->servers[i].ip.data));
101 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
102 sizeof(server->backup->servers[i].ip.data));
107 i = server->backup->servers_count;
108 server->backup->servers = silc_realloc(server->backup->servers,
109 sizeof(*server->backup->servers) *
111 server->backup->servers[i].server = backup_server;
112 server->backup->servers[i].local = local;
113 memset(server->backup->servers[i].ip.data, 0,
114 sizeof(server->backup->servers[i].ip.data));
115 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
116 sizeof(server->backup->servers[i].ip.data));
117 server->backup->servers_count++;
120 /* Returns backup router for IP and port in `replacing' or NULL if there
121 does not exist backup router. */
123 SilcServerEntry silc_server_backup_get(SilcServer server,
124 SilcServerID *server_id)
131 for (i = 0; i < server->backup->servers_count; i++) {
132 if (server->backup->servers[i].server &&
133 !memcmp(&server->backup->servers[i].ip, &server_id->ip.data,
134 sizeof(server_id->ip.data))) {
135 SILC_LOG_DEBUG(("Found backup router %s for %s",
136 server->backup->servers[i].server->server_name,
137 silc_id_render(server_id, SILC_ID_SERVER)));
138 return server->backup->servers[i].server;
145 /* Deletes the backup server `server_entry'. */
147 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
154 for (i = 0; i < server->backup->servers_count; i++) {
155 if (server->backup->servers[i].server == server_entry) {
156 SILC_LOG_DEBUG(("Removing %s as backup router",
157 silc_id_render(server->backup->servers[i].server->id,
159 server->backup->servers[i].server = NULL;
160 memset(server->backup->servers[i].ip.data, 0,
161 sizeof(server->backup->servers[i].ip.data));
166 /* Frees all data allocated for backup routers. Call this after deleting
167 all backup routers and when new routers are added no more, for example
168 when shutting down the server. */
170 void silc_server_backup_free(SilcServer server)
177 /* Delete existing servers if caller didn't do it */
178 for (i = 0; i < server->backup->servers_count; i++) {
179 if (server->backup->servers[i].server)
180 silc_server_backup_del(server, server->backup->servers[i].server);
183 silc_free(server->backup->servers);
184 silc_free(server->backup);
185 server->backup = NULL;
188 /* Marks the IP address and port from the `server_id' as being replaced
189 by backup router indicated by the `server'. If the router connects at
190 a later time we can check whether it has been replaced by an backup
193 void silc_server_backup_replaced_add(SilcServer server,
194 SilcServerID *server_id,
195 SilcServerEntry server_entry)
198 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
201 server->backup = silc_calloc(1, sizeof(*server->backup));
202 if (!server->backup->replaced) {
203 server->backup->replaced =
204 silc_calloc(1, sizeof(*server->backup->replaced));
205 server->backup->replaced_count = 1;
208 SILC_LOG_DEBUG(("Replacing router %s with %s",
209 silc_id_render(server_id, SILC_ID_SERVER),
210 server_entry->server_name));
212 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
213 r->server = server_entry;
215 for (i = 0; i < server->backup->replaced_count; i++) {
216 if (!server->backup->replaced[i]) {
217 server->backup->replaced[i] = r;
222 i = server->backup->replaced_count;
223 server->backup->replaced = silc_realloc(server->backup->replaced,
224 sizeof(*server->backup->replaced) *
226 server->backup->replaced[i] = r;
227 server->backup->replaced_count++;
230 /* Checks whether the IP address and port from the `server_id' has been
231 replaced by an backup router. If it has been then this returns TRUE
232 and the bacup router entry to the `server' pointer if non-NULL. Returns
233 FALSE if the router is not replaced by backup router. */
235 bool silc_server_backup_replaced_get(SilcServer server,
236 SilcServerID *server_id,
237 SilcServerEntry *server_entry)
241 if (!server->backup || !server->backup->replaced)
244 for (i = 0; i < server->backup->replaced_count; i++) {
245 if (!server->backup->replaced[i])
247 if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip.data,
248 sizeof(server_id->ip.data))) {
250 *server_entry = server->backup->replaced[i]->server;
251 SILC_LOG_DEBUG(("Router %s is replaced by %s",
252 silc_id_render(server_id, SILC_ID_SERVER),
253 server->backup->replaced[i]->server->server_name));
258 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
259 silc_id_render(server_id, SILC_ID_SERVER)));
263 /* Deletes a replaced host by the set `server_entry. */
265 void silc_server_backup_replaced_del(SilcServer server,
266 SilcServerEntry server_entry)
270 if (!server->backup || !server->backup->replaced)
273 for (i = 0; i < server->backup->replaced_count; i++) {
274 if (!server->backup->replaced[i])
276 if (server->backup->replaced[i]->server == server_entry) {
277 silc_free(server->backup->replaced[i]);
278 server->backup->replaced[i] = NULL;
284 /* Broadcast the received packet indicated by `packet' to all of our backup
285 routers. All router wide information is passed using broadcast packets.
286 That is why all backup routers need to get this data too. It is expected
287 that the caller already knows that the `packet' is broadcast packet. */
289 void silc_server_backup_broadcast(SilcServer server,
290 SilcSocketConnection sender,
291 SilcPacketContext *packet)
293 SilcServerEntry backup;
294 SilcSocketConnection sock;
296 const SilcBufferStruct p;
297 SilcIDListData idata;
300 if (!server->backup || server->server_type != SILC_ROUTER)
303 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
305 buffer = packet->buffer;
306 silc_buffer_push(buffer, buffer->data - buffer->head);
308 for (i = 0; i < server->backup->servers_count; i++) {
309 backup = server->backup->servers[i].server;
311 if (!backup || backup->connection == sender ||
312 server->backup->servers[i].local == FALSE)
314 if (server->backup->servers[i].server == server->id_entry)
317 idata = (SilcIDListData)backup;
318 sock = backup->connection;
320 if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
321 (const SilcBuffer)&p)) {
322 SILC_LOG_ERROR(("Cannot send packet"));
325 silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
326 silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
327 (SilcBuffer)&p, p.len);
329 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
331 /* Now actually send the packet */
332 silc_server_packet_send_real(server, sock, FALSE);
336 /* A generic routine to send data to all backup routers. If the `sender'
337 is provided it will indicate the original sender of the packet and the
338 packet won't be resent to that entity. The `data' is the data that will
339 be assembled to packet context before sending. The packet will be
340 encrypted this function. If the `force_send' is TRUE the data is sent
341 immediately and not put to queue. If `local' is TRUE then the packet
342 will be sent only to local backup routers inside the cell. If false the
343 packet can go from one cell to the other. This function has no effect
344 if there are no any backup routers. */
346 void silc_server_backup_send(SilcServer server,
347 SilcServerEntry sender,
349 SilcPacketFlags flags,
355 SilcServerEntry backup;
356 SilcSocketConnection sock;
359 if (!server->backup || server->server_type != SILC_ROUTER)
362 for (i = 0; i < server->backup->servers_count; i++) {
363 backup = server->backup->servers[i].server;
364 if (!backup || sender == backup)
366 if (local && server->backup->servers[i].local == FALSE)
368 if (server->backup->servers[i].server == server->id_entry)
371 sock = backup->connection;
373 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
374 silc_get_packet_name(type), sock->hostname, sock->ip));
376 silc_server_packet_send(server, backup->connection, type, flags,
377 data, data_len, force_send);
381 /* Same as silc_server_backup_send but sets a specific Destination ID to
382 the packet. The Destination ID is indicated by the `dst_id' and the
383 ID type `dst_id_type'. For example, packets destined to channels must
384 be sent using this function. */
386 void silc_server_backup_send_dest(SilcServer server,
387 SilcServerEntry sender,
389 SilcPacketFlags flags,
391 SilcIdType dst_id_type,
397 SilcServerEntry backup;
398 SilcSocketConnection sock;
401 if (!server->backup || server->server_type != SILC_ROUTER)
404 for (i = 0; i < server->backup->servers_count; i++) {
405 backup = server->backup->servers[i].server;
406 if (!backup || sender == backup)
408 if (local && server->backup->servers[i].local == FALSE)
410 if (server->backup->servers[i].server == server->id_entry)
413 sock = backup->connection;
415 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
416 silc_get_packet_name(type), sock->hostname, sock->ip));
418 silc_server_packet_send_dest(server, backup->connection, type, flags,
419 dst_id, dst_id_type, data, data_len,
424 /* Processes incoming RESUME_ROUTER packet. This can give the packet
425 for processing to the protocol handler or allocate new protocol if
426 start command is received. */
428 void silc_server_backup_resume_router(SilcServer server,
429 SilcSocketConnection sock,
430 SilcPacketContext *packet)
432 SilcUInt8 type, session;
433 SilcServerBackupProtocolContext ctx;
436 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
437 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
438 SILC_LOG_DEBUG(("Bad packet received"));
442 ret = silc_buffer_unformat(packet->buffer,
443 SILC_STR_UI_CHAR(&type),
444 SILC_STR_UI_CHAR(&session),
447 SILC_LOG_ERROR(("Malformed resume router packet received"));
451 /* Activate the protocol for this socket if necessary */
452 if ((type == SILC_SERVER_BACKUP_RESUMED ||
453 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
454 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
455 ((SilcIDListData)sock->user_data)->status &
456 SILC_IDLIST_STATUS_DISABLED) {
457 SilcServerEntry backup_router;
459 if (silc_server_backup_replaced_get(server,
460 ((SilcServerEntry)sock->
463 SilcSocketConnection bsock =
464 (SilcSocketConnection)backup_router->connection;
465 if (bsock->protocol && bsock->protocol->protocol &&
466 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
467 sock->protocol = bsock->protocol;
468 ctx = sock->protocol->context;
474 /* If the backup resuming protocol is active then process the packet
476 if (sock->protocol && sock->protocol->protocol &&
477 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
478 ctx = sock->protocol->context;
481 if (type != SILC_SERVER_BACKUP_RESUMED &&
482 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
483 for (i = 0; i < ctx->sessions_count; i++) {
484 if (session == ctx->sessions[i].session) {
485 ctx->session = session;
486 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
491 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
495 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
499 /* We don't have protocol active. If we are router and the packet is
500 coming from our primary router then lets check whether it means we've
501 been replaced by an backup router in my cell. This is usually received
502 immediately after we've connected to our primary router. */
504 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
505 sock && SILC_PRIMARY_ROUTE(server) == sock &&
506 type == SILC_SERVER_BACKUP_REPLACED) {
507 /* We have been replaced by an backup router in our cell. We must
508 mark our primary router connection disabled since we are not allowed
509 to use it at this moment. */
510 SilcIDListData idata = (SilcIDListData)sock->user_data;
511 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
512 "wait until backup resuming protocol is executed"));
513 idata->status |= SILC_IDLIST_STATUS_DISABLED;
517 if (type == SILC_SERVER_BACKUP_START ||
518 type == SILC_SERVER_BACKUP_START_GLOBAL) {
519 /* We have received a start for resuming protocol. */
520 SilcServerBackupProtocolContext proto_ctx;
522 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
523 proto_ctx->server = server;
524 proto_ctx->sock = sock;
525 proto_ctx->responder = TRUE;
526 proto_ctx->type = type;
527 proto_ctx->session = session;
528 proto_ctx->start = time(0);
530 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
531 SILC_LOG_INFO(("Starting backup resuming protocol"));
533 /* Run the backup resuming protocol */
534 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
535 &sock->protocol, proto_ctx,
536 silc_server_protocol_backup_done);
537 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
541 /* Timeout task callback to connect to remote router */
543 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
545 SilcServer server = app_context;
546 SilcServerConnection sconn = (SilcServerConnection)context;
548 const char *server_ip;
550 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
551 sconn->remote_port));
553 /* Connect to remote host */
554 server_ip = server->config->server_info->primary == NULL ? NULL :
555 server->config->server_info->primary->server_ip;
556 sock = silc_net_create_connection(server_ip, sconn->remote_port,
559 silc_schedule_task_add(server->schedule, 0,
560 silc_server_backup_connect_to_router,
561 context, 5, 0, SILC_TASK_TIMEOUT,
562 SILC_TASK_PRI_NORMAL);
566 /* Continue with key exchange protocol */
567 silc_server_start_key_exchange(server, sconn, sock);
570 /* Constantly tries to reconnect to a primary router indicated by the
571 `ip' and `port'. The `connected' callback will be called when the
572 connection is created. */
574 void silc_server_backup_reconnect(SilcServer server,
575 const char *ip, SilcUInt16 port,
576 SilcServerConnectRouterCallback callback,
579 SilcServerConnection sconn;
581 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
583 sconn = silc_calloc(1, sizeof(*sconn));
584 sconn->remote_host = strdup(ip);
585 sconn->remote_port = port;
586 sconn->callback = callback;
587 sconn->callback_context = context;
588 sconn->no_reconnect = TRUE;
589 silc_schedule_task_add(server->schedule, 0,
590 silc_server_backup_connect_to_router,
591 sconn, 1, 0, SILC_TASK_TIMEOUT,
592 SILC_TASK_PRI_NORMAL);
595 /* Task that is called after backup router has connected back to
596 primary router and we are starting the resuming protocol */
598 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
600 SilcServerBackupProtocolContext proto_ctx =
601 (SilcServerBackupProtocolContext)context;
602 SilcServer server = proto_ctx->server;
603 SilcSocketConnection sock = proto_ctx->sock;
605 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
606 SILC_LOG_INFO(("Starting backup resuming protocol"));
608 /* Run the backup resuming protocol */
609 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
610 &sock->protocol, proto_ctx,
611 silc_server_protocol_backup_done);
612 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
615 /* Called when we've established connection back to our primary router
616 when we've acting as backup router and have replaced the primary router
617 in the cell. This function will start the backup resuming protocol. */
619 void silc_server_backup_connected(SilcServer server,
620 SilcServerEntry server_entry,
623 SilcServerBackupProtocolContext proto_ctx;
624 SilcSocketConnection sock;
628 SilcServerConfigRouter *primary;
629 primary = silc_server_config_get_primary_router(server);
631 silc_server_backup_reconnect(server,
632 primary->host, primary->port,
633 silc_server_backup_connected,
638 sock = (SilcSocketConnection)server_entry->connection;
639 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
640 proto_ctx->server = server;
641 proto_ctx->sock = sock;
642 proto_ctx->responder = FALSE;
643 proto_ctx->type = SILC_SERVER_BACKUP_START;
644 proto_ctx->start = time(0);
646 /* Start through scheduler */
647 silc_schedule_task_add(server->schedule, 0,
648 silc_server_backup_connected_later,
651 SILC_TASK_PRI_NORMAL);
654 /* Called when normal server has connected to its primary router after
655 backup router has sent the START packet in reusming protocol. We will
656 move the protocol context from the backup router connection to the
659 static void silc_server_backup_connect_primary(SilcServer server,
660 SilcServerEntry server_entry,
663 SilcSocketConnection backup_router = (SilcSocketConnection)context;
664 SilcServerBackupProtocolContext ctx;
665 SilcSocketConnection sock;
666 SilcIDListData idata;
671 SilcServerConfigRouter *primary;
672 primary = silc_server_config_get_primary_router(server);
674 silc_server_backup_reconnect(server,
675 primary->host, primary->port,
676 silc_server_backup_connect_primary,
681 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
682 sock = (SilcSocketConnection)server_entry->connection;
683 idata = (SilcIDListData)server_entry;
685 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
687 /* Send the CONNECTED packet back to the backup router. */
688 buffer = silc_buffer_alloc(2);
689 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
690 silc_buffer_format(buffer,
691 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
692 SILC_STR_UI_CHAR(ctx->session),
694 silc_server_packet_send(server, backup_router,
695 SILC_PACKET_RESUME_ROUTER, 0,
696 buffer->data, buffer->len, FALSE);
697 silc_buffer_free(buffer);
699 /* The primary connection is disabled until it sends the RESUMED packet
701 idata->status |= SILC_IDLIST_STATUS_DISABLED;
703 /* Move this protocol context from this backup router connection to
704 the primary router connection since it will send the subsequent
705 packets in this protocol. We don't talk with backup router
707 sock->protocol = backup_router->protocol;
708 ctx->sock = (SilcSocketConnection)server_entry->connection;
709 backup_router->protocol = NULL;
712 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
714 SilcProtocol protocol = (SilcProtocol)context;
715 SilcServerBackupProtocolContext ctx = protocol->context;
716 SilcServer server = ctx->server;
720 for (i = 0; i < ctx->sessions_count; i++)
721 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
722 ctx->session = ctx->sessions[i].session;
724 /* We've received all the CONNECTED packets and now we'll send the
725 ENDING packet to the new primary router. */
726 packet = silc_buffer_alloc(2);
727 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
728 silc_buffer_format(packet,
729 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
730 SILC_STR_UI_CHAR(ctx->session),
732 silc_server_packet_send(server, ctx->sock,
733 SILC_PACKET_RESUME_ROUTER, 0,
734 packet->data, packet->len, FALSE);
735 silc_buffer_free(packet);
737 protocol->state = SILC_PROTOCOL_STATE_END;
740 /* Backup resuming protocol. This protocol is executed when the primary
741 router wants to resume its position as being primary router. */
743 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
745 SilcProtocol protocol = (SilcProtocol)context;
746 SilcServerBackupProtocolContext ctx = protocol->context;
747 SilcServer server = ctx->server;
749 SilcIDCacheList list;
750 SilcIDCacheEntry id_cache;
751 SilcServerEntry server_entry;
754 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
755 protocol->state = SILC_PROTOCOL_STATE_START;
757 switch(protocol->state) {
758 case SILC_PROTOCOL_STATE_START:
759 if (ctx->responder == FALSE) {
760 /* Initiator of the protocol. We are backup router */
762 packet = silc_buffer_alloc(2);
763 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
765 /* Send the START packet to primary router and normal servers. */
766 if (silc_idcache_get_all(server->local_list->servers, &list)) {
767 if (silc_idcache_list_first(list, &id_cache)) {
769 server_entry = (SilcServerEntry)id_cache->context;
770 if (!server_entry || (server_entry == server->id_entry) ||
771 !server_entry->connection || !server_entry->data.send_key ||
772 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
773 if (!silc_idcache_list_next(list, &id_cache))
779 ctx->sessions = silc_realloc(ctx->sessions,
780 sizeof(*ctx->sessions) *
781 (ctx->sessions_count + 1));
782 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
783 ctx->sessions[ctx->sessions_count].connected = FALSE;
784 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
786 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
787 server_entry->server_name, ctx->sessions_count));
789 /* This connection is performing this protocol too now */
790 ((SilcSocketConnection)server_entry->connection)->protocol =
793 if (server_entry->server_type == SILC_ROUTER)
794 packet->data[0] = SILC_SERVER_BACKUP_START;
796 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
797 packet->data[1] = ctx->sessions_count;
798 silc_server_packet_send(server, server_entry->connection,
799 SILC_PACKET_RESUME_ROUTER, 0,
800 packet->data, packet->len, FALSE);
801 ctx->sessions_count++;
803 if (!silc_idcache_list_next(list, &id_cache))
808 silc_idcache_list_free(list);
811 if (silc_idcache_get_all(server->global_list->servers, &list)) {
812 if (silc_idcache_list_first(list, &id_cache)) {
814 server_entry = (SilcServerEntry)id_cache->context;
815 if (!server_entry || (server_entry == server->id_entry) ||
816 !server_entry->connection || !server_entry->data.send_key ||
817 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
818 if (!silc_idcache_list_next(list, &id_cache))
824 ctx->sessions = silc_realloc(ctx->sessions,
825 sizeof(*ctx->sessions) *
826 (ctx->sessions_count + 1));
827 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
828 ctx->sessions[ctx->sessions_count].connected = FALSE;
829 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
831 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
832 server_entry->server_name, ctx->sessions_count));
834 /* This connection is performing this protocol too now */
835 ((SilcSocketConnection)server_entry->connection)->protocol =
838 if (server_entry->server_type == SILC_ROUTER)
839 packet->data[0] = SILC_SERVER_BACKUP_START;
841 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
842 packet->data[1] = ctx->sessions_count;
843 silc_server_packet_send(server, server_entry->connection,
844 SILC_PACKET_RESUME_ROUTER, 0,
845 packet->data, packet->len, FALSE);
846 ctx->sessions_count++;
848 if (!silc_idcache_list_next(list, &id_cache))
853 silc_idcache_list_free(list);
856 silc_buffer_free(packet);
858 /* If we are not standalone and our primary is not the one we've
859 talking to now, then announce our information to it since we
860 haven't done that yet. Standalone backup router announces
861 these during connecting to the primary. */
862 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
863 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
864 silc_server_announce_clients(server, 0, ctx->sock);
865 silc_server_announce_channels(server, 0, ctx->sock);
870 /* Responder of the protocol. */
871 SilcServerConfigRouter *primary;
873 /* We should have received START or START_GLOBAL packet */
874 if (ctx->type != SILC_SERVER_BACKUP_START &&
875 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
876 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
880 /* Connect to the primary router that was down that is now supposed
881 to be back online. We send the CONNECTED packet after we've
882 established the connection to the primary router. */
883 primary = silc_server_config_get_primary_router(server);
884 if (primary && server->backup_primary) {
885 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
887 silc_server_backup_reconnect(server,
888 primary->host, primary->port,
889 silc_server_backup_connect_primary,
892 /* Nowhere to connect just return the CONNECTED packet */
893 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
896 /* Send the CONNECTED packet back to the backup router. */
897 packet = silc_buffer_alloc(2);
898 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
899 silc_buffer_format(packet,
900 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
901 SILC_STR_UI_CHAR(ctx->session),
903 silc_server_packet_send(server, ctx->sock,
904 SILC_PACKET_RESUME_ROUTER, 0,
905 packet->data, packet->len, FALSE);
906 silc_buffer_free(packet);
909 if (server->server_type == SILC_ROUTER &&
911 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
914 protocol->state = SILC_PROTOCOL_STATE_END;
916 ctx->sessions = silc_realloc(ctx->sessions,
917 sizeof(*ctx->sessions) *
918 (ctx->sessions_count + 1));
919 ctx->sessions[ctx->sessions_count].session = ctx->session;
920 ctx->sessions_count++;
925 if (ctx->responder == FALSE) {
928 /* We should have received CONNECTED packet */
929 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
930 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
934 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
936 for (i = 0; i < ctx->sessions_count; i++) {
937 if (ctx->sessions[i].session == ctx->session) {
938 ctx->sessions[i].connected = TRUE;
943 for (i = 0; i < ctx->sessions_count; i++) {
944 if (!ctx->sessions[i].connected)
948 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
949 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
951 /* Send with a timeout */
952 silc_schedule_task_add(server->schedule, 0,
953 silc_server_backup_send_resumed,
954 protocol, 1, 0, SILC_TASK_TIMEOUT,
955 SILC_TASK_PRI_NORMAL);
960 /* We should have been received ENDING packet */
961 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
962 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
966 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
968 /* This state is received by the primary router but also servers
969 and perhaps other routers so check that if we are the primary
970 router of the cell then start sending RESUMED packets. If we
971 are normal server or one of those other routers then procede
973 if (server->router &&
974 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
975 silc_server_config_is_primary_route(server)) {
976 /* We'll wait for RESUMED packet */
977 protocol->state = SILC_PROTOCOL_STATE_END;
981 /* Switch announced informations to our primary router of using the
983 silc_server_local_servers_toggle_enabled(server, TRUE);
984 silc_server_update_servers_by_server(server, ctx->sock->user_data,
986 silc_server_update_clients_by_server(server, ctx->sock->user_data,
987 server->router, TRUE);
988 if (server->server_type == SILC_SERVER)
989 silc_server_update_channels_by_server(server, ctx->sock->user_data,
992 packet = silc_buffer_alloc(2);
993 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
995 /* We are the primary router, start sending RESUMED packets. */
996 if (silc_idcache_get_all(server->local_list->servers, &list)) {
997 if (silc_idcache_list_first(list, &id_cache)) {
999 server_entry = (SilcServerEntry)id_cache->context;
1000 if (!server_entry || (server_entry == server->id_entry) ||
1001 !server_entry->connection || !server_entry->data.send_key) {
1002 if (!silc_idcache_list_next(list, &id_cache))
1008 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1009 server_entry->server_name));
1011 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1013 /* This connection is performing this protocol too now */
1014 ((SilcSocketConnection)server_entry->connection)->protocol =
1017 if (server_entry->server_type == SILC_ROUTER)
1018 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1020 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1021 silc_server_packet_send(server, server_entry->connection,
1022 SILC_PACKET_RESUME_ROUTER, 0,
1023 packet->data, packet->len, FALSE);
1025 if (!silc_idcache_list_next(list, &id_cache))
1030 silc_idcache_list_free(list);
1033 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1034 if (silc_idcache_list_first(list, &id_cache)) {
1036 server_entry = (SilcServerEntry)id_cache->context;
1037 if (!server_entry || (server_entry == server->id_entry) ||
1038 !server_entry->connection || !server_entry->data.send_key) {
1039 if (!silc_idcache_list_next(list, &id_cache))
1045 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1046 server_entry->server_name));
1048 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1050 /* This connection is performing this protocol too now */
1051 ((SilcSocketConnection)server_entry->connection)->protocol =
1054 if (server_entry->server_type == SILC_ROUTER)
1055 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1057 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1058 silc_server_packet_send(server, server_entry->connection,
1059 SILC_PACKET_RESUME_ROUTER, 0,
1060 packet->data, packet->len, FALSE);
1062 if (!silc_idcache_list_next(list, &id_cache))
1067 silc_idcache_list_free(list);
1070 silc_buffer_free(packet);
1072 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1073 server->wait_backup = FALSE;
1075 /* For us this is the end of this protocol. */
1076 if (protocol->final_callback)
1077 silc_protocol_execute_final(protocol, server->schedule);
1079 silc_protocol_free(protocol);
1083 case SILC_PROTOCOL_STATE_END:
1085 SilcServerEntry router, backup_router;
1087 /* We should have been received RESUMED packet from our primary
1089 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1090 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1091 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1095 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1097 if (server->backup_router)
1098 server->server_type = SILC_BACKUP_ROUTER;
1100 /* We have now new primary router. All traffic goes there from now on. */
1101 router = (SilcServerEntry)ctx->sock->user_data;
1102 if (silc_server_backup_replaced_get(server, router->id,
1105 if (backup_router == server->router) {
1106 /* We have new primary router now */
1107 server->id_entry->router = router;
1108 server->router = router;
1109 SILC_LOG_INFO(("Switching back to primary router %s",
1110 server->router->server_name));
1112 /* We are connected to new primary and now continue using it */
1113 SILC_LOG_INFO(("Resuming the use of primary router %s",
1114 router->server_name));
1117 /* Update the client entries of the backup router to the new
1119 silc_server_local_servers_toggle_enabled(server, FALSE);
1120 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1121 silc_server_update_servers_by_server(server, backup_router, router);
1122 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1123 if (server->server_type == SILC_SERVER)
1124 silc_server_update_channels_by_server(server, backup_router, router);
1125 silc_server_backup_replaced_del(server, backup_router);
1127 /* Announce all of our information to the router. */
1128 if (server->server_type == SILC_ROUTER)
1129 silc_server_announce_servers(server, FALSE, ctx->start,
1130 router->connection);
1132 /* Announce our clients and channels to the router */
1133 silc_server_announce_clients(server, ctx->start,
1134 router->connection);
1135 silc_server_announce_channels(server, ctx->start,
1136 router->connection);
1139 /* Send notify about primary router going down to local operators */
1140 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1141 SILC_NOTIFY_TYPE_NONE,
1142 ("%s resumed the use of primary router %s",
1143 server->server_name,
1144 server->router->server_name));
1146 /* Protocol has ended, call the final callback */
1147 if (protocol->final_callback)
1148 silc_protocol_execute_final(protocol, server->schedule);
1150 silc_protocol_free(protocol);
1154 case SILC_PROTOCOL_STATE_ERROR:
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);
1162 case SILC_PROTOCOL_STATE_FAILURE:
1163 /* Protocol has ended, call the final callback */
1164 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1165 if (protocol->final_callback)
1166 silc_protocol_execute_final(protocol, server->schedule);
1168 silc_protocol_free(protocol);
1171 case SILC_PROTOCOL_STATE_UNKNOWN:
1176 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1178 SilcProtocol protocol = (SilcProtocol)context;
1179 SilcServerBackupProtocolContext ctx = protocol->context;
1180 SilcServer server = ctx->server;
1181 SilcServerEntry server_entry;
1182 SilcSocketConnection sock;
1183 SilcIDCacheList list;
1184 SilcIDCacheEntry id_cache;
1186 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1187 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1188 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1191 /* Remove this protocol from all server entries that has it */
1192 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1193 if (silc_idcache_list_first(list, &id_cache)) {
1195 server_entry = (SilcServerEntry)id_cache->context;
1196 sock = (SilcSocketConnection)server_entry->connection;
1198 if (sock->protocol == protocol) {
1199 sock->protocol = NULL;
1201 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1202 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1205 if (!silc_idcache_list_next(list, &id_cache))
1209 silc_idcache_list_free(list);
1212 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1213 if (silc_idcache_list_first(list, &id_cache)) {
1215 server_entry = (SilcServerEntry)id_cache->context;
1216 sock = (SilcSocketConnection)server_entry->connection;
1218 if (sock->protocol == protocol) {
1219 sock->protocol = NULL;
1221 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1222 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1225 if (!silc_idcache_list_next(list, &id_cache))
1229 silc_idcache_list_free(list);
1232 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1234 if (ctx->sock->protocol)
1235 ctx->sock->protocol = NULL;
1236 silc_protocol_free(protocol);
1237 silc_free(ctx->sessions);