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",
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;
342 if (!backup || sender == backup)
344 if (local && server->backup->servers[i].local == FALSE)
346 if (server->backup->servers[i].server == server->id_entry)
349 sock = backup->connection;
351 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
352 silc_get_packet_name(type), sock->hostname, sock->ip));
354 silc_server_packet_send(server, backup->connection, type, flags,
355 data, data_len, force_send);
359 /* Same as silc_server_backup_send but sets a specific Destination ID to
360 the packet. The Destination ID is indicated by the `dst_id' and the
361 ID type `dst_id_type'. For example, packets destined to channels must
362 be sent using this function. */
364 void silc_server_backup_send_dest(SilcServer server,
365 SilcServerEntry sender,
367 SilcPacketFlags flags,
369 SilcIdType dst_id_type,
375 SilcServerEntry backup;
376 SilcSocketConnection sock;
379 if (!server->backup || server->server_type != SILC_ROUTER)
382 for (i = 0; i < server->backup->servers_count; i++) {
383 backup = server->backup->servers[i].server;
384 if (!backup || sender == backup)
386 if (local && server->backup->servers[i].local == FALSE)
388 if (server->backup->servers[i].server == server->id_entry)
391 sock = backup->connection;
393 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
394 silc_get_packet_name(type), sock->hostname, sock->ip));
396 silc_server_packet_send_dest(server, backup->connection, type, flags,
397 dst_id, dst_id_type, data, data_len,
402 /* Processes incoming RESUME_ROUTER packet. This can give the packet
403 for processing to the protocol handler or allocate new protocol if
404 start command is received. */
406 void silc_server_backup_resume_router(SilcServer server,
407 SilcSocketConnection sock,
408 SilcPacketContext *packet)
410 SilcUInt8 type, session;
411 SilcServerBackupProtocolContext ctx;
414 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
415 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
416 SILC_LOG_DEBUG(("Bad packet received"));
420 ret = silc_buffer_unformat(packet->buffer,
421 SILC_STR_UI_CHAR(&type),
422 SILC_STR_UI_CHAR(&session),
425 SILC_LOG_DEBUG(("Malformed packet received"));
429 /* Activate the protocol for this socket if necessary */
430 if ((type == SILC_SERVER_BACKUP_RESUMED ||
431 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
432 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
433 ((SilcIDListData)sock->user_data)->status &
434 SILC_IDLIST_STATUS_DISABLED) {
435 SilcServerEntry backup_router;
437 if (silc_server_backup_replaced_get(server,
438 ((SilcServerEntry)sock->
441 SilcSocketConnection bsock =
442 (SilcSocketConnection)backup_router->connection;
443 if (bsock->protocol && bsock->protocol->protocol &&
444 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
445 sock->protocol = bsock->protocol;
446 ctx = sock->protocol->context;
452 /* If the backup resuming protocol is active then process the packet
454 if (sock->protocol && sock->protocol->protocol &&
455 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
456 ctx = sock->protocol->context;
459 if (type != SILC_SERVER_BACKUP_RESUMED &&
460 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
461 for (i = 0; i < ctx->sessions_count; i++) {
462 if (session == ctx->sessions[i].session) {
463 ctx->session = session;
464 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
469 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
473 SILC_LOG_DEBUG(("Bad resume router packet"));
477 /* We don't have protocol active. If we are router and the packet is
478 coming from our primary router then lets check whether it means we've
479 been replaced by an backup router in my cell. This is usually received
480 immediately after we've connected to our primary router. */
482 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
483 sock && SILC_PRIMARY_ROUTE(server) == sock &&
484 type == SILC_SERVER_BACKUP_REPLACED) {
485 /* We have been replaced by an backup router in our cell. We must
486 mark our primary router connection disabled since we are not allowed
487 to use it at this moment. */
488 SilcIDListData idata = (SilcIDListData)sock->user_data;
489 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
490 "wait until backup resuming protocol is executed"));
491 idata->status |= SILC_IDLIST_STATUS_DISABLED;
495 if (type == SILC_SERVER_BACKUP_START ||
496 type == SILC_SERVER_BACKUP_START_GLOBAL) {
497 /* We have received a start for resuming protocol. */
498 SilcServerBackupProtocolContext proto_ctx;
500 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
501 proto_ctx->server = server;
502 proto_ctx->sock = sock;
503 proto_ctx->responder = TRUE;
504 proto_ctx->type = type;
505 proto_ctx->session = session;
506 proto_ctx->start = time(0);
508 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
510 /* Run the backup resuming protocol */
511 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
512 &sock->protocol, proto_ctx,
513 silc_server_protocol_backup_done);
514 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
518 /* Timeout task callback to connect to remote router */
520 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
522 SilcServerConnection sconn = (SilcServerConnection)context;
523 SilcServer server = sconn->server;
525 const char *server_ip;
527 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
528 sconn->remote_port));
530 /* Connect to remote host */
531 server_ip = server->config->server_info->primary == NULL ? NULL :
532 server->config->server_info->primary->server_ip;
533 sock = silc_net_create_connection(server_ip, sconn->remote_port,
536 silc_schedule_task_add(server->schedule, 0,
537 silc_server_backup_connect_to_router,
538 context, 5, 0, SILC_TASK_TIMEOUT,
539 SILC_TASK_PRI_NORMAL);
543 /* Continue with key exchange protocol */
544 silc_server_start_key_exchange(server, sconn, sock);
547 /* Constantly tries to reconnect to a primary router indicated by the
548 `ip' and `port'. The `connected' callback will be called when the
549 connection is created. */
551 void silc_server_backup_reconnect(SilcServer server,
552 const char *ip, SilcUInt16 port,
553 SilcServerConnectRouterCallback callback,
556 SilcServerConnection sconn;
558 sconn = silc_calloc(1, sizeof(*sconn));
559 sconn->server = server;
560 sconn->remote_host = strdup(ip);
561 sconn->remote_port = port;
562 sconn->callback = callback;
563 sconn->callback_context = context;
564 sconn->no_reconnect = TRUE;
565 silc_schedule_task_add(server->schedule, 0,
566 silc_server_backup_connect_to_router,
567 sconn, 1, 0, SILC_TASK_TIMEOUT,
568 SILC_TASK_PRI_NORMAL);
571 /* Task that is called after backup router has connected back to
572 primary router and we are starting the resuming protocol */
574 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
576 SilcServerBackupProtocolContext proto_ctx =
577 (SilcServerBackupProtocolContext)context;
578 SilcServer server = proto_ctx->server;
579 SilcSocketConnection sock = proto_ctx->sock;
581 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
583 /* Run the backup resuming protocol */
584 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
585 &sock->protocol, proto_ctx,
586 silc_server_protocol_backup_done);
587 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
590 /* Called when we've established connection back to our primary router
591 when we've acting as backup router and have replaced the primary router
592 in the cell. This function will start the backup resuming protocol. */
594 void silc_server_backup_connected(SilcServer server,
595 SilcServerEntry server_entry,
598 SilcServerBackupProtocolContext proto_ctx;
599 SilcSocketConnection sock;
603 SilcServerConfigRouter *primary;
604 primary = silc_server_config_get_primary_router(server);
606 silc_server_backup_reconnect(server,
607 primary->host, primary->port,
608 silc_server_backup_connected,
613 sock = (SilcSocketConnection)server_entry->connection;
614 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
615 proto_ctx->server = server;
616 proto_ctx->sock = sock;
617 proto_ctx->responder = FALSE;
618 proto_ctx->type = SILC_SERVER_BACKUP_START;
619 proto_ctx->start = time(0);
621 /* Start through scheduler */
622 silc_schedule_task_add(server->schedule, 0,
623 silc_server_backup_connected_later,
626 SILC_TASK_PRI_NORMAL);
629 /* Called when normal server has connected to its primary router after
630 backup router has sent the START packet in reusming protocol. We will
631 move the protocol context from the backup router connection to the
634 static void silc_server_backup_connect_primary(SilcServer server,
635 SilcServerEntry server_entry,
638 SilcSocketConnection backup_router = (SilcSocketConnection)context;
639 SilcServerBackupProtocolContext ctx;
640 SilcSocketConnection sock;
641 SilcIDListData idata;
646 SilcServerConfigRouter *primary;
647 primary = silc_server_config_get_primary_router(server);
649 silc_server_backup_reconnect(server,
650 primary->host, primary->port,
651 silc_server_backup_connect_primary,
656 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
657 sock = (SilcSocketConnection)server_entry->connection;
658 idata = (SilcIDListData)server_entry;
660 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
662 /* Send the CONNECTED packet back to the backup router. */
663 buffer = silc_buffer_alloc(2);
664 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
665 silc_buffer_format(buffer,
666 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
667 SILC_STR_UI_CHAR(ctx->session),
669 silc_server_packet_send(server, backup_router,
670 SILC_PACKET_RESUME_ROUTER, 0,
671 buffer->data, buffer->len, FALSE);
672 silc_buffer_free(buffer);
674 /* The primary connection is disabled until it sends the RESUMED packet
676 idata->status |= SILC_IDLIST_STATUS_DISABLED;
678 /* Move this protocol context from this backup router connection to
679 the primary router connection since it will send the subsequent
680 packets in this protocol. We don't talk with backup router
682 sock->protocol = backup_router->protocol;
683 ctx->sock = (SilcSocketConnection)server_entry->connection;
684 backup_router->protocol = NULL;
687 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
689 SilcProtocol protocol = (SilcProtocol)context;
690 SilcServerBackupProtocolContext ctx = protocol->context;
691 SilcServer server = ctx->server;
695 for (i = 0; i < ctx->sessions_count; i++)
696 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
697 ctx->session = ctx->sessions[i].session;
699 /* We've received all the CONNECTED packets and now we'll send the
700 ENDING packet to the new primary router. */
701 packet = silc_buffer_alloc(2);
702 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
703 silc_buffer_format(packet,
704 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
705 SILC_STR_UI_CHAR(ctx->session),
707 silc_server_packet_send(server, ctx->sock,
708 SILC_PACKET_RESUME_ROUTER, 0,
709 packet->data, packet->len, FALSE);
710 silc_buffer_free(packet);
712 protocol->state = SILC_PROTOCOL_STATE_END;
715 /* Backup resuming protocol. This protocol is executed when the primary
716 router wants to resume its position as being primary router. */
718 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
720 SilcProtocol protocol = (SilcProtocol)context;
721 SilcServerBackupProtocolContext ctx = protocol->context;
722 SilcServer server = ctx->server;
724 SilcIDCacheList list;
725 SilcIDCacheEntry id_cache;
726 SilcServerEntry server_entry;
729 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
730 protocol->state = SILC_PROTOCOL_STATE_START;
732 switch(protocol->state) {
733 case SILC_PROTOCOL_STATE_START:
734 if (ctx->responder == FALSE) {
735 /* Initiator of the protocol. We are backup router */
737 packet = silc_buffer_alloc(2);
738 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
740 /* Send the START packet to primary router and normal servers. */
741 if (silc_idcache_get_all(server->local_list->servers, &list)) {
742 if (silc_idcache_list_first(list, &id_cache)) {
744 server_entry = (SilcServerEntry)id_cache->context;
745 if (!server_entry || (server_entry == server->id_entry) ||
746 !server_entry->connection || !server_entry->data.send_key ||
747 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
748 if (!silc_idcache_list_next(list, &id_cache))
754 ctx->sessions = silc_realloc(ctx->sessions,
755 sizeof(*ctx->sessions) *
756 (ctx->sessions_count + 1));
757 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
758 ctx->sessions[ctx->sessions_count].connected = FALSE;
759 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
761 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
762 server_entry->server_name, ctx->sessions_count));
764 /* This connection is performing this protocol too now */
765 ((SilcSocketConnection)server_entry->connection)->protocol =
768 if (server_entry->server_type == SILC_ROUTER)
769 packet->data[0] = SILC_SERVER_BACKUP_START;
771 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
772 packet->data[1] = ctx->sessions_count;
773 silc_server_packet_send(server, server_entry->connection,
774 SILC_PACKET_RESUME_ROUTER, 0,
775 packet->data, packet->len, FALSE);
776 ctx->sessions_count++;
778 if (!silc_idcache_list_next(list, &id_cache))
783 silc_idcache_list_free(list);
786 if (silc_idcache_get_all(server->global_list->servers, &list)) {
787 if (silc_idcache_list_first(list, &id_cache)) {
789 server_entry = (SilcServerEntry)id_cache->context;
790 if (!server_entry || (server_entry == server->id_entry) ||
791 !server_entry->connection || !server_entry->data.send_key ||
792 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
793 if (!silc_idcache_list_next(list, &id_cache))
799 ctx->sessions = silc_realloc(ctx->sessions,
800 sizeof(*ctx->sessions) *
801 (ctx->sessions_count + 1));
802 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
803 ctx->sessions[ctx->sessions_count].connected = FALSE;
804 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
806 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
807 server_entry->server_name, ctx->sessions_count));
809 /* This connection is performing this protocol too now */
810 ((SilcSocketConnection)server_entry->connection)->protocol =
813 if (server_entry->server_type == SILC_ROUTER)
814 packet->data[0] = SILC_SERVER_BACKUP_START;
816 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
817 packet->data[1] = ctx->sessions_count;
818 silc_server_packet_send(server, server_entry->connection,
819 SILC_PACKET_RESUME_ROUTER, 0,
820 packet->data, packet->len, FALSE);
821 ctx->sessions_count++;
823 if (!silc_idcache_list_next(list, &id_cache))
828 silc_idcache_list_free(list);
831 silc_buffer_free(packet);
833 /* If we are not standalone and our primary is not the one we've
834 talking to now, then announce our information to it since we
835 haven't done that yet. Standalone backup router announces
836 these during connecting to the primary. */
837 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
838 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
839 silc_server_announce_clients(server, 0, ctx->sock);
840 silc_server_announce_channels(server, 0, ctx->sock);
845 /* Responder of the protocol. */
846 SilcServerConfigRouter *primary;
848 /* We should have received START or START_GLOBAL packet */
849 if (ctx->type != SILC_SERVER_BACKUP_START &&
850 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
851 SILC_LOG_DEBUG(("Bad resume router packet"));
855 /* Connect to the primary router that was down that is now supposed
856 to be back online. We send the CONNECTED packet after we've
857 established the connection to the primary router. */
858 primary = silc_server_config_get_primary_router(server);
859 if (primary && server->backup_primary) {
860 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
862 silc_server_backup_reconnect(server,
863 primary->host, primary->port,
864 silc_server_backup_connect_primary,
867 /* Nowhere to connect just return the CONNECTED packet */
868 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
871 /* Send the CONNECTED packet back to the backup router. */
872 packet = silc_buffer_alloc(2);
873 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
874 silc_buffer_format(packet,
875 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
876 SILC_STR_UI_CHAR(ctx->session),
878 silc_server_packet_send(server, ctx->sock,
879 SILC_PACKET_RESUME_ROUTER, 0,
880 packet->data, packet->len, FALSE);
881 silc_buffer_free(packet);
884 if (server->server_type == SILC_ROUTER &&
886 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
889 protocol->state = SILC_PROTOCOL_STATE_END;
891 ctx->sessions = silc_realloc(ctx->sessions,
892 sizeof(*ctx->sessions) *
893 (ctx->sessions_count + 1));
894 ctx->sessions[ctx->sessions_count].session = ctx->session;
895 ctx->sessions_count++;
900 if (ctx->responder == FALSE) {
903 /* We should have received CONNECTED packet */
904 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
905 SILC_LOG_DEBUG(("Bad resume router packet"));
909 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
911 for (i = 0; i < ctx->sessions_count; i++) {
912 if (ctx->sessions[i].session == ctx->session) {
913 ctx->sessions[i].connected = TRUE;
918 for (i = 0; i < ctx->sessions_count; i++) {
919 if (!ctx->sessions[i].connected)
923 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
924 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
926 /* Send with a timeout */
927 silc_schedule_task_add(server->schedule, 0,
928 silc_server_backup_send_resumed,
929 protocol, 1, 0, SILC_TASK_TIMEOUT,
930 SILC_TASK_PRI_NORMAL);
935 /* We should have been received ENDING packet */
936 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
937 SILC_LOG_DEBUG(("Bad resume router packet"));
941 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
943 /* This state is received by the primary router but also servers
944 and perhaps other routers so check that if we are the primary
945 router of the cell then start sending RESUMED packets. If we
946 are normal server or one of those other routers then procede
948 if (server->router &&
949 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
950 silc_server_config_is_primary_route(server)) {
951 /* We'll wait for RESUMED packet */
952 protocol->state = SILC_PROTOCOL_STATE_END;
956 /* Switch announced informations to our primary router of using the
958 silc_server_local_servers_toggle_enabled(server, TRUE);
959 silc_server_update_servers_by_server(server, ctx->sock->user_data,
961 silc_server_update_clients_by_server(server, ctx->sock->user_data,
962 server->router, TRUE);
963 if (server->server_type == SILC_SERVER)
964 silc_server_update_channels_by_server(server, ctx->sock->user_data,
967 packet = silc_buffer_alloc(2);
968 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
970 /* We are the primary router, start sending RESUMED packets. */
971 if (silc_idcache_get_all(server->local_list->servers, &list)) {
972 if (silc_idcache_list_first(list, &id_cache)) {
974 server_entry = (SilcServerEntry)id_cache->context;
975 if (!server_entry || (server_entry == server->id_entry) ||
976 !server_entry->connection || !server_entry->data.send_key) {
977 if (!silc_idcache_list_next(list, &id_cache))
983 SILC_LOG_DEBUG(("Sending RESUMED to %s",
984 server_entry->server_name));
986 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
988 /* This connection is performing this protocol too now */
989 ((SilcSocketConnection)server_entry->connection)->protocol =
992 if (server_entry->server_type == SILC_ROUTER)
993 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
995 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
996 silc_server_packet_send(server, server_entry->connection,
997 SILC_PACKET_RESUME_ROUTER, 0,
998 packet->data, packet->len, FALSE);
1000 if (!silc_idcache_list_next(list, &id_cache))
1005 silc_idcache_list_free(list);
1008 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1009 if (silc_idcache_list_first(list, &id_cache)) {
1011 server_entry = (SilcServerEntry)id_cache->context;
1012 if (!server_entry || (server_entry == server->id_entry) ||
1013 !server_entry->connection || !server_entry->data.send_key) {
1014 if (!silc_idcache_list_next(list, &id_cache))
1020 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1021 server_entry->server_name));
1023 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1025 /* This connection is performing this protocol too now */
1026 ((SilcSocketConnection)server_entry->connection)->protocol =
1029 if (server_entry->server_type == SILC_ROUTER)
1030 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1032 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1033 silc_server_packet_send(server, server_entry->connection,
1034 SILC_PACKET_RESUME_ROUTER, 0,
1035 packet->data, packet->len, FALSE);
1037 if (!silc_idcache_list_next(list, &id_cache))
1042 silc_idcache_list_free(list);
1045 silc_buffer_free(packet);
1047 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1048 server->wait_backup = FALSE;
1050 /* For us this is the end of this protocol. */
1051 if (protocol->final_callback)
1052 silc_protocol_execute_final(protocol, server->schedule);
1054 silc_protocol_free(protocol);
1058 case SILC_PROTOCOL_STATE_END:
1060 SilcServerEntry router, backup_router;
1062 /* We should have been received RESUMED packet from our primary
1064 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1065 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1066 SILC_LOG_DEBUG(("Bad resume router packet"));
1070 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1072 if (server->backup_router)
1073 server->server_type = SILC_BACKUP_ROUTER;
1075 /* We have now new primary router. All traffic goes there from now on. */
1076 router = (SilcServerEntry)ctx->sock->user_data;
1077 if (silc_server_backup_replaced_get(server, router->id,
1080 if (backup_router == server->router) {
1081 /* We have new primary router now */
1082 server->id_entry->router = router;
1083 server->router = router;
1084 SILC_LOG_INFO(("Switching back to primary router %s",
1085 server->router->server_name));
1087 /* We are connected to new primary and now continue using it */
1088 SILC_LOG_INFO(("Resuming the use of primary router %s",
1089 router->server_name));
1092 /* Update the client entries of the backup router to the new
1094 silc_server_local_servers_toggle_enabled(server, FALSE);
1095 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1096 silc_server_update_servers_by_server(server, backup_router, router);
1097 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1098 if (server->server_type == SILC_SERVER)
1099 silc_server_update_channels_by_server(server, backup_router, router);
1100 silc_server_backup_replaced_del(server, backup_router);
1102 /* Announce all of our information to the router. */
1103 if (server->server_type == SILC_ROUTER)
1104 silc_server_announce_servers(server, FALSE, ctx->start,
1105 router->connection);
1107 /* Announce our clients and channels to the router */
1108 silc_server_announce_clients(server, ctx->start,
1109 router->connection);
1110 silc_server_announce_channels(server, ctx->start,
1111 router->connection);
1114 /* Send notify about primary router going down to local operators */
1115 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1116 SILC_NOTIFY_TYPE_NONE,
1117 ("%s resumed the use of primary router %s",
1118 server->server_name,
1119 server->router->server_name));
1121 /* Protocol has ended, call the final callback */
1122 if (protocol->final_callback)
1123 silc_protocol_execute_final(protocol, server->schedule);
1125 silc_protocol_free(protocol);
1129 case SILC_PROTOCOL_STATE_ERROR:
1130 /* Protocol has ended, call the final callback */
1131 if (protocol->final_callback)
1132 silc_protocol_execute_final(protocol, server->schedule);
1134 silc_protocol_free(protocol);
1137 case SILC_PROTOCOL_STATE_FAILURE:
1138 /* Protocol has ended, call the final callback */
1139 if (protocol->final_callback)
1140 silc_protocol_execute_final(protocol, server->schedule);
1142 silc_protocol_free(protocol);
1145 case SILC_PROTOCOL_STATE_UNKNOWN:
1150 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1152 SilcProtocol protocol = (SilcProtocol)context;
1153 SilcServerBackupProtocolContext ctx = protocol->context;
1154 SilcServer server = ctx->server;
1155 SilcServerEntry server_entry;
1156 SilcSocketConnection sock;
1157 SilcIDCacheList list;
1158 SilcIDCacheEntry id_cache;
1160 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1161 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1162 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1165 /* Remove this protocol from all server entries that has it */
1166 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1167 if (silc_idcache_list_first(list, &id_cache)) {
1169 server_entry = (SilcServerEntry)id_cache->context;
1170 sock = (SilcSocketConnection)server_entry->connection;
1172 if (sock->protocol == protocol) {
1173 sock->protocol = NULL;
1175 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1176 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1179 if (!silc_idcache_list_next(list, &id_cache))
1183 silc_idcache_list_free(list);
1186 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1187 if (silc_idcache_list_first(list, &id_cache)) {
1189 server_entry = (SilcServerEntry)id_cache->context;
1190 sock = (SilcSocketConnection)server_entry->connection;
1192 if (sock->protocol == protocol) {
1193 sock->protocol = NULL;
1195 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1196 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1199 if (!silc_idcache_list_next(list, &id_cache))
1203 silc_idcache_list_free(list);
1206 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1208 if (ctx->sock->protocol)
1209 ctx->sock->protocol = NULL;
1210 silc_protocol_free(protocol);
1211 silc_free(ctx->sessions);