5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
24 SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
25 static void silc_server_backup_connect_primary(SilcServer server,
26 SilcServerEntry server_entry,
31 SilcServerEntry server;
35 } SilcServerBackupEntry;
37 /* Holds IP address and port of the primary router that was replaced
42 SilcServerEntry server; /* Backup router that replaced the primary */
43 } SilcServerBackupReplaced;
46 struct SilcServerBackupStruct {
47 SilcServerBackupEntry *servers;
48 SilcUInt32 servers_count;
49 SilcServerBackupReplaced **replaced;
50 SilcUInt32 replaced_count;
56 SilcServerEntry server_entry;
57 } SilcServerBackupProtocolSession;
59 /* Backup resuming protocol context */
62 SilcSocketConnection sock;
66 SilcServerBackupProtocolSession *sessions;
67 SilcUInt32 sessions_count;
69 } *SilcServerBackupProtocolContext;
71 /* Adds the `backup_server' to be one of our backup router. This can be
72 called multiple times to set multiple backup routers. The `ip' and `port'
73 is the IP and port that the `backup_router' will replace if the `ip'
74 will become unresponsive. If `local' is TRUE then the `backup_server' is
75 in the local cell, if FALSE it is in some other cell. */
77 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
78 const char *ip, int port, bool local)
85 if (!server->backup) {
86 server->backup = silc_calloc(1, sizeof(*server->backup));
91 SILC_LOG_DEBUG(("Backup router %s will replace %s",
92 ((SilcSocketConnection)backup_server->connection)->ip,
95 for (i = 0; i < server->backup->servers_count; i++) {
96 if (!server->backup->servers[i].server) {
97 server->backup->servers[i].server = backup_server;
98 server->backup->servers[i].local = local;
99 server->backup->servers[i].port = SILC_SWAB_16(port);
100 memset(server->backup->servers[i].ip.data, 0,
101 sizeof(server->backup->servers[i].ip.data));
102 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
103 sizeof(server->backup->servers[i].ip.data));
108 i = server->backup->servers_count;
109 server->backup->servers = silc_realloc(server->backup->servers,
110 sizeof(*server->backup->servers) *
112 server->backup->servers[i].server = backup_server;
113 server->backup->servers[i].local = local;
114 server->backup->servers[i].port = SILC_SWAB_16(port);
115 memset(server->backup->servers[i].ip.data, 0,
116 sizeof(server->backup->servers[i].ip.data));
117 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
118 sizeof(server->backup->servers[i].ip.data));
119 server->backup->servers_count++;
122 /* Returns backup router for IP and port in `replacing' or NULL if there
123 does not exist backup router. */
125 SilcServerEntry silc_server_backup_get(SilcServer server,
126 SilcServerID *server_id)
133 for (i = 0; i < server->backup->servers_count; i++) {
134 if (server->backup->servers[i].server &&
135 server->backup->servers[i].port == server_id->port &&
136 !memcmp(server->backup->servers[i].ip.data, server_id->ip.data,
137 sizeof(server_id->ip.data))) {
138 SILC_LOG_DEBUG(("Found backup router %s for %s",
139 server->backup->servers[i].server->server_name,
140 silc_id_render(server_id, SILC_ID_SERVER)));
141 return server->backup->servers[i].server;
148 /* Deletes the backup server `server_entry'. */
150 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
157 for (i = 0; i < server->backup->servers_count; i++) {
158 if (server->backup->servers[i].server == server_entry) {
159 SILC_LOG_DEBUG(("Removing %s as backup router",
160 silc_id_render(server->backup->servers[i].server->id,
162 server->backup->servers[i].server = NULL;
163 memset(server->backup->servers[i].ip.data, 0,
164 sizeof(server->backup->servers[i].ip.data));
169 /* Frees all data allocated for backup routers. Call this after deleting
170 all backup routers and when new routers are added no more, for example
171 when shutting down the server. */
173 void silc_server_backup_free(SilcServer server)
180 /* Delete existing servers if caller didn't do it */
181 for (i = 0; i < server->backup->servers_count; i++) {
182 if (server->backup->servers[i].server)
183 silc_server_backup_del(server, server->backup->servers[i].server);
186 silc_free(server->backup->servers);
187 silc_free(server->backup);
188 server->backup = NULL;
191 /* Marks the IP address and port from the `server_id' as being replaced
192 by backup router indicated by the `server'. If the router connects at
193 a later time we can check whether it has been replaced by an backup
196 void silc_server_backup_replaced_add(SilcServer server,
197 SilcServerID *server_id,
198 SilcServerEntry server_entry)
201 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
204 server->backup = silc_calloc(1, sizeof(*server->backup));
205 if (!server->backup->replaced) {
206 server->backup->replaced =
207 silc_calloc(1, sizeof(*server->backup->replaced));
208 server->backup->replaced_count = 1;
211 SILC_LOG_DEBUG(("Replacing router %s with %s",
212 silc_id_render(server_id, SILC_ID_SERVER),
213 server_entry->server_name));
215 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
216 r->server = server_entry;
218 for (i = 0; i < server->backup->replaced_count; i++) {
219 if (!server->backup->replaced[i]) {
220 server->backup->replaced[i] = r;
225 i = server->backup->replaced_count;
226 server->backup->replaced = silc_realloc(server->backup->replaced,
227 sizeof(*server->backup->replaced) *
229 server->backup->replaced[i] = r;
230 server->backup->replaced_count++;
233 /* Checks whether the IP address and port from the `server_id' has been
234 replaced by an backup router. If it has been then this returns TRUE
235 and the bacup router entry to the `server' pointer if non-NULL. Returns
236 FALSE if the router is not replaced by backup router. */
238 bool silc_server_backup_replaced_get(SilcServer server,
239 SilcServerID *server_id,
240 SilcServerEntry *server_entry)
244 if (!server->backup || !server->backup->replaced)
247 for (i = 0; i < server->backup->replaced_count; i++) {
248 if (!server->backup->replaced[i])
250 if (!memcmp(server->backup->replaced[i]->ip.data, server_id->ip.data,
251 sizeof(server_id->ip.data))) {
253 *server_entry = server->backup->replaced[i]->server;
254 SILC_LOG_DEBUG(("Router %s is replaced by %s",
255 silc_id_render(server_id, SILC_ID_SERVER),
256 server->backup->replaced[i]->server->server_name));
261 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
262 silc_id_render(server_id, SILC_ID_SERVER)));
266 /* Deletes a replaced host by the set `server_entry. */
268 void silc_server_backup_replaced_del(SilcServer server,
269 SilcServerEntry server_entry)
273 if (!server->backup || !server->backup->replaced)
276 for (i = 0; i < server->backup->replaced_count; i++) {
277 if (!server->backup->replaced[i])
279 if (server->backup->replaced[i]->server == server_entry) {
280 silc_free(server->backup->replaced[i]);
281 server->backup->replaced[i] = NULL;
287 /* Broadcast the received packet indicated by `packet' to all of our backup
288 routers. All router wide information is passed using broadcast packets.
289 That is why all backup routers need to get this data too. It is expected
290 that the caller already knows that the `packet' is broadcast packet. */
292 void silc_server_backup_broadcast(SilcServer server,
293 SilcSocketConnection sender,
294 SilcPacketContext *packet)
296 SilcServerEntry backup;
297 SilcSocketConnection sock;
299 const SilcBufferStruct p;
300 SilcIDListData idata;
303 if (!server->backup || server->server_type != SILC_ROUTER)
306 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
308 buffer = packet->buffer;
309 silc_buffer_push(buffer, buffer->data - buffer->head);
311 for (i = 0; i < server->backup->servers_count; i++) {
312 backup = server->backup->servers[i].server;
314 if (!backup || backup->connection == sender ||
315 server->backup->servers[i].local == FALSE)
317 if (server->backup->servers[i].server == server->id_entry)
320 idata = (SilcIDListData)backup;
321 sock = backup->connection;
323 if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
324 (const SilcBuffer)&p)) {
325 SILC_LOG_ERROR(("Cannot send packet"));
328 silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
329 silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
330 (SilcBuffer)&p, p.len);
332 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
334 /* Now actually send the packet */
335 silc_server_packet_send_real(server, sock, FALSE);
337 /* Check for mandatory rekey */
338 if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
339 silc_schedule_task_add(server->schedule, sender->sock,
340 silc_server_rekey_callback, sender, 0, 1,
341 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
345 /* A generic routine to send data to all backup routers. If the `sender'
346 is provided it will indicate the original sender of the packet and the
347 packet won't be resent to that entity. The `data' is the data that will
348 be assembled to packet context before sending. The packet will be
349 encrypted this function. If the `force_send' is TRUE the data is sent
350 immediately and not put to queue. If `local' is TRUE then the packet
351 will be sent only to local backup routers inside the cell. If false the
352 packet can go from one cell to the other. This function has no effect
353 if there are no any backup routers. */
355 void silc_server_backup_send(SilcServer server,
356 SilcServerEntry sender,
358 SilcPacketFlags flags,
364 SilcServerEntry backup;
365 SilcSocketConnection sock;
368 if (!server->backup || server->server_type != SILC_ROUTER)
371 for (i = 0; i < server->backup->servers_count; i++) {
372 backup = server->backup->servers[i].server;
373 if (!backup || sender == backup)
375 if (local && server->backup->servers[i].local == FALSE)
377 if (server->backup->servers[i].server == server->id_entry)
380 sock = backup->connection;
382 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
383 silc_get_packet_name(type), sock->hostname, sock->ip));
385 silc_server_packet_send(server, backup->connection, type, flags,
386 data, data_len, force_send);
390 /* Same as silc_server_backup_send but sets a specific Destination ID to
391 the packet. The Destination ID is indicated by the `dst_id' and the
392 ID type `dst_id_type'. For example, packets destined to channels must
393 be sent using this function. */
395 void silc_server_backup_send_dest(SilcServer server,
396 SilcServerEntry sender,
398 SilcPacketFlags flags,
400 SilcIdType dst_id_type,
406 SilcServerEntry backup;
407 SilcSocketConnection sock;
410 if (!server->backup || server->server_type != SILC_ROUTER)
413 for (i = 0; i < server->backup->servers_count; i++) {
414 backup = server->backup->servers[i].server;
415 if (!backup || sender == backup)
417 if (local && server->backup->servers[i].local == FALSE)
419 if (server->backup->servers[i].server == server->id_entry)
422 sock = backup->connection;
424 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
425 silc_get_packet_name(type), sock->hostname, sock->ip));
427 silc_server_packet_send_dest(server, backup->connection, type, flags,
428 dst_id, dst_id_type, data, data_len,
433 SILC_TASK_CALLBACK(silc_server_backup_timeout)
435 SilcProtocol protocol = context;
436 SilcServer server = app_context;
438 SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
439 silc_protocol_cancel(protocol, server->schedule);
440 protocol->state = SILC_PROTOCOL_STATE_ERROR;
441 silc_protocol_execute_final(protocol, server->schedule);
444 /* Processes incoming RESUME_ROUTER packet. This can give the packet
445 for processing to the protocol handler or allocate new protocol if
446 start command is received. */
448 void silc_server_backup_resume_router(SilcServer server,
449 SilcSocketConnection sock,
450 SilcPacketContext *packet)
452 SilcUInt8 type, session;
453 SilcServerBackupProtocolContext ctx;
456 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
457 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
458 SILC_LOG_DEBUG(("Bad packet received"));
462 ret = silc_buffer_unformat(packet->buffer,
463 SILC_STR_UI_CHAR(&type),
464 SILC_STR_UI_CHAR(&session),
467 SILC_LOG_ERROR(("Malformed resume router packet received"));
471 /* Activate the protocol for this socket if necessary */
472 if ((type == SILC_SERVER_BACKUP_RESUMED ||
473 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
474 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
475 ((SilcIDListData)sock->user_data)->status &
476 SILC_IDLIST_STATUS_DISABLED) {
477 SilcServerEntry backup_router;
479 if (silc_server_backup_replaced_get(server,
480 ((SilcServerEntry)sock->
483 SilcSocketConnection bsock =
484 (SilcSocketConnection)backup_router->connection;
485 if (bsock->protocol && bsock->protocol->protocol &&
486 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
487 sock->protocol = bsock->protocol;
488 ctx = sock->protocol->context;
494 /* If the backup resuming protocol is active then process the packet
496 if (sock->protocol && sock->protocol->protocol &&
497 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
498 ctx = sock->protocol->context;
501 if (type != SILC_SERVER_BACKUP_RESUMED &&
502 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
503 for (i = 0; i < ctx->sessions_count; i++) {
504 if (session == ctx->sessions[i].session) {
505 ctx->session = session;
506 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
511 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
515 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
519 /* We don't have protocol active. If we are router and the packet is
520 coming from our primary router then lets check whether it means we've
521 been replaced by an backup router in my cell. This is usually received
522 immediately after we've connected to our primary router. */
524 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
525 sock && SILC_PRIMARY_ROUTE(server) == sock &&
526 type == SILC_SERVER_BACKUP_REPLACED) {
527 /* We have been replaced by an backup router in our cell. We must
528 mark our primary router connection disabled since we are not allowed
529 to use it at this moment. */
530 SilcIDListData idata = (SilcIDListData)sock->user_data;
531 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
532 "wait until backup resuming protocol is executed"));
533 idata->status |= SILC_IDLIST_STATUS_DISABLED;
537 if (type == SILC_SERVER_BACKUP_START ||
538 type == SILC_SERVER_BACKUP_START_GLOBAL) {
539 /* We have received a start for resuming protocol. */
540 SilcServerBackupProtocolContext proto_ctx;
542 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
543 proto_ctx->server = server;
544 proto_ctx->sock = sock;
545 proto_ctx->responder = TRUE;
546 proto_ctx->type = type;
547 proto_ctx->session = session;
548 proto_ctx->start = time(0);
550 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
551 SILC_LOG_INFO(("Starting backup resuming protocol"));
553 /* Run the backup resuming protocol */
554 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
555 &sock->protocol, proto_ctx,
556 silc_server_protocol_backup_done);
557 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
558 silc_schedule_task_add(server->schedule, sock->sock,
559 silc_server_backup_timeout,
560 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
561 SILC_TASK_PRI_NORMAL);
565 /* Timeout task callback to connect to remote router */
567 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
569 SilcServer server = app_context;
570 SilcServerConnection sconn = (SilcServerConnection)context;
572 const char *server_ip;
574 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
575 sconn->remote_port));
577 /* Connect to remote host */
578 server_ip = server->config->server_info->primary == NULL ? NULL :
579 server->config->server_info->primary->server_ip;
580 sock = silc_net_create_connection(server_ip, sconn->remote_port,
583 silc_schedule_task_add(server->schedule, 0,
584 silc_server_backup_connect_to_router,
585 context, 5, 0, SILC_TASK_TIMEOUT,
586 SILC_TASK_PRI_NORMAL);
590 /* Continue with key exchange protocol */
591 silc_server_start_key_exchange(server, sconn, sock);
594 /* Constantly tries to reconnect to a primary router indicated by the
595 `ip' and `port'. The `connected' callback will be called when the
596 connection is created. */
598 void silc_server_backup_reconnect(SilcServer server,
599 const char *ip, SilcUInt16 port,
600 SilcServerConnectRouterCallback callback,
603 SilcServerConnection sconn;
605 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
607 sconn = silc_calloc(1, sizeof(*sconn));
608 sconn->remote_host = strdup(ip);
609 sconn->remote_port = port;
610 sconn->callback = callback;
611 sconn->callback_context = context;
612 sconn->no_reconnect = TRUE;
613 silc_schedule_task_add(server->schedule, 0,
614 silc_server_backup_connect_to_router,
615 sconn, 1, 0, SILC_TASK_TIMEOUT,
616 SILC_TASK_PRI_NORMAL);
619 /* Task that is called after backup router has connected back to
620 primary router and we are starting the resuming protocol */
622 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
624 SilcServerBackupProtocolContext proto_ctx =
625 (SilcServerBackupProtocolContext)context;
626 SilcServer server = proto_ctx->server;
627 SilcSocketConnection sock = proto_ctx->sock;
629 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
630 SILC_LOG_INFO(("Starting backup resuming protocol"));
632 /* Run the backup resuming protocol */
633 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
634 &sock->protocol, proto_ctx,
635 silc_server_protocol_backup_done);
636 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
638 silc_schedule_task_add(server->schedule, sock->sock,
639 silc_server_backup_timeout,
640 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
641 SILC_TASK_PRI_NORMAL);
644 /* Called when we've established connection back to our primary router
645 when we've acting as backup router and have replaced the primary router
646 in the cell. This function will start the backup resuming protocol. */
648 void silc_server_backup_connected(SilcServer server,
649 SilcServerEntry server_entry,
652 SilcServerBackupProtocolContext proto_ctx;
653 SilcSocketConnection sock;
657 SilcServerConfigRouter *primary;
658 primary = silc_server_config_get_primary_router(server);
660 silc_server_backup_reconnect(server,
661 primary->host, primary->port,
662 silc_server_backup_connected,
667 sock = (SilcSocketConnection)server_entry->connection;
668 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
669 proto_ctx->server = server;
670 proto_ctx->sock = sock;
671 proto_ctx->responder = FALSE;
672 proto_ctx->type = SILC_SERVER_BACKUP_START;
673 proto_ctx->start = time(0);
675 /* Start through scheduler */
676 silc_schedule_task_add(server->schedule, 0,
677 silc_server_backup_connected_later,
680 SILC_TASK_PRI_NORMAL);
683 /* Called when normal server has connected to its primary router after
684 backup router has sent the START packet in reusming protocol. We will
685 move the protocol context from the backup router connection to the
688 static void silc_server_backup_connect_primary(SilcServer server,
689 SilcServerEntry server_entry,
692 SilcSocketConnection backup_router = (SilcSocketConnection)context;
693 SilcServerBackupProtocolContext ctx;
694 SilcSocketConnection sock;
695 SilcIDListData idata;
700 SilcServerConfigRouter *primary;
701 primary = silc_server_config_get_primary_router(server);
703 silc_server_backup_reconnect(server,
704 primary->host, primary->port,
705 silc_server_backup_connect_primary,
710 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
711 sock = (SilcSocketConnection)server_entry->connection;
712 idata = (SilcIDListData)server_entry;
714 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
715 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
718 /* Send the CONNECTED packet back to the backup router. */
719 buffer = silc_buffer_alloc(2);
720 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
721 silc_buffer_format(buffer,
722 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
723 SILC_STR_UI_CHAR(ctx->session),
725 silc_server_packet_send(server, backup_router,
726 SILC_PACKET_RESUME_ROUTER, 0,
727 buffer->data, buffer->len, FALSE);
728 silc_buffer_free(buffer);
730 /* The primary connection is disabled until it sends the RESUMED packet
732 idata->status |= SILC_IDLIST_STATUS_DISABLED;
734 /* Move this protocol context from this backup router connection to
735 the primary router connection since it will send the subsequent
736 packets in this protocol. We don't talk with backup router
738 sock->protocol = backup_router->protocol;
739 ctx->sock = (SilcSocketConnection)server_entry->connection;
740 backup_router->protocol = NULL;
743 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
745 SilcProtocol protocol = (SilcProtocol)context;
746 SilcServerBackupProtocolContext ctx = protocol->context;
747 SilcServer server = ctx->server;
751 for (i = 0; i < ctx->sessions_count; i++)
752 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
753 ctx->session = ctx->sessions[i].session;
755 /* We've received all the CONNECTED packets and now we'll send the
756 ENDING packet to the new primary router. */
757 packet = silc_buffer_alloc(2);
758 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
759 silc_buffer_format(packet,
760 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
761 SILC_STR_UI_CHAR(ctx->session),
763 silc_server_packet_send(server, ctx->sock,
764 SILC_PACKET_RESUME_ROUTER, 0,
765 packet->data, packet->len, FALSE);
766 silc_buffer_free(packet);
768 protocol->state = SILC_PROTOCOL_STATE_END;
771 /* Backup resuming protocol. This protocol is executed when the primary
772 router wants to resume its position as being primary router. */
774 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
776 SilcProtocol protocol = (SilcProtocol)context;
777 SilcServerBackupProtocolContext ctx = protocol->context;
778 SilcServer server = ctx->server;
780 SilcIDCacheList list;
781 SilcIDCacheEntry id_cache;
782 SilcServerEntry server_entry;
785 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
786 protocol->state = SILC_PROTOCOL_STATE_START;
788 switch(protocol->state) {
789 case SILC_PROTOCOL_STATE_START:
790 if (ctx->responder == FALSE) {
791 /* Initiator of the protocol. We are backup router */
793 packet = silc_buffer_alloc(2);
794 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
796 /* Send the START packet to primary router and normal servers. */
797 if (silc_idcache_get_all(server->local_list->servers, &list)) {
798 if (silc_idcache_list_first(list, &id_cache)) {
800 server_entry = (SilcServerEntry)id_cache->context;
801 if (!server_entry || (server_entry == server->id_entry) ||
802 !server_entry->connection || !server_entry->data.send_key ||
803 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
804 if (!silc_idcache_list_next(list, &id_cache))
810 ctx->sessions = silc_realloc(ctx->sessions,
811 sizeof(*ctx->sessions) *
812 (ctx->sessions_count + 1));
813 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
814 ctx->sessions[ctx->sessions_count].connected = FALSE;
815 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
817 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
818 server_entry->server_name, ctx->sessions_count));
819 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
820 server_entry->server_name, ctx->sessions_count));
822 /* This connection is performing this protocol too now */
823 ((SilcSocketConnection)server_entry->connection)->protocol =
826 if (server_entry->server_type == SILC_ROUTER)
827 packet->data[0] = SILC_SERVER_BACKUP_START;
829 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
830 packet->data[1] = ctx->sessions_count;
831 silc_server_packet_send(server, server_entry->connection,
832 SILC_PACKET_RESUME_ROUTER, 0,
833 packet->data, packet->len, FALSE);
834 ctx->sessions_count++;
836 if (!silc_idcache_list_next(list, &id_cache))
841 silc_idcache_list_free(list);
844 if (silc_idcache_get_all(server->global_list->servers, &list)) {
845 if (silc_idcache_list_first(list, &id_cache)) {
847 server_entry = (SilcServerEntry)id_cache->context;
848 if (!server_entry || (server_entry == server->id_entry) ||
849 !server_entry->connection || !server_entry->data.send_key ||
850 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
851 if (!silc_idcache_list_next(list, &id_cache))
857 ctx->sessions = silc_realloc(ctx->sessions,
858 sizeof(*ctx->sessions) *
859 (ctx->sessions_count + 1));
860 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
861 ctx->sessions[ctx->sessions_count].connected = FALSE;
862 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
864 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
865 server_entry->server_name, ctx->sessions_count));
866 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
867 server_entry->server_name, ctx->sessions_count));
869 /* This connection is performing this protocol too now */
870 ((SilcSocketConnection)server_entry->connection)->protocol =
873 if (server_entry->server_type == SILC_ROUTER)
874 packet->data[0] = SILC_SERVER_BACKUP_START;
876 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
877 packet->data[1] = ctx->sessions_count;
878 silc_server_packet_send(server, server_entry->connection,
879 SILC_PACKET_RESUME_ROUTER, 0,
880 packet->data, packet->len, FALSE);
881 ctx->sessions_count++;
883 if (!silc_idcache_list_next(list, &id_cache))
888 silc_idcache_list_free(list);
891 silc_buffer_free(packet);
893 /* If we are not standalone and our primary is not the one we've
894 talking to now, then announce our information to it since we
895 haven't done that yet. Standalone backup router announces
896 these during connecting to the primary. */
897 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
898 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
899 silc_server_announce_clients(server, 0, ctx->sock);
900 silc_server_announce_channels(server, 0, ctx->sock);
905 /* Responder of the protocol. */
906 SilcServerConfigRouter *primary;
908 /* We should have received START or START_GLOBAL packet */
909 if (ctx->type != SILC_SERVER_BACKUP_START &&
910 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
911 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
915 /* Connect to the primary router that was down that is now supposed
916 to be back online. We send the CONNECTED packet after we've
917 established the connection to the primary router. */
918 primary = silc_server_config_get_primary_router(server);
919 if (primary && server->backup_primary &&
920 !silc_server_num_sockets_by_remote(server,
921 silc_net_is_ip(primary->host) ?
922 primary->host : NULL,
923 silc_net_is_ip(primary->host) ?
924 NULL : primary->host,
926 SILC_SOCKET_TYPE_ROUTER)) {
927 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
929 silc_server_backup_reconnect(server,
930 primary->host, primary->port,
931 silc_server_backup_connect_primary,
934 /* Nowhere to connect just return the CONNECTED packet */
935 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
937 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
940 /* Send the CONNECTED packet back to the backup router. */
941 packet = silc_buffer_alloc(2);
942 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
943 silc_buffer_format(packet,
944 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
945 SILC_STR_UI_CHAR(ctx->session),
947 silc_server_packet_send(server, ctx->sock,
948 SILC_PACKET_RESUME_ROUTER, 0,
949 packet->data, packet->len, FALSE);
950 silc_buffer_free(packet);
953 if (server->server_type == SILC_ROUTER &&
955 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
958 protocol->state = SILC_PROTOCOL_STATE_END;
960 ctx->sessions = silc_realloc(ctx->sessions,
961 sizeof(*ctx->sessions) *
962 (ctx->sessions_count + 1));
963 ctx->sessions[ctx->sessions_count].session = ctx->session;
964 ctx->sessions_count++;
969 if (ctx->responder == FALSE) {
972 /* We should have received CONNECTED packet */
973 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
974 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
978 for (i = 0; i < ctx->sessions_count; i++) {
979 if (ctx->sessions[i].session == ctx->session) {
980 ctx->sessions[i].connected = TRUE;
981 SILC_LOG_INFO(("Received CONNECTED from %s (session %d)",
982 ctx->sessions[i].server_entry->server_name,
984 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
989 for (i = 0; i < ctx->sessions_count; i++) {
990 if (!ctx->sessions[i].connected)
994 SILC_LOG_INFO(("All sessions have returned CONNECTED packets, "
996 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
998 /* Send with a timeout */
999 silc_schedule_task_add(server->schedule, 0,
1000 silc_server_backup_send_resumed,
1001 protocol, 1, 0, SILC_TASK_TIMEOUT,
1002 SILC_TASK_PRI_NORMAL);
1007 /* We should have been received ENDING packet */
1008 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
1009 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
1013 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
1015 /* This state is received by the primary router but also servers
1016 and perhaps other routers so check that if we are the primary
1017 router of the cell then start sending RESUMED packets. If we
1018 are normal server or one of those other routers then procede
1020 if (server->router &&
1021 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
1022 silc_server_config_is_primary_route(server)) {
1023 /* We'll wait for RESUMED packet */
1024 protocol->state = SILC_PROTOCOL_STATE_END;
1028 /* Switch announced informations to our primary router of using the
1030 silc_server_local_servers_toggle_enabled(server, TRUE);
1031 silc_server_update_servers_by_server(server, ctx->sock->user_data,
1033 silc_server_update_clients_by_server(server, ctx->sock->user_data,
1034 server->router, TRUE);
1035 if (server->server_type == SILC_SERVER)
1036 silc_server_update_channels_by_server(server, ctx->sock->user_data,
1039 packet = silc_buffer_alloc(2);
1040 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1042 /* We are the primary router, start sending RESUMED packets. */
1043 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1044 if (silc_idcache_list_first(list, &id_cache)) {
1046 server_entry = (SilcServerEntry)id_cache->context;
1047 if (!server_entry || (server_entry == server->id_entry) ||
1048 !server_entry->connection || !server_entry->data.send_key) {
1049 if (!silc_idcache_list_next(list, &id_cache))
1055 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1056 server_entry->server_name));
1057 SILC_LOG_INFO(("Sending RESUMED to %s",
1058 server_entry->server_name));
1060 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1062 /* This connection is performing this protocol too now */
1063 ((SilcSocketConnection)server_entry->connection)->protocol =
1066 if (server_entry->server_type == SILC_ROUTER)
1067 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1069 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1070 silc_server_packet_send(server, server_entry->connection,
1071 SILC_PACKET_RESUME_ROUTER, 0,
1072 packet->data, packet->len, FALSE);
1074 if (!silc_idcache_list_next(list, &id_cache))
1079 silc_idcache_list_free(list);
1082 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1083 if (silc_idcache_list_first(list, &id_cache)) {
1085 server_entry = (SilcServerEntry)id_cache->context;
1086 if (!server_entry || (server_entry == server->id_entry) ||
1087 !server_entry->connection || !server_entry->data.send_key) {
1088 if (!silc_idcache_list_next(list, &id_cache))
1094 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1095 server_entry->server_name));
1096 SILC_LOG_INFO(("Sending RESUMED to %s",
1097 server_entry->server_name));
1099 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1101 /* This connection is performing this protocol too now */
1102 ((SilcSocketConnection)server_entry->connection)->protocol =
1105 if (server_entry->server_type == SILC_ROUTER)
1106 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1108 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1109 silc_server_packet_send(server, server_entry->connection,
1110 SILC_PACKET_RESUME_ROUTER, 0,
1111 packet->data, packet->len, FALSE);
1113 if (!silc_idcache_list_next(list, &id_cache))
1118 silc_idcache_list_free(list);
1121 silc_buffer_free(packet);
1123 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1124 server->wait_backup = FALSE;
1126 /* For us this is the end of this protocol. */
1127 if (protocol->final_callback)
1128 silc_protocol_execute_final(protocol, server->schedule);
1130 silc_protocol_free(protocol);
1134 case SILC_PROTOCOL_STATE_END:
1136 SilcServerEntry router, backup_router;
1138 /* We should have been received RESUMED packet from our primary
1140 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1141 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1142 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1146 SILC_LOG_INFO(("Received RESUMED from new primary router"));
1148 if (server->backup_router)
1149 server->server_type = SILC_BACKUP_ROUTER;
1151 /* We have now new primary router. All traffic goes there from now on. */
1152 router = (SilcServerEntry)ctx->sock->user_data;
1153 if (silc_server_backup_replaced_get(server, router->id,
1156 if (backup_router == server->router) {
1157 /* We have new primary router now */
1158 server->id_entry->router = router;
1159 server->router = router;
1160 SILC_LOG_INFO(("Switching back to primary router %s",
1161 server->router->server_name));
1163 /* We are connected to new primary and now continue using it */
1164 SILC_LOG_INFO(("Resuming the use of primary router %s",
1165 router->server_name));
1167 server->backup_primary = FALSE;
1169 /* Update the client entries of the backup router to the new
1171 silc_server_local_servers_toggle_enabled(server, FALSE);
1172 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1173 silc_server_update_servers_by_server(server, backup_router, router);
1174 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1175 if (server->server_type == SILC_SERVER)
1176 silc_server_update_channels_by_server(server, backup_router, router);
1177 silc_server_backup_replaced_del(server, backup_router);
1179 /* Announce all of our information to the router. */
1180 if (server->server_type == SILC_ROUTER)
1181 silc_server_announce_servers(server, FALSE, ctx->start,
1182 router->connection);
1184 /* Announce our clients and channels to the router */
1185 silc_server_announce_clients(server, ctx->start,
1186 router->connection);
1187 silc_server_announce_channels(server, ctx->start,
1188 router->connection);
1191 /* Send notify about primary router going down to local operators */
1192 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1193 SILC_NOTIFY_TYPE_NONE,
1194 ("%s resumed the use of primary router %s",
1195 server->server_name,
1196 server->router->server_name));
1198 /* Protocol has ended, call the final callback */
1199 if (protocol->final_callback)
1200 silc_protocol_execute_final(protocol, server->schedule);
1202 silc_protocol_free(protocol);
1206 case SILC_PROTOCOL_STATE_ERROR:
1207 /* Protocol has ended, call the final callback */
1208 if (protocol->final_callback)
1209 silc_protocol_execute_final(protocol, server->schedule);
1211 silc_protocol_free(protocol);
1214 case SILC_PROTOCOL_STATE_FAILURE:
1215 /* Protocol has ended, call the final callback */
1216 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1217 if (protocol->final_callback)
1218 silc_protocol_execute_final(protocol, server->schedule);
1220 silc_protocol_free(protocol);
1223 case SILC_PROTOCOL_STATE_UNKNOWN:
1228 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1230 SilcProtocol protocol = (SilcProtocol)context;
1231 SilcServerBackupProtocolContext ctx = protocol->context;
1232 SilcServer server = ctx->server;
1233 SilcServerEntry server_entry;
1234 SilcSocketConnection sock;
1235 SilcIDCacheList list;
1236 SilcIDCacheEntry id_cache;
1238 silc_schedule_task_del_by_context(server->schedule, protocol);
1240 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1241 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1242 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1245 if (server->server_shutdown)
1248 /* Remove this protocol from all server entries that has it */
1249 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1250 if (silc_idcache_list_first(list, &id_cache)) {
1252 server_entry = (SilcServerEntry)id_cache->context;
1253 sock = (SilcSocketConnection)server_entry->connection;
1255 if (sock->protocol == protocol) {
1256 sock->protocol = NULL;
1258 /* Backup closes connection and reconnects if error occurred */
1259 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1260 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1261 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1262 server->backup_noswitch = TRUE;
1263 server->server_type = SILC_BACKUP_ROUTER;
1264 if (ctx->sock == sock)
1267 if (sock->user_data)
1268 silc_server_free_sock_user_data(server, sock, NULL);
1269 silc_server_close_connection(server, sock);
1270 silc_server_create_connections(server);
1272 if (!silc_idcache_list_next(list, &id_cache))
1278 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1279 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1282 if (!silc_idcache_list_next(list, &id_cache))
1286 silc_idcache_list_free(list);
1289 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1290 if (silc_idcache_list_first(list, &id_cache)) {
1292 server_entry = (SilcServerEntry)id_cache->context;
1293 sock = (SilcSocketConnection)server_entry->connection;
1295 if (sock->protocol == protocol) {
1296 sock->protocol = NULL;
1298 /* Backup closes connection and reconnects if error occurred */
1299 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1300 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1301 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1302 server->backup_noswitch = TRUE;
1303 server->server_type = SILC_BACKUP_ROUTER;
1304 if (ctx->sock == sock)
1307 if (sock->user_data)
1308 silc_server_free_sock_user_data(server, sock, NULL);
1309 silc_server_close_connection(server, sock);
1310 silc_server_create_connections(server);
1312 if (!silc_idcache_list_next(list, &id_cache))
1318 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1319 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1322 if (!silc_idcache_list_next(list, &id_cache))
1326 silc_idcache_list_free(list);
1329 if (protocol->state != SILC_PROTOCOL_STATE_ERROR &&
1330 protocol->state != SILC_PROTOCOL_STATE_FAILURE)
1331 SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
1333 if (ctx->sock && ctx->sock->protocol)
1334 ctx->sock->protocol = NULL;
1335 silc_protocol_free(protocol);
1336 silc_free(ctx->sessions);