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);
28 SilcServerEntry server;
32 } SilcServerBackupEntry;
34 /* Holds IP address and port of the primary router that was replaced
39 SilcServerEntry server; /* Backup router that replaced the primary */
40 } SilcServerBackupReplaced;
43 struct SilcServerBackupStruct {
44 SilcServerBackupEntry *servers;
45 SilcUInt32 servers_count;
46 SilcServerBackupReplaced **replaced;
47 SilcUInt32 replaced_count;
53 SilcServerEntry server_entry;
54 } SilcServerBackupProtocolSession;
56 /* Backup resuming protocol context */
59 SilcSocketConnection sock;
63 SilcServerBackupProtocolSession *sessions;
64 SilcUInt32 sessions_count;
66 } *SilcServerBackupProtocolContext;
68 /* Adds the `backup_server' to be one of our backup router. This can be
69 called multiple times to set multiple backup routers. The `ip' and `port'
70 is the IP and port that the `backup_router' will replace if the `ip'
71 will become unresponsive. If `local' is TRUE then the `backup_server' is
72 in the local cell, if FALSE it is in some other cell. */
74 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
75 const char *ip, int port, bool local)
82 if (!server->backup) {
83 server->backup = silc_calloc(1, sizeof(*server->backup));
88 SILC_LOG_DEBUG(("Backup router %s will replace %s",
89 ((SilcSocketConnection)backup_server->connection)->ip,
92 for (i = 0; i < server->backup->servers_count; i++) {
93 if (!server->backup->servers[i].server) {
94 server->backup->servers[i].server = backup_server;
95 server->backup->servers[i].local = local;
96 memset(server->backup->servers[i].ip.data, 0,
97 sizeof(server->backup->servers[i].ip.data));
98 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
99 sizeof(server->backup->servers[i].ip.data));
104 i = server->backup->servers_count;
105 server->backup->servers = silc_realloc(server->backup->servers,
106 sizeof(*server->backup->servers) *
108 server->backup->servers[i].server = backup_server;
109 server->backup->servers[i].local = local;
110 memset(server->backup->servers[i].ip.data, 0,
111 sizeof(server->backup->servers[i].ip.data));
112 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
113 sizeof(server->backup->servers[i].ip.data));
114 server->backup->servers_count++;
117 /* Returns backup router for IP and port in `replacing' or NULL if there
118 does not exist backup router. */
120 SilcServerEntry silc_server_backup_get(SilcServer server,
121 SilcServerID *server_id)
128 for (i = 0; i < server->backup->servers_count; i++) {
129 if (server->backup->servers[i].server &&
130 !memcmp(&server->backup->servers[i].ip, &server_id->ip.data,
131 sizeof(server_id->ip.data))) {
132 SILC_LOG_DEBUG(("Found backup router %s for %s",
133 server->backup->servers[i].server->server_name,
134 silc_id_render(server_id, SILC_ID_SERVER)));
135 return server->backup->servers[i].server;
142 /* Deletes the backup server `server_entry'. */
144 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
151 for (i = 0; i < server->backup->servers_count; i++) {
152 if (server->backup->servers[i].server == server_entry) {
153 SILC_LOG_DEBUG(("Removing %s as backup router",
154 silc_id_render(server->backup->servers[i].server->id,
156 server->backup->servers[i].server = NULL;
157 memset(server->backup->servers[i].ip.data, 0,
158 sizeof(server->backup->servers[i].ip.data));
163 /* Marks the IP address and port from the `server_id' as being replaced
164 by backup router indicated by the `server'. If the router connects at
165 a later time we can check whether it has been replaced by an backup
168 void silc_server_backup_replaced_add(SilcServer server,
169 SilcServerID *server_id,
170 SilcServerEntry server_entry)
173 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
176 server->backup = silc_calloc(1, sizeof(*server->backup));
177 if (!server->backup->replaced) {
178 server->backup->replaced =
179 silc_calloc(1, sizeof(*server->backup->replaced));
180 server->backup->replaced_count = 1;
183 SILC_LOG_DEBUG(("Replacing router %s with %s backup",
184 silc_id_render(server_id, SILC_ID_SERVER),
185 server_entry->server_name));
187 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
188 r->server = server_entry;
190 for (i = 0; i < server->backup->replaced_count; i++) {
191 if (!server->backup->replaced[i]) {
192 server->backup->replaced[i] = r;
197 i = server->backup->replaced_count;
198 server->backup->replaced = silc_realloc(server->backup->replaced,
199 sizeof(*server->backup->replaced) *
201 server->backup->replaced[i] = r;
202 server->backup->replaced_count++;
205 /* Checks whether the IP address and port from the `server_id' has been
206 replaced by an backup router. If it has been then this returns TRUE
207 and the bacup router entry to the `server' pointer if non-NULL. Returns
208 FALSE if the router is not replaced by backup router. */
210 bool silc_server_backup_replaced_get(SilcServer server,
211 SilcServerID *server_id,
212 SilcServerEntry *server_entry)
216 if (!server->backup || !server->backup->replaced)
219 for (i = 0; i < server->backup->replaced_count; i++) {
220 if (!server->backup->replaced[i])
222 if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip.data,
223 sizeof(server_id->ip.data))) {
225 *server_entry = server->backup->replaced[i]->server;
226 SILC_LOG_DEBUG(("Router %s is replaced by %s",
227 silc_id_render(server_id, SILC_ID_SERVER),
228 server->backup->replaced[i]->server->server_name));
233 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
234 silc_id_render(server_id, SILC_ID_SERVER)));
238 /* Deletes a replaced host by the set `server_entry. */
240 void silc_server_backup_replaced_del(SilcServer server,
241 SilcServerEntry server_entry)
245 if (!server->backup || !server->backup->replaced)
248 for (i = 0; i < server->backup->replaced_count; i++) {
249 if (!server->backup->replaced[i])
251 if (server->backup->replaced[i]->server == server_entry) {
252 silc_free(server->backup->replaced[i]);
253 server->backup->replaced[i] = NULL;
259 /* Broadcast the received packet indicated by `packet' to all of our backup
260 routers. All router wide information is passed using broadcast packets.
261 That is why all backup routers need to get this data too. It is expected
262 that the caller already knows that the `packet' is broadcast packet. */
264 void silc_server_backup_broadcast(SilcServer server,
265 SilcSocketConnection sender,
266 SilcPacketContext *packet)
268 SilcServerEntry backup;
269 SilcSocketConnection sock;
271 const SilcBufferStruct p;
272 SilcIDListData idata;
275 if (!server->backup || server->server_type != SILC_ROUTER)
278 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
280 buffer = packet->buffer;
281 silc_buffer_push(buffer, buffer->data - buffer->head);
283 for (i = 0; i < server->backup->servers_count; i++) {
284 backup = server->backup->servers[i].server;
286 if (!backup || backup->connection == sender ||
287 server->backup->servers[i].local == FALSE)
289 if (server->backup->servers[i].server == server->id_entry)
292 idata = (SilcIDListData)backup;
293 sock = backup->connection;
295 if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
296 (const SilcBuffer)&p)) {
297 SILC_LOG_ERROR(("Cannot send packet"));
300 silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
301 silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
302 (SilcBuffer)&p, p.len);
304 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
306 /* Now actually send the packet */
307 silc_server_packet_send_real(server, sock, FALSE);
311 /* A generic routine to send data to all backup routers. If the `sender'
312 is provided it will indicate the original sender of the packet and the
313 packet won't be resent to that entity. The `data' is the data that will
314 be assembled to packet context before sending. The packet will be
315 encrypted this function. If the `force_send' is TRUE the data is sent
316 immediately and not put to queue. If `local' is TRUE then the packet
317 will be sent only to local backup routers inside the cell. If false the
318 packet can go from one cell to the other. This function has no effect
319 if there are no any backup routers. */
321 void silc_server_backup_send(SilcServer server,
322 SilcServerEntry sender,
324 SilcPacketFlags flags,
330 SilcServerEntry backup;
331 SilcSocketConnection sock;
334 if (!server->backup || server->server_type != SILC_ROUTER)
337 for (i = 0; i < server->backup->servers_count; i++) {
338 backup = server->backup->servers[i].server;
342 if (sender == backup)
345 if (local && server->backup->servers[i].local == FALSE)
347 if (server->backup->servers[i].server == server->id_entry)
350 sock = backup->connection;
352 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
353 silc_get_packet_name(type), sock->hostname, sock->ip));
355 silc_server_packet_send(server, backup->connection, type, flags,
356 data, data_len, force_send);
360 /* Same as silc_server_backup_send but sets a specific Destination ID to
361 the packet. The Destination ID is indicated by the `dst_id' and the
362 ID type `dst_id_type'. For example, packets destined to channels must
363 be sent using this function. */
365 void silc_server_backup_send_dest(SilcServer server,
366 SilcServerEntry sender,
368 SilcPacketFlags flags,
370 SilcIdType dst_id_type,
376 SilcServerEntry backup;
377 SilcSocketConnection sock;
380 if (!server->backup || server->server_type != SILC_ROUTER)
383 for (i = 0; i < server->backup->servers_count; i++) {
384 backup = server->backup->servers[i].server;
388 if (sender == backup)
391 if (local && server->backup->servers[i].local == FALSE)
393 if (server->backup->servers[i].server == server->id_entry)
396 sock = backup->connection;
398 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
399 silc_get_packet_name(type), sock->hostname, sock->ip));
401 silc_server_packet_send_dest(server, backup->connection, type, flags,
402 dst_id, dst_id_type, data, data_len,
407 /* Processes incoming RESUME_ROUTER packet. This can give the packet
408 for processing to the protocol handler or allocate new protocol if
409 start command is received. */
411 void silc_server_backup_resume_router(SilcServer server,
412 SilcSocketConnection sock,
413 SilcPacketContext *packet)
415 SilcUInt8 type, session;
416 SilcServerBackupProtocolContext ctx;
419 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
420 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
421 SILC_LOG_DEBUG(("Bad packet received"));
425 ret = silc_buffer_unformat(packet->buffer,
426 SILC_STR_UI_CHAR(&type),
427 SILC_STR_UI_CHAR(&session),
430 SILC_LOG_DEBUG(("Malformed packet received"));
434 /* Activate the protocol for this socket if necessary */
435 if ((type == SILC_SERVER_BACKUP_RESUMED ||
436 type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
437 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
438 ((SilcIDListData)sock->user_data)->status &
439 SILC_IDLIST_STATUS_DISABLED) {
440 SilcServerEntry backup_router;
442 if (silc_server_backup_replaced_get(server,
443 ((SilcServerEntry)sock->
446 SilcSocketConnection bsock =
447 (SilcSocketConnection)backup_router->connection;
448 if (bsock->protocol && bsock->protocol->protocol &&
449 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
450 sock->protocol = bsock->protocol;
451 ctx = sock->protocol->context;
457 /* If the backup resuming protocol is active then process the packet
459 if (sock->protocol && sock->protocol->protocol &&
460 sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
461 ctx = sock->protocol->context;
464 if (type != SILC_SERVER_BACKUP_RESUMED &&
465 type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
466 for (i = 0; i < ctx->sessions_count; i++) {
467 if (session == ctx->sessions[i].session) {
468 ctx->session = session;
469 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
474 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
478 SILC_LOG_DEBUG(("Bad resume router packet"));
482 /* We don't have protocol active. If we are router and the packet is
483 coming from our primary router then lets check whether it means we've
484 been replaced by an backup router in my cell. This is usually received
485 immediately after we've connected to our primary router. */
487 if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
488 sock && SILC_PRIMARY_ROUTE(server) == sock &&
489 type == SILC_SERVER_BACKUP_REPLACED) {
490 /* We have been replaced by an backup router in our cell. We must
491 mark our primary router connection disabled since we are not allowed
492 to use it at this moment. */
493 SilcIDListData idata = (SilcIDListData)sock->user_data;
494 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
495 "wait until backup resuming protocol is executed"));
496 idata->status |= SILC_IDLIST_STATUS_DISABLED;
500 if (type == SILC_SERVER_BACKUP_START ||
501 type == SILC_SERVER_BACKUP_START_GLOBAL) {
502 /* We have received a start for resuming protocol. */
503 SilcServerBackupProtocolContext proto_ctx;
505 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
506 proto_ctx->server = server;
507 proto_ctx->sock = sock;
508 proto_ctx->responder = TRUE;
509 proto_ctx->type = type;
510 proto_ctx->session = session;
511 proto_ctx->start = time(0);
513 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
515 /* Run the backup resuming protocol */
516 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
517 &sock->protocol, proto_ctx,
518 silc_server_protocol_backup_done);
519 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
523 /* Timeout task callback to connect to remote router */
525 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
527 SilcServerConnection sconn = (SilcServerConnection)context;
528 SilcServer server = sconn->server;
530 const char *server_ip;
532 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
533 sconn->remote_port));
535 /* Connect to remote host */
536 server_ip = server->config->server_info->primary == NULL ? NULL :
537 server->config->server_info->primary->server_ip;
538 sock = silc_net_create_connection(server_ip, sconn->remote_port,
541 silc_schedule_task_add(server->schedule, 0,
542 silc_server_backup_connect_to_router,
543 context, 5, 0, SILC_TASK_TIMEOUT,
544 SILC_TASK_PRI_NORMAL);
548 /* Continue with key exchange protocol */
549 silc_server_start_key_exchange(server, sconn, sock);
552 /* Constantly tries to reconnect to a primary router indicated by the
553 `ip' and `port'. The `connected' callback will be called when the
554 connection is created. */
556 void silc_server_backup_reconnect(SilcServer server,
557 const char *ip, SilcUInt16 port,
558 SilcServerConnectRouterCallback callback,
561 SilcServerConnection sconn;
563 sconn = silc_calloc(1, sizeof(*sconn));
564 sconn->server = server;
565 sconn->remote_host = strdup(ip);
566 sconn->remote_port = port;
567 sconn->callback = callback;
568 sconn->callback_context = context;
569 silc_schedule_task_add(server->schedule, 0,
570 silc_server_backup_connect_to_router,
571 sconn, 1, 0, SILC_TASK_TIMEOUT,
572 SILC_TASK_PRI_NORMAL);
575 /* Task that is called after backup router has connected back to
576 primary router and we are starting the resuming protocol */
578 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
580 SilcServerBackupProtocolContext proto_ctx =
581 (SilcServerBackupProtocolContext)context;
582 SilcServer server = proto_ctx->server;
583 SilcSocketConnection sock = proto_ctx->sock;
585 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
587 /* Run the backup resuming protocol */
588 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
589 &sock->protocol, proto_ctx,
590 silc_server_protocol_backup_done);
591 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
594 /* Called when we've established connection back to our primary router
595 when we've acting as backup router and have replaced the primary router
596 in the cell. This function will start the backup resuming protocol. */
598 void silc_server_backup_connected(SilcServer server,
599 SilcServerEntry server_entry,
602 SilcServerBackupProtocolContext proto_ctx;
603 SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
605 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
606 proto_ctx->server = server;
607 proto_ctx->sock = sock;
608 proto_ctx->responder = FALSE;
609 proto_ctx->type = SILC_SERVER_BACKUP_START;
610 proto_ctx->start = time(0);
612 /* Start through scheduler */
613 silc_schedule_task_add(server->schedule, 0,
614 silc_server_backup_connected_later,
617 SILC_TASK_PRI_NORMAL);
620 /* Called when normal server has connected to its primary router after
621 backup router has sent the START packet in reusming protocol. We will
622 move the protocol context from the backup router connection to the
625 static void silc_server_backup_connect_primary(SilcServer server,
626 SilcServerEntry server_entry,
629 SilcSocketConnection backup_router = (SilcSocketConnection)context;
630 SilcSocketConnection sock = (SilcSocketConnection)server_entry->connection;
631 SilcIDListData idata = (SilcIDListData)server_entry;
632 SilcServerBackupProtocolContext ctx =
633 (SilcServerBackupProtocolContext)backup_router->protocol->context;
636 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
638 /* Send the CONNECTED packet back to the backup router. */
639 buffer = silc_buffer_alloc(2);
640 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
641 silc_buffer_format(buffer,
642 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
643 SILC_STR_UI_CHAR(ctx->session),
645 silc_server_packet_send(server, backup_router,
646 SILC_PACKET_RESUME_ROUTER, 0,
647 buffer->data, buffer->len, FALSE);
648 silc_buffer_free(buffer);
650 /* The primary connection is disabled until it sends the RESUMED packet
652 idata->status |= SILC_IDLIST_STATUS_DISABLED;
654 /* Move this protocol context from this backup router connection to
655 the primary router connection since it will send the subsequent
656 packets in this protocol. We don't talk with backup router
658 sock->protocol = backup_router->protocol;
659 ctx->sock = (SilcSocketConnection)server_entry->connection;
660 backup_router->protocol = NULL;
663 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
665 SilcProtocol protocol = (SilcProtocol)context;
666 SilcServerBackupProtocolContext ctx = protocol->context;
667 SilcServer server = ctx->server;
671 for (i = 0; i < ctx->sessions_count; i++)
672 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
673 ctx->session = ctx->sessions[i].session;
675 /* We've received all the CONNECTED packets and now we'll send the
676 ENDING packet to the new primary router. */
677 packet = silc_buffer_alloc(2);
678 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
679 silc_buffer_format(packet,
680 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
681 SILC_STR_UI_CHAR(ctx->session),
683 silc_server_packet_send(server, ctx->sock,
684 SILC_PACKET_RESUME_ROUTER, 0,
685 packet->data, packet->len, FALSE);
686 silc_buffer_free(packet);
688 protocol->state = SILC_PROTOCOL_STATE_END;
691 /* Backup resuming protocol. This protocol is executed when the primary
692 router wants to resume its position as being primary router. */
694 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
696 SilcProtocol protocol = (SilcProtocol)context;
697 SilcServerBackupProtocolContext ctx = protocol->context;
698 SilcServer server = ctx->server;
700 SilcIDCacheList list;
701 SilcIDCacheEntry id_cache;
702 SilcServerEntry server_entry;
705 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
706 protocol->state = SILC_PROTOCOL_STATE_START;
708 switch(protocol->state) {
709 case SILC_PROTOCOL_STATE_START:
710 if (ctx->responder == FALSE) {
711 /* Initiator of the protocol. We are backup router */
713 packet = silc_buffer_alloc(2);
714 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
716 /* Send the START packet to primary router and normal servers. */
717 if (silc_idcache_get_all(server->local_list->servers, &list)) {
718 if (silc_idcache_list_first(list, &id_cache)) {
720 server_entry = (SilcServerEntry)id_cache->context;
721 if (!server_entry || (server_entry == server->id_entry) ||
722 !server_entry->connection || !server_entry->data.send_key ||
723 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
724 if (!silc_idcache_list_next(list, &id_cache))
730 ctx->sessions = silc_realloc(ctx->sessions,
731 sizeof(*ctx->sessions) *
732 (ctx->sessions_count + 1));
733 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
734 ctx->sessions[ctx->sessions_count].connected = FALSE;
735 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
737 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
738 server_entry->server_name, ctx->sessions_count));
740 /* This connection is performing this protocol too now */
741 ((SilcSocketConnection)server_entry->connection)->protocol =
744 if (server_entry->server_type == SILC_ROUTER)
745 packet->data[0] = SILC_SERVER_BACKUP_START;
747 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
748 packet->data[1] = ctx->sessions_count;
749 silc_server_packet_send(server, server_entry->connection,
750 SILC_PACKET_RESUME_ROUTER, 0,
751 packet->data, packet->len, FALSE);
752 ctx->sessions_count++;
754 if (!silc_idcache_list_next(list, &id_cache))
759 silc_idcache_list_free(list);
762 if (silc_idcache_get_all(server->global_list->servers, &list)) {
763 if (silc_idcache_list_first(list, &id_cache)) {
765 server_entry = (SilcServerEntry)id_cache->context;
766 if (!server_entry || (server_entry == server->id_entry) ||
767 !server_entry->connection || !server_entry->data.send_key ||
768 (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
769 if (!silc_idcache_list_next(list, &id_cache))
775 ctx->sessions = silc_realloc(ctx->sessions,
776 sizeof(*ctx->sessions) *
777 (ctx->sessions_count + 1));
778 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
779 ctx->sessions[ctx->sessions_count].connected = FALSE;
780 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
782 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
783 server_entry->server_name, ctx->sessions_count));
785 /* This connection is performing this protocol too now */
786 ((SilcSocketConnection)server_entry->connection)->protocol =
789 if (server_entry->server_type == SILC_ROUTER)
790 packet->data[0] = SILC_SERVER_BACKUP_START;
792 packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
793 packet->data[1] = ctx->sessions_count;
794 silc_server_packet_send(server, server_entry->connection,
795 SILC_PACKET_RESUME_ROUTER, 0,
796 packet->data, packet->len, FALSE);
797 ctx->sessions_count++;
799 if (!silc_idcache_list_next(list, &id_cache))
804 silc_idcache_list_free(list);
807 silc_buffer_free(packet);
809 /* Announce all of our information */
810 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
811 silc_server_announce_clients(server, 0, ctx->sock);
812 silc_server_announce_channels(server, 0, ctx->sock);
816 /* Responder of the protocol. */
817 SilcServerConfigRouter *primary;
819 /* We should have received START or START_GLOBAL packet */
820 if (ctx->type != SILC_SERVER_BACKUP_START &&
821 ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
822 SILC_LOG_DEBUG(("Bad resume router packet"));
826 /* Connect to the primary router that was down that is now supposed
827 to be back online. We send the CONNECTED packet after we've
828 established the connection to the primary router. */
829 primary = silc_server_config_get_primary_router(server);
830 if (primary && server->backup_primary) {
831 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
833 silc_server_backup_reconnect(server,
834 primary->host, primary->port,
835 silc_server_backup_connect_primary,
838 /* Nowhere to connect just return the CONNECTED packet */
839 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
842 /* Send the CONNECTED packet back to the backup router. */
843 packet = silc_buffer_alloc(2);
844 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
845 silc_buffer_format(packet,
846 SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
847 SILC_STR_UI_CHAR(ctx->session),
849 silc_server_packet_send(server, ctx->sock,
850 SILC_PACKET_RESUME_ROUTER, 0,
851 packet->data, packet->len, FALSE);
852 silc_buffer_free(packet);
855 if (server->server_type == SILC_ROUTER &&
857 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
860 protocol->state = SILC_PROTOCOL_STATE_END;
862 ctx->sessions = silc_realloc(ctx->sessions,
863 sizeof(*ctx->sessions) *
864 (ctx->sessions_count + 1));
865 ctx->sessions[ctx->sessions_count].session = ctx->session;
866 ctx->sessions_count++;
871 if (ctx->responder == FALSE) {
874 /* We should have received CONNECTED packet */
875 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
876 SILC_LOG_DEBUG(("Bad resume router packet"));
880 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
882 for (i = 0; i < ctx->sessions_count; i++) {
883 if (ctx->sessions[i].session == ctx->session) {
884 ctx->sessions[i].connected = TRUE;
889 for (i = 0; i < ctx->sessions_count; i++) {
890 if (!ctx->sessions[i].connected)
894 SILC_LOG_DEBUG(("All sessions has returned CONNECTED packets"));
895 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
897 /* Send with a timeout */
898 silc_schedule_task_add(server->schedule, 0,
899 silc_server_backup_send_resumed,
900 protocol, 1, 0, SILC_TASK_TIMEOUT,
901 SILC_TASK_PRI_NORMAL);
906 /* We should have been received ENDING packet */
907 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
908 SILC_LOG_DEBUG(("Bad resume router packet"));
912 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
914 /* This state is received by the primary router but also servers
915 and perhaps other routers so check that if we are the primary
916 router of the cell then start sending RESUMED packets. If we
917 are normal server or one of those other routers then procede
919 if (server->router &&
920 !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
921 silc_server_config_is_primary_route(server)) {
922 /* We'll wait for RESUMED packet */
923 protocol->state = SILC_PROTOCOL_STATE_END;
927 /* Switch announced informations to our primary router of using the
929 silc_server_update_servers_by_server(server, ctx->sock->user_data,
930 server->router, TRUE);
931 silc_server_update_clients_by_server(server, ctx->sock->user_data,
932 server->router, TRUE, FALSE);
933 if (server->server_type == SILC_SERVER)
934 silc_server_update_channels_by_server(server, ctx->sock->user_data,
937 packet = silc_buffer_alloc(2);
938 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
940 /* We are the primary router, start sending RESUMED packets. */
941 if (silc_idcache_get_all(server->local_list->servers, &list)) {
942 if (silc_idcache_list_first(list, &id_cache)) {
944 server_entry = (SilcServerEntry)id_cache->context;
945 if (!server_entry || (server_entry == server->id_entry) ||
946 !server_entry->connection || !server_entry->data.send_key) {
947 if (!silc_idcache_list_next(list, &id_cache))
953 SILC_LOG_DEBUG(("Sending RESUMED to %s",
954 server_entry->server_name));
956 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
958 /* This connection is performing this protocol too now */
959 ((SilcSocketConnection)server_entry->connection)->protocol =
962 if (server_entry->server_type == SILC_ROUTER)
963 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
965 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
966 silc_server_packet_send(server, server_entry->connection,
967 SILC_PACKET_RESUME_ROUTER, 0,
968 packet->data, packet->len, FALSE);
970 if (!silc_idcache_list_next(list, &id_cache))
975 silc_idcache_list_free(list);
978 if (silc_idcache_get_all(server->global_list->servers, &list)) {
979 if (silc_idcache_list_first(list, &id_cache)) {
981 server_entry = (SilcServerEntry)id_cache->context;
982 if (!server_entry || (server_entry == server->id_entry) ||
983 !server_entry->connection || !server_entry->data.send_key) {
984 if (!silc_idcache_list_next(list, &id_cache))
990 SILC_LOG_DEBUG(("Sending RESUMED to %s",
991 server_entry->server_name));
993 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
995 /* This connection is performing this protocol too now */
996 ((SilcSocketConnection)server_entry->connection)->protocol =
999 if (server_entry->server_type == SILC_ROUTER)
1000 packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
1002 packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
1003 silc_server_packet_send(server, server_entry->connection,
1004 SILC_PACKET_RESUME_ROUTER, 0,
1005 packet->data, packet->len, FALSE);
1007 if (!silc_idcache_list_next(list, &id_cache))
1012 silc_idcache_list_free(list);
1015 silc_buffer_free(packet);
1017 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1019 /* For us this is the end of this protocol. */
1020 if (protocol->final_callback)
1021 silc_protocol_execute_final(protocol, server->schedule);
1023 silc_protocol_free(protocol);
1027 case SILC_PROTOCOL_STATE_END:
1029 SilcServerEntry router, backup_router;
1031 /* We should have been received RESUMED packet from our primary
1033 if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
1034 ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
1035 SILC_LOG_DEBUG(("Bad resume router packet"));
1039 SILC_LOG_DEBUG(("Received RESUMED from new primary router"));
1041 if (server->backup_router)
1042 server->server_type = SILC_BACKUP_ROUTER;
1044 /* We have now new primary router. All traffic goes there from now on. */
1045 router = (SilcServerEntry)ctx->sock->user_data;
1046 if (silc_server_backup_replaced_get(server, router->id,
1049 if (backup_router == server->router) {
1050 /* We have new primary router now */
1051 server->id_entry->router = router;
1052 server->router = router;
1053 server->router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1055 SILC_LOG_INFO(("Switching back to primary router %s",
1056 server->router->server_name));
1058 /* We cannot talk to backup router connection anymore, it's
1059 enabled again if primary goes down. */
1060 backup_router->data.status |= SILC_IDLIST_STATUS_DISABLED;
1062 /* We are connected to new primary and now continue using it */
1063 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1064 SILC_LOG_INFO(("Resuming the use of primary router %s",
1065 router->server_name));
1068 /* Update the client entries of the backup router to the new
1070 silc_server_update_servers_by_server(server, backup_router, router,
1072 silc_server_update_clients_by_server(server, NULL, router,
1074 if (server->server_type == SILC_SERVER)
1075 silc_server_update_channels_by_server(server, backup_router, router);
1076 silc_server_backup_replaced_del(server, backup_router);
1078 /* Announce all of our information to the router. */
1079 if (server->server_type == SILC_ROUTER)
1080 silc_server_announce_servers(server, FALSE, 0, router->connection);
1082 /* Announce our clients and channels to the router */
1083 silc_server_announce_clients(server, 0, router->connection);
1084 silc_server_announce_channels(server, 0, router->connection);
1087 /* Send notify about primary router going down to local operators */
1088 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1089 SILC_NOTIFY_TYPE_NONE,
1090 ("%s resumed the use of primary router %s",
1091 server->server_name,
1092 server->router->server_name));
1094 /* Protocol has ended, call the final callback */
1095 if (protocol->final_callback)
1096 silc_protocol_execute_final(protocol, server->schedule);
1098 silc_protocol_free(protocol);
1102 case SILC_PROTOCOL_STATE_ERROR:
1103 /* Protocol has ended, call the final callback */
1104 if (protocol->final_callback)
1105 silc_protocol_execute_final(protocol, server->schedule);
1107 silc_protocol_free(protocol);
1110 case SILC_PROTOCOL_STATE_FAILURE:
1111 /* Protocol has ended, call the final callback */
1112 if (protocol->final_callback)
1113 silc_protocol_execute_final(protocol, server->schedule);
1115 silc_protocol_free(protocol);
1118 case SILC_PROTOCOL_STATE_UNKNOWN:
1123 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1125 SilcProtocol protocol = (SilcProtocol)context;
1126 SilcServerBackupProtocolContext ctx = protocol->context;
1127 SilcServer server = ctx->server;
1128 SilcServerEntry server_entry;
1129 SilcSocketConnection sock;
1130 SilcIDCacheList list;
1131 SilcIDCacheEntry id_cache;
1133 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1134 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1135 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1138 /* Remove this protocol from all server entries that has it */
1139 if (silc_idcache_get_all(server->local_list->servers, &list)) {
1140 if (silc_idcache_list_first(list, &id_cache)) {
1142 server_entry = (SilcServerEntry)id_cache->context;
1143 sock = (SilcSocketConnection)server_entry->connection;
1145 if (sock->protocol == protocol) {
1146 sock->protocol = NULL;
1148 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1149 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1152 if (!silc_idcache_list_next(list, &id_cache))
1156 silc_idcache_list_free(list);
1159 if (silc_idcache_get_all(server->global_list->servers, &list)) {
1160 if (silc_idcache_list_first(list, &id_cache)) {
1162 server_entry = (SilcServerEntry)id_cache->context;
1163 sock = (SilcSocketConnection)server_entry->connection;
1165 if (sock->protocol == protocol) {
1166 sock->protocol = NULL;
1168 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1169 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1172 if (!silc_idcache_list_next(list, &id_cache))
1176 silc_idcache_list_free(list);
1179 SILC_LOG_DEBUG(("Backup resuming protocol has ended"));
1181 if (ctx->sock->protocol)
1182 ctx->sock->protocol = NULL;
1183 silc_protocol_free(protocol);
1184 silc_free(ctx->sessions);