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);
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));
716 /* Send the CONNECTED packet back to the backup router. */
717 buffer = silc_buffer_alloc(2);
718 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
719 silc_buffer_format(buffer,
720 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
721 SILC_STR_UI_CHAR(ctx->session),
723 silc_server_packet_send(server, backup_router,
724 SILC_PACKET_RESUME_ROUTER, 0,
725 buffer->data, buffer->len, FALSE);
726 silc_buffer_free(buffer);
728 /* The primary connection is disabled until it sends the RESUMED packet
730 idata->status |= SILC_IDLIST_STATUS_DISABLED;
732 /* Move this protocol context from this backup router connection to
733 the primary router connection since it will send the subsequent
734 packets in this protocol. We don't talk with backup router
736 sock->protocol = backup_router->protocol;
737 ctx->sock = (SilcSocketConnection)server_entry->connection;
738 backup_router->protocol = NULL;
741 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
743 SilcProtocol protocol = (SilcProtocol)context;
744 SilcServerBackupProtocolContext ctx = protocol->context;
745 SilcServer server = ctx->server;
749 for (i = 0; i < ctx->sessions_count; i++)
750 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
751 ctx->session = ctx->sessions[i].session;
753 /* We've received all the CONNECTED packets and now we'll send the
754 ENDING packet to the new primary router. */
755 packet = silc_buffer_alloc(2);
756 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
757 silc_buffer_format(packet,
758 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
759 SILC_STR_UI_CHAR(ctx->session),
761 silc_server_packet_send(server, ctx->sock,
762 SILC_PACKET_RESUME_ROUTER, 0,
763 packet->data, packet->len, FALSE);
764 silc_buffer_free(packet);
766 protocol->state = SILC_PROTOCOL_STATE_END;
769 /* Backup resuming protocol. This protocol is executed when the primary
770 router wants to resume its position as being primary router. */
772 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
774 SilcProtocol protocol = (SilcProtocol)context;
775 SilcServerBackupProtocolContext ctx = protocol->context;
776 SilcServer server = ctx->server;
778 SilcIDCacheList list;
779 SilcIDCacheEntry id_cache;
780 SilcServerEntry server_entry;
783 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
784 protocol->state = SILC_PROTOCOL_STATE_START;
786 switch(protocol->state) {
787 case SILC_PROTOCOL_STATE_START:
788 if (ctx->responder == FALSE) {
789 /* Initiator of the protocol. We are backup router */
791 packet = silc_buffer_alloc(2);
792 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
794 /* Send the START packet to primary router and normal servers. */
795 if (silc_idcache_get_all(server->local_list->servers, &list)) {
796 if (silc_idcache_list_first(list, &id_cache)) {
798 server_entry = (SilcServerEntry)id_cache->context;
799 if (!server_entry || (server_entry == server->id_entry) ||
800 !server_entry->connection || !server_entry->data.send_key ||
801 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
802 if (!silc_idcache_list_next(list, &id_cache))
808 ctx->sessions = silc_realloc(ctx->sessions,
809 sizeof(*ctx->sessions) *
810 (ctx->sessions_count + 1));
811 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
812 ctx->sessions[ctx->sessions_count].connected = FALSE;
813 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
815 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
816 server_entry->server_name, ctx->sessions_count));
817 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
818 server_entry->server_name, ctx->sessions_count));
820 /* This connection is performing this protocol too now */
821 ((SilcSocketConnection)server_entry->connection)->protocol =
824 if (server_entry->server_type == SILC_ROUTER)
825 packet->data[0] = SILC_SERVER_BACKUP_START;
827 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
828 packet->data[1] = ctx->sessions_count;
829 silc_server_packet_send(server, server_entry->connection,
830 SILC_PACKET_RESUME_ROUTER, 0,
831 packet->data, packet->len, FALSE);
832 ctx->sessions_count++;
834 if (!silc_idcache_list_next(list, &id_cache))
839 silc_idcache_list_free(list);
842 if (silc_idcache_get_all(server->global_list->servers, &list)) {
843 if (silc_idcache_list_first(list, &id_cache)) {
845 server_entry = (SilcServerEntry)id_cache->context;
846 if (!server_entry || (server_entry == server->id_entry) ||
847 !server_entry->connection || !server_entry->data.send_key ||
848 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
849 if (!silc_idcache_list_next(list, &id_cache))
855 ctx->sessions = silc_realloc(ctx->sessions,
856 sizeof(*ctx->sessions) *
857 (ctx->sessions_count + 1));
858 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
859 ctx->sessions[ctx->sessions_count].connected = FALSE;
860 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
862 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
863 server_entry->server_name, ctx->sessions_count));
864 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
865 server_entry->server_name, ctx->sessions_count));
867 /* This connection is performing this protocol too now */
868 ((SilcSocketConnection)server_entry->connection)->protocol =
871 if (server_entry->server_type == SILC_ROUTER)
872 packet->data[0] = SILC_SERVER_BACKUP_START;
874 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
875 packet->data[1] = ctx->sessions_count;
876 silc_server_packet_send(server, server_entry->connection,
877 SILC_PACKET_RESUME_ROUTER, 0,
878 packet->data, packet->len, FALSE);
879 ctx->sessions_count++;
881 if (!silc_idcache_list_next(list, &id_cache))
886 silc_idcache_list_free(list);
889 silc_buffer_free(packet);
891 /* If we are not standalone and our primary is not the one we've
892 talking to now, then announce our information to it since we
893 haven't done that yet. Standalone backup router announces
894 these during connecting to the primary. */
895 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
896 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
897 silc_server_announce_clients(server, 0, ctx->sock);
898 silc_server_announce_channels(server, 0, ctx->sock);
903 /* Responder of the protocol. */
904 SilcServerConfigRouter *primary;
906 /* We should have received START or START_GLOBAL packet */
907 if (ctx->type != SILC_SERVER_BACKUP_START &&
908 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
909 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
913 /* Connect to the primary router that was down that is now supposed
914 to be back online. We send the CONNECTED packet after we've
915 established the connection to the primary router. */
916 primary = silc_server_config_get_primary_router(server);
917 if (primary && server->backup_primary) {
918 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
920 silc_server_backup_reconnect(server,
921 primary->host, primary->port,
922 silc_server_backup_connect_primary,
925 /* Nowhere to connect just return the CONNECTED packet */
926 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
929 /* Send the CONNECTED packet back to the backup router. */
930 packet = silc_buffer_alloc(2);
931 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
932 silc_buffer_format(packet,
933 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
934 SILC_STR_UI_CHAR(ctx->session),
936 silc_server_packet_send(server, ctx->sock,
937 SILC_PACKET_RESUME_ROUTER, 0,
938 packet->data, packet->len, FALSE);
939 silc_buffer_free(packet);
942 if (server->server_type == SILC_ROUTER &&
944 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
947 protocol->state = SILC_PROTOCOL_STATE_END;
949 ctx->sessions = silc_realloc(ctx->sessions,
950 sizeof(*ctx->sessions) *
951 (ctx->sessions_count + 1));
952 ctx->sessions[ctx->sessions_count].session = ctx->session;
953 ctx->sessions_count++;
958 if (ctx->responder == FALSE) {
961 /* We should have received CONNECTED packet */
962 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
963 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
967 for (i = 0; i < ctx->sessions_count; i++) {
968 if (ctx->sessions[i].session == ctx->session) {
969 ctx->sessions[i].connected = TRUE;
970 SILC_LOG_INFO(("Received CONNECTED from %s (session %d)",
971 ctx->sessions[i].server_entry->server_name,
973 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
978 for (i = 0; i < ctx->sessions_count; i++) {
979 if (!ctx->sessions[i].connected)
983 SILC_LOG_INFO(("All sessions have returned CONNECTED packets, "
985 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
987 /* Send with a timeout */
988 silc_schedule_task_add(server->schedule, 0,
989 silc_server_backup_send_resumed,
990 protocol, 1, 0, SILC_TASK_TIMEOUT,
991 SILC_TASK_PRI_NORMAL);
996 /* We should have been received ENDING packet */
997 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
998 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
1002 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
1004 /* This state is received by the primary router but also servers
1005 and perhaps other routers so check that if we are the primary
1006 router of the cell then start sending RESUMED packets. If we
1007 are normal server or one of those other routers then procede
1009 if (server->router &&
1010 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
1011 silc_server_config_is_primary_route(server)) {
1012 /* We'll wait for RESUMED packet */
1013 protocol->state = SILC_PROTOCOL_STATE_END;
1017 /* Switch announced informations to our primary router of using the
1019 silc_server_local_servers_toggle_enabled(server, TRUE);
1020 silc_server_update_servers_by_server(server, ctx->sock->user_data,
1022 silc_server_update_clients_by_server(server, ctx->sock->user_data,
1023 server->router, TRUE);
1024 if (server->server_type == SILC_SERVER)
1025 silc_server_update_channels_by_server(server, ctx->sock->user_data,
1028 packet = silc_buffer_alloc(2);
1029 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1031 /* We are the primary router, start sending RESUMED packets. */
1032 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1033 if (silc_idcache_list_first(list, &id_cache)) {
1035 server_entry = (SilcServerEntry)id_cache->context;
1036 if (!server_entry || (server_entry == server->id_entry) ||
1037 !server_entry->connection || !server_entry->data.send_key) {
1038 if (!silc_idcache_list_next(list, &id_cache))
1044 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1045 server_entry->server_name));
1047 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1049 /* This connection is performing this protocol too now */
1050 ((SilcSocketConnection)server_entry->connection)->protocol =
1053 if (server_entry->server_type == SILC_ROUTER)
1054 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1056 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1057 silc_server_packet_send(server, server_entry->connection,
1058 SILC_PACKET_RESUME_ROUTER, 0,
1059 packet->data, packet->len, FALSE);
1061 if (!silc_idcache_list_next(list, &id_cache))
1066 silc_idcache_list_free(list);
1069 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1070 if (silc_idcache_list_first(list, &id_cache)) {
1072 server_entry = (SilcServerEntry)id_cache->context;
1073 if (!server_entry || (server_entry == server->id_entry) ||
1074 !server_entry->connection || !server_entry->data.send_key) {
1075 if (!silc_idcache_list_next(list, &id_cache))
1081 SILC_LOG_DEBUG(("Sending RESUMED to %s",
1082 server_entry->server_name));
1084 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1086 /* This connection is performing this protocol too now */
1087 ((SilcSocketConnection)server_entry->connection)->protocol =
1090 if (server_entry->server_type == SILC_ROUTER)
1091 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1093 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1094 silc_server_packet_send(server, server_entry->connection,
1095 SILC_PACKET_RESUME_ROUTER, 0,
1096 packet->data, packet->len, FALSE);
1098 if (!silc_idcache_list_next(list, &id_cache))
1103 silc_idcache_list_free(list);
1106 silc_buffer_free(packet);
1108 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1109 server->wait_backup = FALSE;
1111 /* For us this is the end of this protocol. */
1112 if (protocol->final_callback)
1113 silc_protocol_execute_final(protocol, server->schedule);
1115 silc_protocol_free(protocol);
1119 case SILC_PROTOCOL_STATE_END:
1121 SilcServerEntry router, backup_router;
1123 /* We should have been received RESUMED packet from our primary
1125 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1126 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1127 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1131 SILC_LOG_INFO(("Received RESUMED from new primary router"));
1133 if (server->backup_router)
1134 server->server_type = SILC_BACKUP_ROUTER;
1136 /* We have now new primary router. All traffic goes there from now on. */
1137 router = (SilcServerEntry)ctx->sock->user_data;
1138 if (silc_server_backup_replaced_get(server, router->id,
1141 if (backup_router == server->router) {
1142 /* We have new primary router now */
1143 server->id_entry->router = router;
1144 server->router = router;
1145 SILC_LOG_INFO(("Switching back to primary router %s",
1146 server->router->server_name));
1148 /* We are connected to new primary and now continue using it */
1149 SILC_LOG_INFO(("Resuming the use of primary router %s",
1150 router->server_name));
1153 /* Update the client entries of the backup router to the new
1155 silc_server_local_servers_toggle_enabled(server, FALSE);
1156 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1157 silc_server_update_servers_by_server(server, backup_router, router);
1158 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1159 if (server->server_type == SILC_SERVER)
1160 silc_server_update_channels_by_server(server, backup_router, router);
1161 silc_server_backup_replaced_del(server, backup_router);
1163 /* Announce all of our information to the router. */
1164 if (server->server_type == SILC_ROUTER)
1165 silc_server_announce_servers(server, FALSE, ctx->start,
1166 router->connection);
1168 /* Announce our clients and channels to the router */
1169 silc_server_announce_clients(server, ctx->start,
1170 router->connection);
1171 silc_server_announce_channels(server, ctx->start,
1172 router->connection);
1175 /* Send notify about primary router going down to local operators */
1176 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1177 SILC_NOTIFY_TYPE_NONE,
1178 ("%s resumed the use of primary router %s",
1179 server->server_name,
1180 server->router->server_name));
1182 /* Protocol has ended, call the final callback */
1183 if (protocol->final_callback)
1184 silc_protocol_execute_final(protocol, server->schedule);
1186 silc_protocol_free(protocol);
1190 case SILC_PROTOCOL_STATE_ERROR:
1191 /* Protocol has ended, call the final callback */
1192 if (protocol->final_callback)
1193 silc_protocol_execute_final(protocol, server->schedule);
1195 silc_protocol_free(protocol);
1198 case SILC_PROTOCOL_STATE_FAILURE:
1199 /* Protocol has ended, call the final callback */
1200 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1201 if (protocol->final_callback)
1202 silc_protocol_execute_final(protocol, server->schedule);
1204 silc_protocol_free(protocol);
1207 case SILC_PROTOCOL_STATE_UNKNOWN:
1212 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1214 SilcProtocol protocol = (SilcProtocol)context;
1215 SilcServerBackupProtocolContext ctx = protocol->context;
1216 SilcServer server = ctx->server;
1217 SilcServerEntry server_entry;
1218 SilcSocketConnection sock;
1219 SilcIDCacheList list;
1220 SilcIDCacheEntry id_cache;
1222 silc_schedule_task_del_by_context(server->schedule, protocol);
1224 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1225 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1226 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1229 if (server->server_shutdown)
1232 /* Remove this protocol from all server entries that has it */
1233 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1234 if (silc_idcache_list_first(list, &id_cache)) {
1236 server_entry = (SilcServerEntry)id_cache->context;
1237 sock = (SilcSocketConnection)server_entry->connection;
1239 if (sock->protocol == protocol) {
1240 sock->protocol = NULL;
1242 /* Backup closes connection and reconnects if error occurred */
1243 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1244 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1245 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1246 server->backup_noswitch = TRUE;
1247 server->server_type = SILC_BACKUP_ROUTER;
1249 if (sock->user_data)
1250 silc_server_free_sock_user_data(server, sock, NULL);
1251 silc_server_close_connection(server, sock);
1253 silc_schedule_task_add(server->schedule, 0,
1254 silc_server_connect_to_router,
1257 SILC_TASK_PRI_NORMAL);
1259 if (!silc_idcache_list_next(list, &id_cache))
1265 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1266 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1269 if (!silc_idcache_list_next(list, &id_cache))
1273 silc_idcache_list_free(list);
1276 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1277 if (silc_idcache_list_first(list, &id_cache)) {
1279 server_entry = (SilcServerEntry)id_cache->context;
1280 sock = (SilcSocketConnection)server_entry->connection;
1282 if (sock->protocol == protocol) {
1283 sock->protocol = NULL;
1285 /* Backup closes connection and reconnects if error occurred */
1286 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1287 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1288 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1289 server->backup_noswitch = TRUE;
1290 server->server_type = SILC_BACKUP_ROUTER;
1292 if (sock->user_data)
1293 silc_server_free_sock_user_data(server, sock, NULL);
1294 silc_server_close_connection(server, sock);
1296 silc_schedule_task_add(server->schedule, 0,
1297 silc_server_connect_to_router,
1300 SILC_TASK_PRI_NORMAL);
1302 if (!silc_idcache_list_next(list, &id_cache))
1308 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1309 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1312 if (!silc_idcache_list_next(list, &id_cache))
1316 silc_idcache_list_free(list);
1319 if (protocol->state != SILC_PROTOCOL_STATE_ERROR &&
1320 protocol->state != SILC_PROTOCOL_STATE_FAILURE)
1321 SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
1323 if (ctx->sock->protocol)
1324 ctx->sock->protocol = NULL;
1325 silc_protocol_free(protocol);
1326 silc_free(ctx->sessions);