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_DEBUG(("Malformed 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_DEBUG(("Bad resume router packet"));
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"));
532 /* Run the backup resuming protocol */
533 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
534 &sock->protocol, proto_ctx,
535 silc_server_protocol_backup_done);
536 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
540 /* Timeout task callback to connect to remote router */
542 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
544 SilcServer server = app_context;
545 SilcServerConnection sconn = (SilcServerConnection)context;
547 const char *server_ip;
549 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
550 sconn->remote_port));
552 /* Connect to remote host */
553 server_ip = server->config->server_info->primary == NULL ? NULL :
554 server->config->server_info->primary->server_ip;
555 sock = silc_net_create_connection(server_ip, sconn->remote_port,
558 silc_schedule_task_add(server->schedule, 0,
559 silc_server_backup_connect_to_router,
560 context, 5, 0, SILC_TASK_TIMEOUT,
561 SILC_TASK_PRI_NORMAL);
565 /* Continue with key exchange protocol */
566 silc_server_start_key_exchange(server, sconn, sock);
569 /* Constantly tries to reconnect to a primary router indicated by the
570 `ip' and `port'. The `connected' callback will be called when the
571 connection is created. */
573 void silc_server_backup_reconnect(SilcServer server,
574 const char *ip, SilcUInt16 port,
575 SilcServerConnectRouterCallback callback,
578 SilcServerConnection sconn;
580 sconn = silc_calloc(1, sizeof(*sconn));
581 sconn->remote_host = strdup(ip);
582 sconn->remote_port = port;
583 sconn->callback = callback;
584 sconn->callback_context = context;
585 sconn->no_reconnect = TRUE;
586 silc_schedule_task_add(server->schedule, 0,
587 silc_server_backup_connect_to_router,
588 sconn, 1, 0, SILC_TASK_TIMEOUT,
589 SILC_TASK_PRI_NORMAL);
592 /* Task that is called after backup router has connected back to
593 primary router and we are starting the resuming protocol */
595 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
597 SilcServerBackupProtocolContext proto_ctx =
598 (SilcServerBackupProtocolContext)context;
599 SilcServer server = proto_ctx->server;
600 SilcSocketConnection sock = proto_ctx->sock;
602 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
604 /* Run the backup resuming protocol */
605 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
606 &sock->protocol, proto_ctx,
607 silc_server_protocol_backup_done);
608 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
611 /* Called when we've established connection back to our primary router
612 when we've acting as backup router and have replaced the primary router
613 in the cell. This function will start the backup resuming protocol. */
615 void silc_server_backup_connected(SilcServer server,
616 SilcServerEntry server_entry,
619 SilcServerBackupProtocolContext proto_ctx;
620 SilcSocketConnection sock;
624 SilcServerConfigRouter *primary;
625 primary = silc_server_config_get_primary_router(server);
627 silc_server_backup_reconnect(server,
628 primary->host, primary->port,
629 silc_server_backup_connected,
634 sock = (SilcSocketConnection)server_entry->connection;
635 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
636 proto_ctx->server = server;
637 proto_ctx->sock = sock;
638 proto_ctx->responder = FALSE;
639 proto_ctx->type = SILC_SERVER_BACKUP_START;
640 proto_ctx->start = time(0);
642 /* Start through scheduler */
643 silc_schedule_task_add(server->schedule, 0,
644 silc_server_backup_connected_later,
647 SILC_TASK_PRI_NORMAL);
650 /* Called when normal server has connected to its primary router after
651 backup router has sent the START packet in reusming protocol. We will
652 move the protocol context from the backup router connection to the
655 static void silc_server_backup_connect_primary(SilcServer server,
656 SilcServerEntry server_entry,
659 SilcSocketConnection backup_router = (SilcSocketConnection)context;
660 SilcServerBackupProtocolContext ctx;
661 SilcSocketConnection sock;
662 SilcIDListData idata;
667 SilcServerConfigRouter *primary;
668 primary = silc_server_config_get_primary_router(server);
670 silc_server_backup_reconnect(server,
671 primary->host, primary->port,
672 silc_server_backup_connect_primary,
677 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
678 sock = (SilcSocketConnection)server_entry->connection;
679 idata = (SilcIDListData)server_entry;
681 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
683 /* Send the CONNECTED packet back to the backup router. */
684 buffer = silc_buffer_alloc(2);
685 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
686 silc_buffer_format(buffer,
687 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
688 SILC_STR_UI_CHAR(ctx->session),
690 silc_server_packet_send(server, backup_router,
691 SILC_PACKET_RESUME_ROUTER, 0,
692 buffer->data, buffer->len, FALSE);
693 silc_buffer_free(buffer);
695 /* The primary connection is disabled until it sends the RESUMED packet
697 idata->status |= SILC_IDLIST_STATUS_DISABLED;
699 /* Move this protocol context from this backup router connection to
700 the primary router connection since it will send the subsequent
701 packets in this protocol. We don't talk with backup router
703 sock->protocol = backup_router->protocol;
704 ctx->sock = (SilcSocketConnection)server_entry->connection;
705 backup_router->protocol = NULL;
708 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
710 SilcProtocol protocol = (SilcProtocol)context;
711 SilcServerBackupProtocolContext ctx = protocol->context;
712 SilcServer server = ctx->server;
716 for (i = 0; i < ctx->sessions_count; i++)
717 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
718 ctx->session = ctx->sessions[i].session;
720 /* We've received all the CONNECTED packets and now we'll send the
721 ENDING packet to the new primary router. */
722 packet = silc_buffer_alloc(2);
723 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
724 silc_buffer_format(packet,
725 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
726 SILC_STR_UI_CHAR(ctx->session),
728 silc_server_packet_send(server, ctx->sock,
729 SILC_PACKET_RESUME_ROUTER, 0,
730 packet->data, packet->len, FALSE);
731 silc_buffer_free(packet);
733 protocol->state = SILC_PROTOCOL_STATE_END;
736 /* Backup resuming protocol. This protocol is executed when the primary
737 router wants to resume its position as being primary router. */
739 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
741 SilcProtocol protocol = (SilcProtocol)context;
742 SilcServerBackupProtocolContext ctx = protocol->context;
743 SilcServer server = ctx->server;
745 SilcIDCacheList list;
746 SilcIDCacheEntry id_cache;
747 SilcServerEntry server_entry;
750 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
751 protocol->state = SILC_PROTOCOL_STATE_START;
753 switch(protocol->state) {
754 case SILC_PROTOCOL_STATE_START:
755 if (ctx->responder == FALSE) {
756 /* Initiator of the protocol. We are backup router */
758 packet = silc_buffer_alloc(2);
759 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
761 /* Send the START packet to primary router and normal servers. */
762 if (silc_idcache_get_all(server->local_list->servers, &list)) {
763 if (silc_idcache_list_first(list, &id_cache)) {
765 server_entry = (SilcServerEntry)id_cache->context;
766 if (!server_entry || (server_entry == server->id_entry) ||
767 !server_entry->connection || !server_entry->data.send_key ||
768 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
769 if (!silc_idcache_list_next(list, &id_cache))
775 ctx->sessions = silc_realloc(ctx->sessions,
776 sizeof(*ctx->sessions) *
777 (ctx->sessions_count + 1));
778 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
779 ctx->sessions[ctx->sessions_count].connected = FALSE;
780 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
782 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
783 server_entry->server_name, ctx->sessions_count));
785 /* This connection is performing this protocol too now */
786 ((SilcSocketConnection)server_entry->connection)->protocol =
789 if (server_entry->server_type == SILC_ROUTER)
790 packet->data[0] = SILC_SERVER_BACKUP_START;
792 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
793 packet->data[1] = ctx->sessions_count;
794 silc_server_packet_send(server, server_entry->connection,
795 SILC_PACKET_RESUME_ROUTER, 0,
796 packet->data, packet->len, FALSE);
797 ctx->sessions_count++;
799 if (!silc_idcache_list_next(list, &id_cache))
804 silc_idcache_list_free(list);
807 if (silc_idcache_get_all(server->global_list->servers, &list)) {
808 if (silc_idcache_list_first(list, &id_cache)) {
810 server_entry = (SilcServerEntry)id_cache->context;
811 if (!server_entry || (server_entry == server->id_entry) ||
812 !server_entry->connection || !server_entry->data.send_key ||
813 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
814 if (!silc_idcache_list_next(list, &id_cache))
820 ctx->sessions = silc_realloc(ctx->sessions,
821 sizeof(*ctx->sessions) *
822 (ctx->sessions_count + 1));
823 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
824 ctx->sessions[ctx->sessions_count].connected = FALSE;
825 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
827 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
828 server_entry->server_name, ctx->sessions_count));
830 /* This connection is performing this protocol too now */
831 ((SilcSocketConnection)server_entry->connection)->protocol =
834 if (server_entry->server_type == SILC_ROUTER)
835 packet->data[0] = SILC_SERVER_BACKUP_START;
837 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
838 packet->data[1] = ctx->sessions_count;
839 silc_server_packet_send(server, server_entry->connection,
840 SILC_PACKET_RESUME_ROUTER, 0,
841 packet->data, packet->len, FALSE);
842 ctx->sessions_count++;
844 if (!silc_idcache_list_next(list, &id_cache))
849 silc_idcache_list_free(list);
852 silc_buffer_free(packet);
854 /* If we are not standalone and our primary is not the one we've
855 talking to now, then announce our information to it since we
856 haven't done that yet. Standalone backup router announces
857 these during connecting to the primary. */
858 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
859 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
860 silc_server_announce_clients(server, 0, ctx->sock);
861 silc_server_announce_channels(server, 0, ctx->sock);
866 /* Responder of the protocol. */
867 SilcServerConfigRouter *primary;
869 /* We should have received START or START_GLOBAL packet */
870 if (ctx->type != SILC_SERVER_BACKUP_START &&
871 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
872 SILC_LOG_DEBUG(("Bad resume router packet"));
876 /* Connect to the primary router that was down that is now supposed
877 to be back online. We send the CONNECTED packet after we've
878 established the connection to the primary router. */
879 primary = silc_server_config_get_primary_router(server);
880 if (primary && server->backup_primary) {
881 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
883 silc_server_backup_reconnect(server,
884 primary->host, primary->port,
885 silc_server_backup_connect_primary,
888 /* Nowhere to connect just return the CONNECTED packet */
889 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
892 /* Send the CONNECTED packet back to the backup router. */
893 packet = silc_buffer_alloc(2);
894 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
895 silc_buffer_format(packet,
896 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
897 SILC_STR_UI_CHAR(ctx->session),
899 silc_server_packet_send(server, ctx->sock,
900 SILC_PACKET_RESUME_ROUTER, 0,
901 packet->data, packet->len, FALSE);
902 silc_buffer_free(packet);
905 if (server->server_type == SILC_ROUTER &&
907 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
910 protocol->state = SILC_PROTOCOL_STATE_END;
912 ctx->sessions = silc_realloc(ctx->sessions,
913 sizeof(*ctx->sessions) *
914 (ctx->sessions_count + 1));
915 ctx->sessions[ctx->sessions_count].session = ctx->session;
916 ctx->sessions_count++;
921 if (ctx->responder == FALSE) {
924 /* We should have received CONNECTED packet */
925 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
926 SILC_LOG_DEBUG(("Bad resume router packet"));
930 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
932 for (i = 0; i < ctx->sessions_count; i++) {
933 if (ctx->sessions[i].session == ctx->session) {
934 ctx->sessions[i].connected = TRUE;
939 for (i = 0; i < ctx->sessions_count; i++) {
940 if (!ctx->sessions[i].connected)
944 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
945 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
947 /* Send with a timeout */
948 silc_schedule_task_add(server->schedule, 0,
949 silc_server_backup_send_resumed,
950 protocol, 1, 0, SILC_TASK_TIMEOUT,
951 SILC_TASK_PRI_NORMAL);
956 /* We should have been received ENDING packet */
957 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
958 SILC_LOG_DEBUG(("Bad resume router packet"));
962 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
964 /* This state is received by the primary router but also servers
965 and perhaps other routers so check that if we are the primary
966 router of the cell then start sending RESUMED packets. If we
967 are normal server or one of those other routers then procede
969 if (server->router &&
970 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
971 silc_server_config_is_primary_route(server)) {
972 /* We'll wait for RESUMED packet */
973 protocol->state = SILC_PROTOCOL_STATE_END;
977 /* Switch announced informations to our primary router of using the
979 silc_server_local_servers_toggle_enabled(server, TRUE);
980 silc_server_update_servers_by_server(server, ctx->sock->user_data,
982 silc_server_update_clients_by_server(server, ctx->sock->user_data,
983 server->router, TRUE);
984 if (server->server_type == SILC_SERVER)
985 silc_server_update_channels_by_server(server, ctx->sock->user_data,
988 packet = silc_buffer_alloc(2);
989 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
991 /* We are the primary router, start sending RESUMED packets. */
992 if (silc_idcache_get_all(server->local_list->servers, &list)) {
993 if (silc_idcache_list_first(list, &id_cache)) {
995 server_entry = (SilcServerEntry)id_cache->context;
996 if (!server_entry || (server_entry == server->id_entry) ||
997 !server_entry->connection || !server_entry->data.send_key) {
998 if (!silc_idcache_list_next(list, &id_cache))
1004 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1005 server_entry->server_name));
1007 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1009 /* This connection is performing this protocol too now */
1010 ((SilcSocketConnection)server_entry->connection)->protocol =
1013 if (server_entry->server_type == SILC_ROUTER)
1014 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1016 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1017 silc_server_packet_send(server, server_entry->connection,
1018 SILC_PACKET_RESUME_ROUTER, 0,
1019 packet->data, packet->len, FALSE);
1021 if (!silc_idcache_list_next(list, &id_cache))
1026 silc_idcache_list_free(list);
1029 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1030 if (silc_idcache_list_first(list, &id_cache)) {
1032 server_entry = (SilcServerEntry)id_cache->context;
1033 if (!server_entry || (server_entry == server->id_entry) ||
1034 !server_entry->connection || !server_entry->data.send_key) {
1035 if (!silc_idcache_list_next(list, &id_cache))
1041 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1042 server_entry->server_name));
1044 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1046 /* This connection is performing this protocol too now */
1047 ((SilcSocketConnection)server_entry->connection)->protocol =
1050 if (server_entry->server_type == SILC_ROUTER)
1051 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1053 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1054 silc_server_packet_send(server, server_entry->connection,
1055 SILC_PACKET_RESUME_ROUTER, 0,
1056 packet->data, packet->len, FALSE);
1058 if (!silc_idcache_list_next(list, &id_cache))
1063 silc_idcache_list_free(list);
1066 silc_buffer_free(packet);
1068 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1069 server->wait_backup = FALSE;
1071 /* For us this is the end of this protocol. */
1072 if (protocol->final_callback)
1073 silc_protocol_execute_final(protocol, server->schedule);
1075 silc_protocol_free(protocol);
1079 case SILC_PROTOCOL_STATE_END:
1081 SilcServerEntry router, backup_router;
1083 /* We should have been received RESUMED packet from our primary
1085 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1086 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1087 SILC_LOG_DEBUG(("Bad resume router packet"));
1091 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1093 if (server->backup_router)
1094 server->server_type = SILC_BACKUP_ROUTER;
1096 /* We have now new primary router. All traffic goes there from now on. */
1097 router = (SilcServerEntry)ctx->sock->user_data;
1098 if (silc_server_backup_replaced_get(server, router->id,
1101 if (backup_router == server->router) {
1102 /* We have new primary router now */
1103 server->id_entry->router = router;
1104 server->router = router;
1105 SILC_LOG_INFO(("Switching back to primary router %s",
1106 server->router->server_name));
1108 /* We are connected to new primary and now continue using it */
1109 SILC_LOG_INFO(("Resuming the use of primary router %s",
1110 router->server_name));
1113 /* Update the client entries of the backup router to the new
1115 silc_server_local_servers_toggle_enabled(server, FALSE);
1116 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1117 silc_server_update_servers_by_server(server, backup_router, router);
1118 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1119 if (server->server_type == SILC_SERVER)
1120 silc_server_update_channels_by_server(server, backup_router, router);
1121 silc_server_backup_replaced_del(server, backup_router);
1123 /* Announce all of our information to the router. */
1124 if (server->server_type == SILC_ROUTER)
1125 silc_server_announce_servers(server, FALSE, ctx->start,
1126 router->connection);
1128 /* Announce our clients and channels to the router */
1129 silc_server_announce_clients(server, ctx->start,
1130 router->connection);
1131 silc_server_announce_channels(server, ctx->start,
1132 router->connection);
1135 /* Send notify about primary router going down to local operators */
1136 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1137 SILC_NOTIFY_TYPE_NONE,
1138 ("%s resumed the use of primary router %s",
1139 server->server_name,
1140 server->router->server_name));
1142 /* Protocol has ended, call the final callback */
1143 if (protocol->final_callback)
1144 silc_protocol_execute_final(protocol, server->schedule);
1146 silc_protocol_free(protocol);
1150 case SILC_PROTOCOL_STATE_ERROR:
1151 /* Protocol has ended, call the final callback */
1152 if (protocol->final_callback)
1153 silc_protocol_execute_final(protocol, server->schedule);
1155 silc_protocol_free(protocol);
1158 case SILC_PROTOCOL_STATE_FAILURE:
1159 /* Protocol has ended, call the final callback */
1160 if (protocol->final_callback)
1161 silc_protocol_execute_final(protocol, server->schedule);
1163 silc_protocol_free(protocol);
1166 case SILC_PROTOCOL_STATE_UNKNOWN:
1171 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1173 SilcProtocol protocol = (SilcProtocol)context;
1174 SilcServerBackupProtocolContext ctx = protocol->context;
1175 SilcServer server = ctx->server;
1176 SilcServerEntry server_entry;
1177 SilcSocketConnection sock;
1178 SilcIDCacheList list;
1179 SilcIDCacheEntry id_cache;
1181 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1182 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1183 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1186 /* Remove this protocol from all server entries that has it */
1187 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1188 if (silc_idcache_list_first(list, &id_cache)) {
1190 server_entry = (SilcServerEntry)id_cache->context;
1191 sock = (SilcSocketConnection)server_entry->connection;
1193 if (sock->protocol == protocol) {
1194 sock->protocol = NULL;
1196 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1197 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1200 if (!silc_idcache_list_next(list, &id_cache))
1204 silc_idcache_list_free(list);
1207 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1208 if (silc_idcache_list_first(list, &id_cache)) {
1210 server_entry = (SilcServerEntry)id_cache->context;
1211 sock = (SilcSocketConnection)server_entry->connection;
1213 if (sock->protocol == protocol) {
1214 sock->protocol = NULL;
1216 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1217 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1220 if (!silc_idcache_list_next(list, &id_cache))
1224 silc_idcache_list_free(list);
1227 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1229 if (ctx->sock->protocol)
1230 ctx->sock->protocol = NULL;
1231 silc_protocol_free(protocol);
1232 silc_free(ctx->sessions);