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 = htons(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 = htons(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);
339 /* A generic routine to send data to all backup routers. If the `sender'
340 is provided it will indicate the original sender of the packet and the
341 packet won't be resent to that entity. The `data' is the data that will
342 be assembled to packet context before sending. The packet will be
343 encrypted this function. If the `force_send' is TRUE the data is sent
344 immediately and not put to queue. If `local' is TRUE then the packet
345 will be sent only to local backup routers inside the cell. If false the
346 packet can go from one cell to the other. This function has no effect
347 if there are no any backup routers. */
349 void silc_server_backup_send(SilcServer server,
350 SilcServerEntry sender,
352 SilcPacketFlags flags,
358 SilcServerEntry backup;
359 SilcSocketConnection sock;
362 if (!server->backup || server->server_type != SILC_ROUTER)
365 for (i = 0; i < server->backup->servers_count; i++) {
366 backup = server->backup->servers[i].server;
367 if (!backup || sender == backup)
369 if (local && server->backup->servers[i].local == FALSE)
371 if (server->backup->servers[i].server == server->id_entry)
374 sock = backup->connection;
376 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
377 silc_get_packet_name(type), sock->hostname, sock->ip));
379 silc_server_packet_send(server, backup->connection, type, flags,
380 data, data_len, force_send);
384 /* Same as silc_server_backup_send but sets a specific Destination ID to
385 the packet. The Destination ID is indicated by the `dst_id' and the
386 ID type `dst_id_type'. For example, packets destined to channels must
387 be sent using this function. */
389 void silc_server_backup_send_dest(SilcServer server,
390 SilcServerEntry sender,
392 SilcPacketFlags flags,
394 SilcIdType dst_id_type,
400 SilcServerEntry backup;
401 SilcSocketConnection sock;
404 if (!server->backup || server->server_type != SILC_ROUTER)
407 for (i = 0; i < server->backup->servers_count; i++) {
408 backup = server->backup->servers[i].server;
409 if (!backup || sender == backup)
411 if (local && server->backup->servers[i].local == FALSE)
413 if (server->backup->servers[i].server == server->id_entry)
416 sock = backup->connection;
418 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
419 silc_get_packet_name(type), sock->hostname, sock->ip));
421 silc_server_packet_send_dest(server, backup->connection, type, flags,
422 dst_id, dst_id_type, data, data_len,
427 /* Processes incoming RESUME_ROUTER packet. This can give the packet
428 for processing to the protocol handler or allocate new protocol if
429 start command is received. */
431 void silc_server_backup_resume_router(SilcServer server,
432 SilcSocketConnection sock,
433 SilcPacketContext *packet)
435 SilcUInt8 type, session;
436 SilcServerBackupProtocolContext ctx;
439 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
440 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
441 SILC_LOG_DEBUG(("Bad packet received"));
445 ret = silc_buffer_unformat(packet->buffer,
446 SILC_STR_UI_CHAR(&type),
447 SILC_STR_UI_CHAR(&session),
450 SILC_LOG_ERROR(("Malformed resume router packet received"));
454 /* Activate the protocol for this socket if necessary */
455 if ((type == SILC_SERVER_BACKUP_RESUMED ||
456 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
457 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
458 ((SilcIDListData)sock->user_data)->status &
459 SILC_IDLIST_STATUS_DISABLED) {
460 SilcServerEntry backup_router;
462 if (silc_server_backup_replaced_get(server,
463 ((SilcServerEntry)sock->
466 SilcSocketConnection bsock =
467 (SilcSocketConnection)backup_router->connection;
468 if (bsock->protocol && bsock->protocol->protocol &&
469 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
470 sock->protocol = bsock->protocol;
471 ctx = sock->protocol->context;
477 /* If the backup resuming protocol is active then process the packet
479 if (sock->protocol && sock->protocol->protocol &&
480 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
481 ctx = sock->protocol->context;
484 if (type != SILC_SERVER_BACKUP_RESUMED &&
485 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
486 for (i = 0; i < ctx->sessions_count; i++) {
487 if (session == ctx->sessions[i].session) {
488 ctx->session = session;
489 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
494 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
498 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
502 /* We don't have protocol active. If we are router and the packet is
503 coming from our primary router then lets check whether it means we've
504 been replaced by an backup router in my cell. This is usually received
505 immediately after we've connected to our primary router. */
507 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
508 sock && SILC_PRIMARY_ROUTE(server) == sock &&
509 type == SILC_SERVER_BACKUP_REPLACED) {
510 /* We have been replaced by an backup router in our cell. We must
511 mark our primary router connection disabled since we are not allowed
512 to use it at this moment. */
513 SilcIDListData idata = (SilcIDListData)sock->user_data;
514 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
515 "wait until backup resuming protocol is executed"));
516 idata->status |= SILC_IDLIST_STATUS_DISABLED;
520 if (type == SILC_SERVER_BACKUP_START ||
521 type == SILC_SERVER_BACKUP_START_GLOBAL) {
522 /* We have received a start for resuming protocol. */
523 SilcServerBackupProtocolContext proto_ctx;
525 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
526 proto_ctx->server = server;
527 proto_ctx->sock = sock;
528 proto_ctx->responder = TRUE;
529 proto_ctx->type = type;
530 proto_ctx->session = session;
531 proto_ctx->start = time(0);
533 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
534 SILC_LOG_INFO(("Starting backup resuming protocol"));
536 /* Run the backup resuming protocol */
537 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
538 &sock->protocol, proto_ctx,
539 silc_server_protocol_backup_done);
540 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
544 /* Timeout task callback to connect to remote router */
546 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
548 SilcServer server = app_context;
549 SilcServerConnection sconn = (SilcServerConnection)context;
551 const char *server_ip;
553 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
554 sconn->remote_port));
556 /* Connect to remote host */
557 server_ip = server->config->server_info->primary == NULL ? NULL :
558 server->config->server_info->primary->server_ip;
559 sock = silc_net_create_connection(server_ip, sconn->remote_port,
562 silc_schedule_task_add(server->schedule, 0,
563 silc_server_backup_connect_to_router,
564 context, 5, 0, SILC_TASK_TIMEOUT,
565 SILC_TASK_PRI_NORMAL);
569 /* Continue with key exchange protocol */
570 silc_server_start_key_exchange(server, sconn, sock);
573 /* Constantly tries to reconnect to a primary router indicated by the
574 `ip' and `port'. The `connected' callback will be called when the
575 connection is created. */
577 void silc_server_backup_reconnect(SilcServer server,
578 const char *ip, SilcUInt16 port,
579 SilcServerConnectRouterCallback callback,
582 SilcServerConnection sconn;
584 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
586 sconn = silc_calloc(1, sizeof(*sconn));
587 sconn->remote_host = strdup(ip);
588 sconn->remote_port = port;
589 sconn->callback = callback;
590 sconn->callback_context = context;
591 sconn->no_reconnect = TRUE;
592 silc_schedule_task_add(server->schedule, 0,
593 silc_server_backup_connect_to_router,
594 sconn, 1, 0, SILC_TASK_TIMEOUT,
595 SILC_TASK_PRI_NORMAL);
598 /* Task that is called after backup router has connected back to
599 primary router and we are starting the resuming protocol */
601 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
603 SilcServerBackupProtocolContext proto_ctx =
604 (SilcServerBackupProtocolContext)context;
605 SilcServer server = proto_ctx->server;
606 SilcSocketConnection sock = proto_ctx->sock;
608 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
609 SILC_LOG_INFO(("Starting backup resuming protocol"));
611 /* Run the backup resuming protocol */
612 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
613 &sock->protocol, proto_ctx,
614 silc_server_protocol_backup_done);
615 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
618 /* Called when we've established connection back to our primary router
619 when we've acting as backup router and have replaced the primary router
620 in the cell. This function will start the backup resuming protocol. */
622 void silc_server_backup_connected(SilcServer server,
623 SilcServerEntry server_entry,
626 SilcServerBackupProtocolContext proto_ctx;
627 SilcSocketConnection sock;
631 SilcServerConfigRouter *primary;
632 primary = silc_server_config_get_primary_router(server);
634 silc_server_backup_reconnect(server,
635 primary->host, primary->port,
636 silc_server_backup_connected,
641 sock = (SilcSocketConnection)server_entry->connection;
642 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
643 proto_ctx->server = server;
644 proto_ctx->sock = sock;
645 proto_ctx->responder = FALSE;
646 proto_ctx->type = SILC_SERVER_BACKUP_START;
647 proto_ctx->start = time(0);
649 /* Start through scheduler */
650 silc_schedule_task_add(server->schedule, 0,
651 silc_server_backup_connected_later,
654 SILC_TASK_PRI_NORMAL);
657 /* Called when normal server has connected to its primary router after
658 backup router has sent the START packet in reusming protocol. We will
659 move the protocol context from the backup router connection to the
662 static void silc_server_backup_connect_primary(SilcServer server,
663 SilcServerEntry server_entry,
666 SilcSocketConnection backup_router = (SilcSocketConnection)context;
667 SilcServerBackupProtocolContext ctx;
668 SilcSocketConnection sock;
669 SilcIDListData idata;
674 SilcServerConfigRouter *primary;
675 primary = silc_server_config_get_primary_router(server);
677 silc_server_backup_reconnect(server,
678 primary->host, primary->port,
679 silc_server_backup_connect_primary,
684 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
685 sock = (SilcSocketConnection)server_entry->connection;
686 idata = (SilcIDListData)server_entry;
688 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
690 /* Send the CONNECTED packet back to the backup router. */
691 buffer = silc_buffer_alloc(2);
692 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
693 silc_buffer_format(buffer,
694 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
695 SILC_STR_UI_CHAR(ctx->session),
697 silc_server_packet_send(server, backup_router,
698 SILC_PACKET_RESUME_ROUTER, 0,
699 buffer->data, buffer->len, FALSE);
700 silc_buffer_free(buffer);
702 /* The primary connection is disabled until it sends the RESUMED packet
704 idata->status |= SILC_IDLIST_STATUS_DISABLED;
706 /* Move this protocol context from this backup router connection to
707 the primary router connection since it will send the subsequent
708 packets in this protocol. We don't talk with backup router
710 sock->protocol = backup_router->protocol;
711 ctx->sock = (SilcSocketConnection)server_entry->connection;
712 backup_router->protocol = NULL;
715 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
717 SilcProtocol protocol = (SilcProtocol)context;
718 SilcServerBackupProtocolContext ctx = protocol->context;
719 SilcServer server = ctx->server;
723 for (i = 0; i < ctx->sessions_count; i++)
724 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
725 ctx->session = ctx->sessions[i].session;
727 /* We've received all the CONNECTED packets and now we'll send the
728 ENDING packet to the new primary router. */
729 packet = silc_buffer_alloc(2);
730 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
731 silc_buffer_format(packet,
732 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
733 SILC_STR_UI_CHAR(ctx->session),
735 silc_server_packet_send(server, ctx->sock,
736 SILC_PACKET_RESUME_ROUTER, 0,
737 packet->data, packet->len, FALSE);
738 silc_buffer_free(packet);
740 protocol->state = SILC_PROTOCOL_STATE_END;
743 /* Backup resuming protocol. This protocol is executed when the primary
744 router wants to resume its position as being primary router. */
746 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
748 SilcProtocol protocol = (SilcProtocol)context;
749 SilcServerBackupProtocolContext ctx = protocol->context;
750 SilcServer server = ctx->server;
752 SilcIDCacheList list;
753 SilcIDCacheEntry id_cache;
754 SilcServerEntry server_entry;
757 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
758 protocol->state = SILC_PROTOCOL_STATE_START;
760 switch(protocol->state) {
761 case SILC_PROTOCOL_STATE_START:
762 if (ctx->responder == FALSE) {
763 /* Initiator of the protocol. We are backup router */
765 packet = silc_buffer_alloc(2);
766 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
768 /* Send the START packet to primary router and normal servers. */
769 if (silc_idcache_get_all(server->local_list->servers, &list)) {
770 if (silc_idcache_list_first(list, &id_cache)) {
772 server_entry = (SilcServerEntry)id_cache->context;
773 if (!server_entry || (server_entry == server->id_entry) ||
774 !server_entry->connection || !server_entry->data.send_key ||
775 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
776 if (!silc_idcache_list_next(list, &id_cache))
782 ctx->sessions = silc_realloc(ctx->sessions,
783 sizeof(*ctx->sessions) *
784 (ctx->sessions_count + 1));
785 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
786 ctx->sessions[ctx->sessions_count].connected = FALSE;
787 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
789 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
790 server_entry->server_name, ctx->sessions_count));
792 /* This connection is performing this protocol too now */
793 ((SilcSocketConnection)server_entry->connection)->protocol =
796 if (server_entry->server_type == SILC_ROUTER)
797 packet->data[0] = SILC_SERVER_BACKUP_START;
799 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
800 packet->data[1] = ctx->sessions_count;
801 silc_server_packet_send(server, server_entry->connection,
802 SILC_PACKET_RESUME_ROUTER, 0,
803 packet->data, packet->len, FALSE);
804 ctx->sessions_count++;
806 if (!silc_idcache_list_next(list, &id_cache))
811 silc_idcache_list_free(list);
814 if (silc_idcache_get_all(server->global_list->servers, &list)) {
815 if (silc_idcache_list_first(list, &id_cache)) {
817 server_entry = (SilcServerEntry)id_cache->context;
818 if (!server_entry || (server_entry == server->id_entry) ||
819 !server_entry->connection || !server_entry->data.send_key ||
820 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
821 if (!silc_idcache_list_next(list, &id_cache))
827 ctx->sessions = silc_realloc(ctx->sessions,
828 sizeof(*ctx->sessions) *
829 (ctx->sessions_count + 1));
830 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
831 ctx->sessions[ctx->sessions_count].connected = FALSE;
832 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
834 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
835 server_entry->server_name, ctx->sessions_count));
837 /* This connection is performing this protocol too now */
838 ((SilcSocketConnection)server_entry->connection)->protocol =
841 if (server_entry->server_type == SILC_ROUTER)
842 packet->data[0] = SILC_SERVER_BACKUP_START;
844 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
845 packet->data[1] = ctx->sessions_count;
846 silc_server_packet_send(server, server_entry->connection,
847 SILC_PACKET_RESUME_ROUTER, 0,
848 packet->data, packet->len, FALSE);
849 ctx->sessions_count++;
851 if (!silc_idcache_list_next(list, &id_cache))
856 silc_idcache_list_free(list);
859 silc_buffer_free(packet);
861 /* If we are not standalone and our primary is not the one we've
862 talking to now, then announce our information to it since we
863 haven't done that yet. Standalone backup router announces
864 these during connecting to the primary. */
865 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
866 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
867 silc_server_announce_clients(server, 0, ctx->sock);
868 silc_server_announce_channels(server, 0, ctx->sock);
873 /* Responder of the protocol. */
874 SilcServerConfigRouter *primary;
876 /* We should have received START or START_GLOBAL packet */
877 if (ctx->type != SILC_SERVER_BACKUP_START &&
878 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
879 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
883 /* Connect to the primary router that was down that is now supposed
884 to be back online. We send the CONNECTED packet after we've
885 established the connection to the primary router. */
886 primary = silc_server_config_get_primary_router(server);
887 if (primary && server->backup_primary) {
888 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
890 silc_server_backup_reconnect(server,
891 primary->host, primary->port,
892 silc_server_backup_connect_primary,
895 /* Nowhere to connect just return the CONNECTED packet */
896 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
899 /* Send the CONNECTED packet back to the backup router. */
900 packet = silc_buffer_alloc(2);
901 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
902 silc_buffer_format(packet,
903 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
904 SILC_STR_UI_CHAR(ctx->session),
906 silc_server_packet_send(server, ctx->sock,
907 SILC_PACKET_RESUME_ROUTER, 0,
908 packet->data, packet->len, FALSE);
909 silc_buffer_free(packet);
912 if (server->server_type == SILC_ROUTER &&
914 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
917 protocol->state = SILC_PROTOCOL_STATE_END;
919 ctx->sessions = silc_realloc(ctx->sessions,
920 sizeof(*ctx->sessions) *
921 (ctx->sessions_count + 1));
922 ctx->sessions[ctx->sessions_count].session = ctx->session;
923 ctx->sessions_count++;
928 if (ctx->responder == FALSE) {
931 /* We should have received CONNECTED packet */
932 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
933 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
937 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
939 for (i = 0; i < ctx->sessions_count; i++) {
940 if (ctx->sessions[i].session == ctx->session) {
941 ctx->sessions[i].connected = TRUE;
946 for (i = 0; i < ctx->sessions_count; i++) {
947 if (!ctx->sessions[i].connected)
951 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
952 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
954 /* Send with a timeout */
955 silc_schedule_task_add(server->schedule, 0,
956 silc_server_backup_send_resumed,
957 protocol, 1, 0, SILC_TASK_TIMEOUT,
958 SILC_TASK_PRI_NORMAL);
963 /* We should have been received ENDING packet */
964 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
965 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
969 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
971 /* This state is received by the primary router but also servers
972 and perhaps other routers so check that if we are the primary
973 router of the cell then start sending RESUMED packets. If we
974 are normal server or one of those other routers then procede
976 if (server->router &&
977 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
978 silc_server_config_is_primary_route(server)) {
979 /* We'll wait for RESUMED packet */
980 protocol->state = SILC_PROTOCOL_STATE_END;
984 /* Switch announced informations to our primary router of using the
986 silc_server_local_servers_toggle_enabled(server, TRUE);
987 silc_server_update_servers_by_server(server, ctx->sock->user_data,
989 silc_server_update_clients_by_server(server, ctx->sock->user_data,
990 server->router, TRUE);
991 if (server->server_type == SILC_SERVER)
992 silc_server_update_channels_by_server(server, ctx->sock->user_data,
995 packet = silc_buffer_alloc(2);
996 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
998 /* We are the primary router, start sending RESUMED packets. */
999 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1000 if (silc_idcache_list_first(list, &id_cache)) {
1002 server_entry = (SilcServerEntry)id_cache->context;
1003 if (!server_entry || (server_entry == server->id_entry) ||
1004 !server_entry->connection || !server_entry->data.send_key) {
1005 if (!silc_idcache_list_next(list, &id_cache))
1011 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1012 server_entry->server_name));
1014 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1016 /* This connection is performing this protocol too now */
1017 ((SilcSocketConnection)server_entry->connection)->protocol =
1020 if (server_entry->server_type == SILC_ROUTER)
1021 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1023 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1024 silc_server_packet_send(server, server_entry->connection,
1025 SILC_PACKET_RESUME_ROUTER, 0,
1026 packet->data, packet->len, FALSE);
1028 if (!silc_idcache_list_next(list, &id_cache))
1033 silc_idcache_list_free(list);
1036 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1037 if (silc_idcache_list_first(list, &id_cache)) {
1039 server_entry = (SilcServerEntry)id_cache->context;
1040 if (!server_entry || (server_entry == server->id_entry) ||
1041 !server_entry->connection || !server_entry->data.send_key) {
1042 if (!silc_idcache_list_next(list, &id_cache))
1048 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1049 server_entry->server_name));
1051 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1053 /* This connection is performing this protocol too now */
1054 ((SilcSocketConnection)server_entry->connection)->protocol =
1057 if (server_entry->server_type == SILC_ROUTER)
1058 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1060 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1061 silc_server_packet_send(server, server_entry->connection,
1062 SILC_PACKET_RESUME_ROUTER, 0,
1063 packet->data, packet->len, FALSE);
1065 if (!silc_idcache_list_next(list, &id_cache))
1070 silc_idcache_list_free(list);
1073 silc_buffer_free(packet);
1075 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1076 server->wait_backup = FALSE;
1078 /* For us this is the end of this protocol. */
1079 if (protocol->final_callback)
1080 silc_protocol_execute_final(protocol, server->schedule);
1082 silc_protocol_free(protocol);
1086 case SILC_PROTOCOL_STATE_END:
1088 SilcServerEntry router, backup_router;
1090 /* We should have been received RESUMED packet from our primary
1092 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1093 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1094 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1098 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1100 if (server->backup_router)
1101 server->server_type = SILC_BACKUP_ROUTER;
1103 /* We have now new primary router. All traffic goes there from now on. */
1104 router = (SilcServerEntry)ctx->sock->user_data;
1105 if (silc_server_backup_replaced_get(server, router->id,
1108 if (backup_router == server->router) {
1109 /* We have new primary router now */
1110 server->id_entry->router = router;
1111 server->router = router;
1112 SILC_LOG_INFO(("Switching back to primary router %s",
1113 server->router->server_name));
1115 /* We are connected to new primary and now continue using it */
1116 SILC_LOG_INFO(("Resuming the use of primary router %s",
1117 router->server_name));
1120 /* Update the client entries of the backup router to the new
1122 silc_server_local_servers_toggle_enabled(server, FALSE);
1123 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1124 silc_server_update_servers_by_server(server, backup_router, router);
1125 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1126 if (server->server_type == SILC_SERVER)
1127 silc_server_update_channels_by_server(server, backup_router, router);
1128 silc_server_backup_replaced_del(server, backup_router);
1130 /* Announce all of our information to the router. */
1131 if (server->server_type == SILC_ROUTER)
1132 silc_server_announce_servers(server, FALSE, ctx->start,
1133 router->connection);
1135 /* Announce our clients and channels to the router */
1136 silc_server_announce_clients(server, ctx->start,
1137 router->connection);
1138 silc_server_announce_channels(server, ctx->start,
1139 router->connection);
1142 /* Send notify about primary router going down to local operators */
1143 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1144 SILC_NOTIFY_TYPE_NONE,
1145 ("%s resumed the use of primary router %s",
1146 server->server_name,
1147 server->router->server_name));
1149 /* Protocol has ended, call the final callback */
1150 if (protocol->final_callback)
1151 silc_protocol_execute_final(protocol, server->schedule);
1153 silc_protocol_free(protocol);
1157 case SILC_PROTOCOL_STATE_ERROR:
1158 /* Protocol has ended, call the final callback */
1159 if (protocol->final_callback)
1160 silc_protocol_execute_final(protocol, server->schedule);
1162 silc_protocol_free(protocol);
1165 case SILC_PROTOCOL_STATE_FAILURE:
1166 /* Protocol has ended, call the final callback */
1167 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1168 if (protocol->final_callback)
1169 silc_protocol_execute_final(protocol, server->schedule);
1171 silc_protocol_free(protocol);
1174 case SILC_PROTOCOL_STATE_UNKNOWN:
1179 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1181 SilcProtocol protocol = (SilcProtocol)context;
1182 SilcServerBackupProtocolContext ctx = protocol->context;
1183 SilcServer server = ctx->server;
1184 SilcServerEntry server_entry;
1185 SilcSocketConnection sock;
1186 SilcIDCacheList list;
1187 SilcIDCacheEntry id_cache;
1189 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1190 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1191 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1194 /* Remove this protocol from all server entries that has it */
1195 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1196 if (silc_idcache_list_first(list, &id_cache)) {
1198 server_entry = (SilcServerEntry)id_cache->context;
1199 sock = (SilcSocketConnection)server_entry->connection;
1201 if (sock->protocol == protocol) {
1202 sock->protocol = NULL;
1204 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1205 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1208 if (!silc_idcache_list_next(list, &id_cache))
1212 silc_idcache_list_free(list);
1215 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1216 if (silc_idcache_list_first(list, &id_cache)) {
1218 server_entry = (SilcServerEntry)id_cache->context;
1219 sock = (SilcSocketConnection)server_entry->connection;
1221 if (sock->protocol == protocol) {
1222 sock->protocol = NULL;
1224 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1225 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1228 if (!silc_idcache_list_next(list, &id_cache))
1232 silc_idcache_list_free(list);
1235 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1237 if (ctx->sock->protocol)
1238 ctx->sock->protocol = NULL;
1239 silc_protocol_free(protocol);
1240 silc_free(ctx->sessions);