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 /* Marks the IP address and port from the `server_id' as being replaced
167 by backup router indicated by the `server'. If the router connects at
168 a later time we can check whether it has been replaced by an backup
171 void silc_server_backup_replaced_add(SilcServer server,
172 SilcServerID *server_id,
173 SilcServerEntry server_entry)
176 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
179 server->backup = silc_calloc(1, sizeof(*server->backup));
180 if (!server->backup->replaced) {
181 server->backup->replaced =
182 silc_calloc(1, sizeof(*server->backup->replaced));
183 server->backup->replaced_count = 1;
186 SILC_LOG_DEBUG(("Replacing router %s with %s backup",
187 silc_id_render(server_id, SILC_ID_SERVER),
188 server_entry->server_name));
190 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
191 r->server = server_entry;
193 for (i = 0; i < server->backup->replaced_count; i++) {
194 if (!server->backup->replaced[i]) {
195 server->backup->replaced[i] = r;
200 i = server->backup->replaced_count;
201 server->backup->replaced = silc_realloc(server->backup->replaced,
202 sizeof(*server->backup->replaced) *
204 server->backup->replaced[i] = r;
205 server->backup->replaced_count++;
208 /* Checks whether the IP address and port from the `server_id' has been
209 replaced by an backup router. If it has been then this returns TRUE
210 and the bacup router entry to the `server' pointer if non-NULL. Returns
211 FALSE if the router is not replaced by backup router. */
213 bool silc_server_backup_replaced_get(SilcServer server,
214 SilcServerID *server_id,
215 SilcServerEntry *server_entry)
219 if (!server->backup || !server->backup->replaced)
222 for (i = 0; i < server->backup->replaced_count; i++) {
223 if (!server->backup->replaced[i])
225 if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip.data,
226 sizeof(server_id->ip.data))) {
228 *server_entry = server->backup->replaced[i]->server;
229 SILC_LOG_DEBUG(("Router %s is replaced by %s",
230 silc_id_render(server_id, SILC_ID_SERVER),
231 server->backup->replaced[i]->server->server_name));
236 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
237 silc_id_render(server_id, SILC_ID_SERVER)));
241 /* Deletes a replaced host by the set `server_entry. */
243 void silc_server_backup_replaced_del(SilcServer server,
244 SilcServerEntry server_entry)
248 if (!server->backup || !server->backup->replaced)
251 for (i = 0; i < server->backup->replaced_count; i++) {
252 if (!server->backup->replaced[i])
254 if (server->backup->replaced[i]->server == server_entry) {
255 silc_free(server->backup->replaced[i]);
256 server->backup->replaced[i] = NULL;
262 /* Broadcast the received packet indicated by `packet' to all of our backup
263 routers. All router wide information is passed using broadcast packets.
264 That is why all backup routers need to get this data too. It is expected
265 that the caller already knows that the `packet' is broadcast packet. */
267 void silc_server_backup_broadcast(SilcServer server,
268 SilcSocketConnection sender,
269 SilcPacketContext *packet)
271 SilcServerEntry backup;
272 SilcSocketConnection sock;
274 const SilcBufferStruct p;
275 SilcIDListData idata;
278 if (!server->backup || server->server_type != SILC_ROUTER)
281 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
283 buffer = packet->buffer;
284 silc_buffer_push(buffer, buffer->data - buffer->head);
286 for (i = 0; i < server->backup->servers_count; i++) {
287 backup = server->backup->servers[i].server;
289 if (!backup || backup->connection == sender ||
290 server->backup->servers[i].local == FALSE)
292 if (server->backup->servers[i].server == server->id_entry)
295 idata = (SilcIDListData)backup;
296 sock = backup->connection;
298 if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
299 (const SilcBuffer)&p)) {
300 SILC_LOG_ERROR(("Cannot send packet"));
303 silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
304 silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
305 (SilcBuffer)&p, p.len);
307 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
309 /* Now actually send the packet */
310 silc_server_packet_send_real(server, sock, FALSE);
314 /* A generic routine to send data to all backup routers. If the `sender'
315 is provided it will indicate the original sender of the packet and the
316 packet won't be resent to that entity. The `data' is the data that will
317 be assembled to packet context before sending. The packet will be
318 encrypted this function. If the `force_send' is TRUE the data is sent
319 immediately and not put to queue. If `local' is TRUE then the packet
320 will be sent only to local backup routers inside the cell. If false the
321 packet can go from one cell to the other. This function has no effect
322 if there are no any backup routers. */
324 void silc_server_backup_send(SilcServer server,
325 SilcServerEntry sender,
327 SilcPacketFlags flags,
333 SilcServerEntry backup;
334 SilcSocketConnection sock;
337 if (!server->backup || server->server_type != SILC_ROUTER)
340 for (i = 0; i < server->backup->servers_count; i++) {
341 backup = server->backup->servers[i].server;
345 if (sender == backup)
348 if (local && server->backup->servers[i].local == FALSE)
350 if (server->backup->servers[i].server == server->id_entry)
353 sock = backup->connection;
355 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
356 silc_get_packet_name(type), sock->hostname, sock->ip));
358 silc_server_packet_send(server, backup->connection, type, flags,
359 data, data_len, force_send);
363 /* Same as silc_server_backup_send but sets a specific Destination ID to
364 the packet. The Destination ID is indicated by the `dst_id' and the
365 ID type `dst_id_type'. For example, packets destined to channels must
366 be sent using this function. */
368 void silc_server_backup_send_dest(SilcServer server,
369 SilcServerEntry sender,
371 SilcPacketFlags flags,
373 SilcIdType dst_id_type,
379 SilcServerEntry backup;
380 SilcSocketConnection sock;
383 if (!server->backup || server->server_type != SILC_ROUTER)
386 for (i = 0; i < server->backup->servers_count; i++) {
387 backup = server->backup->servers[i].server;
391 if (sender == backup)
394 if (local && server->backup->servers[i].local == FALSE)
396 if (server->backup->servers[i].server == server->id_entry)
399 sock = backup->connection;
401 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
402 silc_get_packet_name(type), sock->hostname, sock->ip));
404 silc_server_packet_send_dest(server, backup->connection, type, flags,
405 dst_id, dst_id_type, data, data_len,
410 /* Processes incoming RESUME_ROUTER packet. This can give the packet
411 for processing to the protocol handler or allocate new protocol if
412 start command is received. */
414 void silc_server_backup_resume_router(SilcServer server,
415 SilcSocketConnection sock,
416 SilcPacketContext *packet)
418 SilcUInt8 type, session;
419 SilcServerBackupProtocolContext ctx;
422 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
423 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
424 SILC_LOG_DEBUG(("Bad packet received"));
428 ret = silc_buffer_unformat(packet->buffer,
429 SILC_STR_UI_CHAR(&type),
430 SILC_STR_UI_CHAR(&session),
433 SILC_LOG_DEBUG(("Malformed packet received"));
437 /* Activate the protocol for this socket if necessary */
438 if ((type == SILC_SERVER_BACKUP_RESUMED ||
439 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
440 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
441 ((SilcIDListData)sock->user_data)->status &
442 SILC_IDLIST_STATUS_DISABLED) {
443 SilcServerEntry backup_router;
445 if (silc_server_backup_replaced_get(server,
446 ((SilcServerEntry)sock->
449 SilcSocketConnection bsock =
450 (SilcSocketConnection)backup_router->connection;
451 if (bsock->protocol && bsock->protocol->protocol &&
452 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
453 sock->protocol = bsock->protocol;
454 ctx = sock->protocol->context;
460 /* If the backup resuming protocol is active then process the packet
462 if (sock->protocol && sock->protocol->protocol &&
463 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
464 ctx = sock->protocol->context;
467 if (type != SILC_SERVER_BACKUP_RESUMED &&
468 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
469 for (i = 0; i < ctx->sessions_count; i++) {
470 if (session == ctx->sessions[i].session) {
471 ctx->session = session;
472 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
477 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
481 SILC_LOG_DEBUG(("Bad resume router packet"));
485 /* We don't have protocol active. If we are router and the packet is
486 coming from our primary router then lets check whether it means we've
487 been replaced by an backup router in my cell. This is usually received
488 immediately after we've connected to our primary router. */
490 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
491 sock && SILC_PRIMARY_ROUTE(server) == sock &&
492 type == SILC_SERVER_BACKUP_REPLACED) {
493 /* We have been replaced by an backup router in our cell. We must
494 mark our primary router connection disabled since we are not allowed
495 to use it at this moment. */
496 SilcIDListData idata = (SilcIDListData)sock->user_data;
497 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
498 "wait until backup resuming protocol is executed"));
499 idata->status |= SILC_IDLIST_STATUS_DISABLED;
503 if (type == SILC_SERVER_BACKUP_START ||
504 type == SILC_SERVER_BACKUP_START_GLOBAL) {
505 /* We have received a start for resuming protocol. */
506 SilcServerBackupProtocolContext proto_ctx;
508 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
509 proto_ctx->server = server;
510 proto_ctx->sock = sock;
511 proto_ctx->responder = TRUE;
512 proto_ctx->type = type;
513 proto_ctx->session = session;
514 proto_ctx->start = time(0);
516 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
518 /* Run the backup resuming protocol */
519 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
520 &sock->protocol, proto_ctx,
521 silc_server_protocol_backup_done);
522 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
526 /* Timeout task callback to connect to remote router */
528 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
530 SilcServerConnection sconn = (SilcServerConnection)context;
531 SilcServer server = sconn->server;
533 const char *server_ip;
535 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
536 sconn->remote_port));
538 /* Connect to remote host */
539 server_ip = server->config->server_info->primary == NULL ? NULL :
540 server->config->server_info->primary->server_ip;
541 sock = silc_net_create_connection(server_ip, sconn->remote_port,
544 silc_schedule_task_add(server->schedule, 0,
545 silc_server_backup_connect_to_router,
546 context, 5, 0, SILC_TASK_TIMEOUT,
547 SILC_TASK_PRI_NORMAL);
551 /* Continue with key exchange protocol */
552 silc_server_start_key_exchange(server, sconn, sock);
555 /* Constantly tries to reconnect to a primary router indicated by the
556 `ip' and `port'. The `connected' callback will be called when the
557 connection is created. */
559 void silc_server_backup_reconnect(SilcServer server,
560 const char *ip, SilcUInt16 port,
561 SilcServerConnectRouterCallback callback,
564 SilcServerConnection sconn;
566 sconn = silc_calloc(1, sizeof(*sconn));
567 sconn->server = server;
568 sconn->remote_host = strdup(ip);
569 sconn->remote_port = port;
570 sconn->callback = callback;
571 sconn->callback_context = context;
572 sconn->no_reconnect = TRUE;
573 silc_schedule_task_add(server->schedule, 0,
574 silc_server_backup_connect_to_router,
575 sconn, 1, 0, SILC_TASK_TIMEOUT,
576 SILC_TASK_PRI_NORMAL);
579 /* Task that is called after backup router has connected back to
580 primary router and we are starting the resuming protocol */
582 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
584 SilcServerBackupProtocolContext proto_ctx =
585 (SilcServerBackupProtocolContext)context;
586 SilcServer server = proto_ctx->server;
587 SilcSocketConnection sock = proto_ctx->sock;
589 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
591 /* Run the backup resuming protocol */
592 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
593 &sock->protocol, proto_ctx,
594 silc_server_protocol_backup_done);
595 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
598 /* Called when we've established connection back to our primary router
599 when we've acting as backup router and have replaced the primary router
600 in the cell. This function will start the backup resuming protocol. */
602 void silc_server_backup_connected(SilcServer server,
603 SilcServerEntry server_entry,
606 SilcServerBackupProtocolContext proto_ctx;
607 SilcSocketConnection sock;
611 SilcServerConfigRouter *primary;
612 primary = silc_server_config_get_primary_router(server);
614 silc_server_backup_reconnect(server,
615 primary->host, primary->port,
616 silc_server_backup_connected,
621 sock = (SilcSocketConnection)server_entry->connection;
622 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
623 proto_ctx->server = server;
624 proto_ctx->sock = sock;
625 proto_ctx->responder = FALSE;
626 proto_ctx->type = SILC_SERVER_BACKUP_START;
627 proto_ctx->start = time(0);
629 /* Start through scheduler */
630 silc_schedule_task_add(server->schedule, 0,
631 silc_server_backup_connected_later,
634 SILC_TASK_PRI_NORMAL);
637 /* Called when normal server has connected to its primary router after
638 backup router has sent the START packet in reusming protocol. We will
639 move the protocol context from the backup router connection to the
642 static void silc_server_backup_connect_primary(SilcServer server,
643 SilcServerEntry server_entry,
646 SilcSocketConnection backup_router = (SilcSocketConnection)context;
647 SilcServerBackupProtocolContext ctx;
648 SilcSocketConnection sock;
649 SilcIDListData idata;
654 SilcServerConfigRouter *primary;
655 primary = silc_server_config_get_primary_router(server);
657 silc_server_backup_reconnect(server,
658 primary->host, primary->port,
659 silc_server_backup_connect_primary,
664 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
665 sock = (SilcSocketConnection)server_entry->connection;
666 idata = (SilcIDListData)server_entry;
668 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
670 /* Send the CONNECTED packet back to the backup router. */
671 buffer = silc_buffer_alloc(2);
672 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
673 silc_buffer_format(buffer,
674 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
675 SILC_STR_UI_CHAR(ctx->session),
677 silc_server_packet_send(server, backup_router,
678 SILC_PACKET_RESUME_ROUTER, 0,
679 buffer->data, buffer->len, FALSE);
680 silc_buffer_free(buffer);
682 /* The primary connection is disabled until it sends the RESUMED packet
684 idata->status |= SILC_IDLIST_STATUS_DISABLED;
686 /* Move this protocol context from this backup router connection to
687 the primary router connection since it will send the subsequent
688 packets in this protocol. We don't talk with backup router
690 sock->protocol = backup_router->protocol;
691 ctx->sock = (SilcSocketConnection)server_entry->connection;
692 backup_router->protocol = NULL;
695 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
697 SilcProtocol protocol = (SilcProtocol)context;
698 SilcServerBackupProtocolContext ctx = protocol->context;
699 SilcServer server = ctx->server;
703 for (i = 0; i < ctx->sessions_count; i++)
704 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
705 ctx->session = ctx->sessions[i].session;
707 /* We've received all the CONNECTED packets and now we'll send the
708 ENDING packet to the new primary router. */
709 packet = silc_buffer_alloc(2);
710 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
711 silc_buffer_format(packet,
712 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
713 SILC_STR_UI_CHAR(ctx->session),
715 silc_server_packet_send(server, ctx->sock,
716 SILC_PACKET_RESUME_ROUTER, 0,
717 packet->data, packet->len, FALSE);
718 silc_buffer_free(packet);
720 protocol->state = SILC_PROTOCOL_STATE_END;
723 /* Backup resuming protocol. This protocol is executed when the primary
724 router wants to resume its position as being primary router. */
726 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
728 SilcProtocol protocol = (SilcProtocol)context;
729 SilcServerBackupProtocolContext ctx = protocol->context;
730 SilcServer server = ctx->server;
732 SilcIDCacheList list;
733 SilcIDCacheEntry id_cache;
734 SilcServerEntry server_entry;
737 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
738 protocol->state = SILC_PROTOCOL_STATE_START;
740 switch(protocol->state) {
741 case SILC_PROTOCOL_STATE_START:
742 if (ctx->responder == FALSE) {
743 /* Initiator of the protocol. We are backup router */
745 packet = silc_buffer_alloc(2);
746 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
748 /* Send the START packet to primary router and normal servers. */
749 if (silc_idcache_get_all(server->local_list->servers, &list)) {
750 if (silc_idcache_list_first(list, &id_cache)) {
752 server_entry = (SilcServerEntry)id_cache->context;
753 if (!server_entry || (server_entry == server->id_entry) ||
754 !server_entry->connection || !server_entry->data.send_key ||
755 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
756 if (!silc_idcache_list_next(list, &id_cache))
762 ctx->sessions = silc_realloc(ctx->sessions,
763 sizeof(*ctx->sessions) *
764 (ctx->sessions_count + 1));
765 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
766 ctx->sessions[ctx->sessions_count].connected = FALSE;
767 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
769 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
770 server_entry->server_name, ctx->sessions_count));
772 /* This connection is performing this protocol too now */
773 ((SilcSocketConnection)server_entry->connection)->protocol =
776 if (server_entry->server_type == SILC_ROUTER)
777 packet->data[0] = SILC_SERVER_BACKUP_START;
779 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
780 packet->data[1] = ctx->sessions_count;
781 silc_server_packet_send(server, server_entry->connection,
782 SILC_PACKET_RESUME_ROUTER, 0,
783 packet->data, packet->len, FALSE);
784 ctx->sessions_count++;
786 if (!silc_idcache_list_next(list, &id_cache))
791 silc_idcache_list_free(list);
794 if (silc_idcache_get_all(server->global_list->servers, &list)) {
795 if (silc_idcache_list_first(list, &id_cache)) {
797 server_entry = (SilcServerEntry)id_cache->context;
798 if (!server_entry || (server_entry == server->id_entry) ||
799 !server_entry->connection || !server_entry->data.send_key ||
800 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
801 if (!silc_idcache_list_next(list, &id_cache))
807 ctx->sessions = silc_realloc(ctx->sessions,
808 sizeof(*ctx->sessions) *
809 (ctx->sessions_count + 1));
810 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
811 ctx->sessions[ctx->sessions_count].connected = FALSE;
812 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
814 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
815 server_entry->server_name, ctx->sessions_count));
817 /* This connection is performing this protocol too now */
818 ((SilcSocketConnection)server_entry->connection)->protocol =
821 if (server_entry->server_type == SILC_ROUTER)
822 packet->data[0] = SILC_SERVER_BACKUP_START;
824 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
825 packet->data[1] = ctx->sessions_count;
826 silc_server_packet_send(server, server_entry->connection,
827 SILC_PACKET_RESUME_ROUTER, 0,
828 packet->data, packet->len, FALSE);
829 ctx->sessions_count++;
831 if (!silc_idcache_list_next(list, &id_cache))
836 silc_idcache_list_free(list);
839 silc_buffer_free(packet);
841 /* Announce all of our information */
842 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
843 silc_server_announce_clients(server, 0, ctx->sock);
844 silc_server_announce_channels(server, 0, ctx->sock);
848 /* Responder of the protocol. */
849 SilcServerConfigRouter *primary;
851 /* We should have received START or START_GLOBAL packet */
852 if (ctx->type != SILC_SERVER_BACKUP_START &&
853 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
854 SILC_LOG_DEBUG(("Bad resume router packet"));
858 /* Connect to the primary router that was down that is now supposed
859 to be back online. We send the CONNECTED packet after we've
860 established the connection to the primary router. */
861 primary = silc_server_config_get_primary_router(server);
862 if (primary && server->backup_primary) {
863 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
865 silc_server_backup_reconnect(server,
866 primary->host, primary->port,
867 silc_server_backup_connect_primary,
870 /* Nowhere to connect just return the CONNECTED packet */
871 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
874 /* Send the CONNECTED packet back to the backup router. */
875 packet = silc_buffer_alloc(2);
876 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
877 silc_buffer_format(packet,
878 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
879 SILC_STR_UI_CHAR(ctx->session),
881 silc_server_packet_send(server, ctx->sock,
882 SILC_PACKET_RESUME_ROUTER, 0,
883 packet->data, packet->len, FALSE);
884 silc_buffer_free(packet);
887 if (server->server_type == SILC_ROUTER &&
889 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
892 protocol->state = SILC_PROTOCOL_STATE_END;
894 ctx->sessions = silc_realloc(ctx->sessions,
895 sizeof(*ctx->sessions) *
896 (ctx->sessions_count + 1));
897 ctx->sessions[ctx->sessions_count].session = ctx->session;
898 ctx->sessions_count++;
903 if (ctx->responder == FALSE) {
906 /* We should have received CONNECTED packet */
907 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
908 SILC_LOG_DEBUG(("Bad resume router packet"));
912 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
914 for (i = 0; i < ctx->sessions_count; i++) {
915 if (ctx->sessions[i].session == ctx->session) {
916 ctx->sessions[i].connected = TRUE;
921 for (i = 0; i < ctx->sessions_count; i++) {
922 if (!ctx->sessions[i].connected)
926 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
927 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
929 /* Send with a timeout */
930 silc_schedule_task_add(server->schedule, 0,
931 silc_server_backup_send_resumed,
932 protocol, 1, 0, SILC_TASK_TIMEOUT,
933 SILC_TASK_PRI_NORMAL);
938 /* We should have been received ENDING packet */
939 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
940 SILC_LOG_DEBUG(("Bad resume router packet"));
944 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
946 /* This state is received by the primary router but also servers
947 and perhaps other routers so check that if we are the primary
948 router of the cell then start sending RESUMED packets. If we
949 are normal server or one of those other routers then procede
951 if (server->router &&
952 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
953 silc_server_config_is_primary_route(server)) {
954 /* We'll wait for RESUMED packet */
955 protocol->state = SILC_PROTOCOL_STATE_END;
959 /* Switch announced informations to our primary router of using the
961 silc_server_local_servers_toggle_enabled(server, TRUE);
962 silc_server_update_servers_by_server(server, ctx->sock->user_data,
964 silc_server_update_clients_by_server(server, ctx->sock->user_data,
965 server->router, TRUE, FALSE);
966 if (server->server_type == SILC_SERVER)
967 silc_server_update_channels_by_server(server, ctx->sock->user_data,
970 packet = silc_buffer_alloc(2);
971 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
973 /* We are the primary router, start sending RESUMED packets. */
974 if (silc_idcache_get_all(server->local_list->servers, &list)) {
975 if (silc_idcache_list_first(list, &id_cache)) {
977 server_entry = (SilcServerEntry)id_cache->context;
978 if (!server_entry || (server_entry == server->id_entry) ||
979 !server_entry->connection || !server_entry->data.send_key) {
980 if (!silc_idcache_list_next(list, &id_cache))
986 SILC_LOG_DEBUG(("Sending RESUMED to %s",
987 server_entry->server_name));
989 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
991 /* This connection is performing this protocol too now */
992 ((SilcSocketConnection)server_entry->connection)->protocol =
995 if (server_entry->server_type == SILC_ROUTER)
996 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
998 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
999 silc_server_packet_send(server, server_entry->connection,
1000 SILC_PACKET_RESUME_ROUTER, 0,
1001 packet->data, packet->len, FALSE);
1003 if (!silc_idcache_list_next(list, &id_cache))
1008 silc_idcache_list_free(list);
1011 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1012 if (silc_idcache_list_first(list, &id_cache)) {
1014 server_entry = (SilcServerEntry)id_cache->context;
1015 if (!server_entry || (server_entry == server->id_entry) ||
1016 !server_entry->connection || !server_entry->data.send_key) {
1017 if (!silc_idcache_list_next(list, &id_cache))
1023 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1024 server_entry->server_name));
1026 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1028 /* This connection is performing this protocol too now */
1029 ((SilcSocketConnection)server_entry->connection)->protocol =
1032 if (server_entry->server_type == SILC_ROUTER)
1033 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1035 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1036 silc_server_packet_send(server, server_entry->connection,
1037 SILC_PACKET_RESUME_ROUTER, 0,
1038 packet->data, packet->len, FALSE);
1040 if (!silc_idcache_list_next(list, &id_cache))
1045 silc_idcache_list_free(list);
1048 silc_buffer_free(packet);
1050 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1052 /* For us this is the end of this protocol. */
1053 if (protocol->final_callback)
1054 silc_protocol_execute_final(protocol, server->schedule);
1056 silc_protocol_free(protocol);
1060 case SILC_PROTOCOL_STATE_END:
1062 SilcServerEntry router, backup_router;
1064 /* We should have been received RESUMED packet from our primary
1066 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1067 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1068 SILC_LOG_DEBUG(("Bad resume router packet"));
1072 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1074 if (server->backup_router)
1075 server->server_type = SILC_BACKUP_ROUTER;
1077 /* We have now new primary router. All traffic goes there from now on. */
1078 router = (SilcServerEntry)ctx->sock->user_data;
1079 if (silc_server_backup_replaced_get(server, router->id,
1082 if (backup_router == server->router) {
1083 /* We have new primary router now */
1084 server->id_entry->router = router;
1085 server->router = router;
1086 server->router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1088 SILC_LOG_INFO(("Switching back to primary router %s",
1089 server->router->server_name));
1091 /* We are connected to new primary and now continue using it */
1092 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1093 SILC_LOG_INFO(("Resuming the use of primary router %s",
1094 router->server_name));
1097 /* Update the client entries of the backup router to the new
1099 silc_server_local_servers_toggle_enabled(server, FALSE);
1100 silc_server_update_servers_by_server(server, backup_router, router);
1101 silc_server_update_clients_by_server(server, NULL, router,
1103 if (server->server_type == SILC_SERVER)
1104 silc_server_update_channels_by_server(server, backup_router, router);
1105 silc_server_backup_replaced_del(server, backup_router);
1107 /* Announce all of our information to the router. */
1108 if (server->server_type == SILC_ROUTER)
1109 silc_server_announce_servers(server, FALSE, 0, router->connection);
1111 /* Announce our clients and channels to the router */
1112 silc_server_announce_clients(server, 0, router->connection);
1113 silc_server_announce_channels(server, 0, router->connection);
1116 /* Send notify about primary router going down to local operators */
1117 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1118 SILC_NOTIFY_TYPE_NONE,
1119 ("%s resumed the use of primary router %s",
1120 server->server_name,
1121 server->router->server_name));
1123 /* Protocol has ended, call the final callback */
1124 if (protocol->final_callback)
1125 silc_protocol_execute_final(protocol, server->schedule);
1127 silc_protocol_free(protocol);
1131 case SILC_PROTOCOL_STATE_ERROR:
1132 /* Protocol has ended, call the final callback */
1133 if (protocol->final_callback)
1134 silc_protocol_execute_final(protocol, server->schedule);
1136 silc_protocol_free(protocol);
1139 case SILC_PROTOCOL_STATE_FAILURE:
1140 /* Protocol has ended, call the final callback */
1141 if (protocol->final_callback)
1142 silc_protocol_execute_final(protocol, server->schedule);
1144 silc_protocol_free(protocol);
1147 case SILC_PROTOCOL_STATE_UNKNOWN:
1152 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1154 SilcProtocol protocol = (SilcProtocol)context;
1155 SilcServerBackupProtocolContext ctx = protocol->context;
1156 SilcServer server = ctx->server;
1157 SilcServerEntry server_entry;
1158 SilcSocketConnection sock;
1159 SilcIDCacheList list;
1160 SilcIDCacheEntry id_cache;
1162 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1163 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1164 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1167 /* Remove this protocol from all server entries that has it */
1168 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1169 if (silc_idcache_list_first(list, &id_cache)) {
1171 server_entry = (SilcServerEntry)id_cache->context;
1172 sock = (SilcSocketConnection)server_entry->connection;
1176 SILC_LOG_DEBUG(("******** REMOVE THIS TEST, IT ALLOWS A BUG"));
1177 if (!silc_idcache_list_next(list, &id_cache))
1182 if (sock->protocol == protocol) {
1183 sock->protocol = NULL;
1185 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1186 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1189 if (!silc_idcache_list_next(list, &id_cache))
1193 silc_idcache_list_free(list);
1196 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1197 if (silc_idcache_list_first(list, &id_cache)) {
1199 server_entry = (SilcServerEntry)id_cache->context;
1200 sock = (SilcSocketConnection)server_entry->connection;
1204 SILC_LOG_DEBUG(("******** REMOVE THIS TEST, IT ALLOWS A BUG"));
1205 if (!silc_idcache_list_next(list, &id_cache))
1210 if (sock->protocol == protocol) {
1211 sock->protocol = NULL;
1213 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1214 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1217 if (!silc_idcache_list_next(list, &id_cache))
1221 silc_idcache_list_free(list);
1224 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1226 if (ctx->sock->protocol)
1227 ctx->sock->protocol = NULL;
1228 silc_protocol_free(protocol);
1229 silc_free(ctx->sessions);