5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2003 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,
30 /************************** Types and Definitions ***************************/
34 SilcServerEntry server;
38 } SilcServerBackupEntry;
40 /* Holds IP address and port of the primary router that was replaced
45 SilcServerEntry server; /* Backup router that replaced the primary */
46 } SilcServerBackupReplaced;
49 struct SilcServerBackupStruct {
50 SilcServerBackupEntry *servers;
51 SilcUInt32 servers_count;
52 SilcServerBackupReplaced **replaced;
53 SilcUInt32 replaced_count;
59 SilcServerEntry server_entry;
60 } SilcServerBackupProtocolSession;
62 /* Backup resuming protocol context */
65 SilcSocketConnection sock;
69 SilcServerBackupProtocolSession *sessions;
70 SilcUInt32 sessions_count;
72 } *SilcServerBackupProtocolContext;
75 /********************* Backup Configuration Routines ************************/
77 /* Adds the `backup_server' to be one of our backup router. This can be
78 called multiple times to set multiple backup routers. The `ip' and `port'
79 is the IP and port that the `backup_router' will replace if the `ip'
80 will become unresponsive. If `local' is TRUE then the `backup_server' is
81 in the local cell, if FALSE it is in some other cell. */
83 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
84 const char *ip, int port, bool local)
91 if (!server->backup) {
92 server->backup = silc_calloc(1, sizeof(*server->backup));
97 /* See if already added */
98 for (i = 0; i < server->backup->servers_count; i++) {
99 if (server->backup->servers[i].server == backup_server)
103 SILC_LOG_DEBUG(("Backup router %s will replace %s",
104 ((SilcSocketConnection)backup_server->connection)->ip,
107 for (i = 0; i < server->backup->servers_count; i++) {
108 if (!server->backup->servers[i].server) {
109 server->backup->servers[i].server = backup_server;
110 server->backup->servers[i].local = local;
111 server->backup->servers[i].port = SILC_SWAB_16(port);
112 memset(server->backup->servers[i].ip.data, 0,
113 sizeof(server->backup->servers[i].ip.data));
114 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
115 sizeof(server->backup->servers[i].ip.data));
120 i = server->backup->servers_count;
121 server->backup->servers = silc_realloc(server->backup->servers,
122 sizeof(*server->backup->servers) *
124 server->backup->servers[i].server = backup_server;
125 server->backup->servers[i].local = local;
126 server->backup->servers[i].port = SILC_SWAB_16(port);
127 memset(server->backup->servers[i].ip.data, 0,
128 sizeof(server->backup->servers[i].ip.data));
129 silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
130 sizeof(server->backup->servers[i].ip.data));
131 server->backup->servers_count++;
134 /* Returns backup router for IP and port in `server_id' or NULL if there
135 does not exist backup router. */
137 SilcServerEntry silc_server_backup_get(SilcServer server,
138 SilcServerID *server_id)
145 for (i = 0; i < server->backup->servers_count; i++) {
146 if (server->backup->servers[i].server &&
147 server->backup->servers[i].port == server_id->port &&
148 !memcmp(server->backup->servers[i].ip.data, server_id->ip.data,
149 sizeof(server_id->ip.data))) {
150 SILC_LOG_DEBUG(("Found backup router %s for %s",
151 server->backup->servers[i].server->server_name,
152 silc_id_render(server_id, SILC_ID_SERVER)));
153 return server->backup->servers[i].server;
160 /* Deletes the backup server `server_entry'. */
162 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
169 for (i = 0; i < server->backup->servers_count; i++) {
170 if (server->backup->servers[i].server == server_entry) {
171 SILC_LOG_DEBUG(("Removing %s as backup router",
172 silc_id_render(server->backup->servers[i].server->id,
174 server->backup->servers[i].server = NULL;
175 memset(server->backup->servers[i].ip.data, 0,
176 sizeof(server->backup->servers[i].ip.data));
181 /* Frees all data allocated for backup routers. Call this after deleting
182 all backup routers and when new routers are added no more, for example
183 when shutting down the server. */
185 void silc_server_backup_free(SilcServer server)
192 /* Delete existing servers if caller didn't do it */
193 for (i = 0; i < server->backup->servers_count; i++) {
194 if (server->backup->servers[i].server)
195 silc_server_backup_del(server, server->backup->servers[i].server);
198 silc_free(server->backup->servers);
199 silc_free(server->backup);
200 server->backup = NULL;
203 /* Marks the IP address and port from the `server_id' as being replaced
204 by backup router indicated by the `server'. If the router connects at
205 a later time we can check whether it has been replaced by an backup
208 void silc_server_backup_replaced_add(SilcServer server,
209 SilcServerID *server_id,
210 SilcServerEntry server_entry)
213 SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
216 server->backup = silc_calloc(1, sizeof(*server->backup));
217 if (!server->backup->replaced) {
218 server->backup->replaced =
219 silc_calloc(1, sizeof(*server->backup->replaced));
220 server->backup->replaced_count = 1;
223 SILC_LOG_DEBUG(("Replacing router %s with %s",
224 silc_id_render(server_id, SILC_ID_SERVER),
225 server_entry->server_name));
227 memcpy(&r->ip, &server_id->ip, sizeof(server_id->ip));
228 r->server = server_entry;
230 for (i = 0; i < server->backup->replaced_count; i++) {
231 if (!server->backup->replaced[i]) {
232 server->backup->replaced[i] = r;
237 i = server->backup->replaced_count;
238 server->backup->replaced = silc_realloc(server->backup->replaced,
239 sizeof(*server->backup->replaced) *
241 server->backup->replaced[i] = r;
242 server->backup->replaced_count++;
245 /* Checks whether the IP address and port from the `server_id' has been
246 replaced by an backup router. If it has been then this returns TRUE
247 and the bacup router entry to the `server' pointer if non-NULL. Returns
248 FALSE if the router is not replaced by backup router. */
250 bool silc_server_backup_replaced_get(SilcServer server,
251 SilcServerID *server_id,
252 SilcServerEntry *server_entry)
256 if (!server->backup || !server->backup->replaced)
259 for (i = 0; i < server->backup->replaced_count; i++) {
260 if (!server->backup->replaced[i])
262 if (!memcmp(server->backup->replaced[i]->ip.data, server_id->ip.data,
263 sizeof(server_id->ip.data))) {
265 *server_entry = server->backup->replaced[i]->server;
266 SILC_LOG_DEBUG(("Router %s is replaced by %s",
267 silc_id_render(server_id, SILC_ID_SERVER),
268 server->backup->replaced[i]->server->server_name));
273 SILC_LOG_DEBUG(("Router %s is not replaced by backup router",
274 silc_id_render(server_id, SILC_ID_SERVER)));
278 /* Deletes a replaced host by the set `server_entry. */
280 void silc_server_backup_replaced_del(SilcServer server,
281 SilcServerEntry server_entry)
285 if (!server->backup || !server->backup->replaced)
288 for (i = 0; i < server->backup->replaced_count; i++) {
289 if (!server->backup->replaced[i])
291 if (server->backup->replaced[i]->server == server_entry) {
292 silc_free(server->backup->replaced[i]);
293 server->backup->replaced[i] = NULL;
299 /* Broadcast the received packet indicated by `packet' to all of our backup
300 routers. All router wide information is passed using broadcast packets.
301 That is why all backup routers need to get this data too. It is expected
302 that the caller already knows that the `packet' is broadcast packet. */
304 void silc_server_backup_broadcast(SilcServer server,
305 SilcSocketConnection sender,
306 SilcPacketContext *packet)
308 SilcServerEntry backup;
309 SilcSocketConnection sock;
311 const SilcBufferStruct p;
312 SilcIDListData idata;
315 if (!server->backup || server->server_type != SILC_ROUTER)
318 SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
320 buffer = packet->buffer;
321 silc_buffer_push(buffer, buffer->data - buffer->head);
323 for (i = 0; i < server->backup->servers_count; i++) {
324 backup = server->backup->servers[i].server;
326 if (!backup || backup->connection == sender ||
327 server->backup->servers[i].local == FALSE)
329 if (server->backup->servers[i].server == server->id_entry)
332 idata = (SilcIDListData)backup;
333 sock = backup->connection;
335 if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
336 (const SilcBuffer)&p)) {
337 SILC_LOG_ERROR(("Cannot send packet"));
340 silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
341 silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
342 (SilcBuffer)&p, p.len);
344 SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
346 /* Now actually send the packet */
347 silc_server_packet_send_real(server, sock, FALSE);
349 /* Check for mandatory rekey */
350 if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
351 silc_schedule_task_add(server->schedule, sender->sock,
352 silc_server_rekey_callback, sender, 0, 1,
353 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
357 /* A generic routine to send data to all backup routers. If the `sender'
358 is provided it will indicate the original sender of the packet and the
359 packet won't be resent to that entity. The `data' is the data that will
360 be assembled to packet context before sending. The packet will be
361 encrypted this function. If the `force_send' is TRUE the data is sent
362 immediately and not put to queue. If `local' is TRUE then the packet
363 will be sent only to local backup routers inside the cell. If false the
364 packet can go from one cell to the other. This function has no effect
365 if there are no any backup routers. */
367 void silc_server_backup_send(SilcServer server,
368 SilcServerEntry sender,
370 SilcPacketFlags flags,
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;
385 if (!backup || sender == backup)
387 if (local && server->backup->servers[i].local == FALSE)
389 if (server->backup->servers[i].server == server->id_entry)
392 sock = backup->connection;
394 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
395 silc_get_packet_name(type), sock->hostname, sock->ip));
397 silc_server_packet_send(server, backup->connection, type, flags,
398 data, data_len, force_send);
402 /* Same as silc_server_backup_send but sets a specific Destination ID to
403 the packet. The Destination ID is indicated by the `dst_id' and the
404 ID type `dst_id_type'. For example, packets destined to channels must
405 be sent using this function. */
407 void silc_server_backup_send_dest(SilcServer server,
408 SilcServerEntry sender,
410 SilcPacketFlags flags,
412 SilcIdType dst_id_type,
418 SilcServerEntry backup;
419 SilcSocketConnection sock;
422 if (!server->backup || server->server_type != SILC_ROUTER)
425 for (i = 0; i < server->backup->servers_count; i++) {
426 backup = server->backup->servers[i].server;
427 if (!backup || sender == backup)
429 if (local && server->backup->servers[i].local == FALSE)
431 if (server->backup->servers[i].server == server->id_entry)
434 sock = backup->connection;
436 SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
437 silc_get_packet_name(type), sock->hostname, sock->ip));
439 silc_server_packet_send_dest(server, backup->connection, type, flags,
440 dst_id, dst_id_type, data, data_len,
445 /* Send the START_USE indication to remote connection. If `failure' is
446 TRUE then this sends SILC_PACKET_FAILURE. Otherwise it sends
447 SILC_PACKET_RESUME_ROUTER. */
449 void silc_server_backup_send_start_use(SilcServer server,
450 SilcSocketConnection sock,
453 unsigned char data[4];
455 SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
456 failure ? "failure" : "success", sock->ip));
459 SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
460 silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
463 data[0] = SILC_SERVER_BACKUP_START_USE;
465 silc_server_packet_send(server, sock,
466 SILC_PACKET_RESUME_ROUTER, 0,
471 /* Send the REPLACED indication to remote router. This is send by the
472 primary router (remote router) of the primary router that came back
473 online. This is not sent by backup router or any other server. */
475 void silc_server_backup_send_replaced(SilcServer server,
476 SilcSocketConnection sock)
478 unsigned char data[4];
480 SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
482 data[0] = SILC_SERVER_BACKUP_REPLACED;
484 silc_server_packet_send(server, sock,
485 SILC_PACKET_RESUME_ROUTER, 0,
490 /************************ Backup Resuming Protocol **************************/
492 SILC_TASK_CALLBACK(silc_server_backup_timeout)
494 SilcProtocol protocol = context;
495 SilcServer server = app_context;
497 SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
498 silc_protocol_cancel(protocol, server->schedule);
499 protocol->state = SILC_PROTOCOL_STATE_ERROR;
500 silc_protocol_execute_final(protocol, server->schedule);
505 SilcSocketConnection sock;
506 SilcPacketContext *packet;
507 } *SilcServerBackupPing;
509 /* PING command reply callback */
511 void silc_server_backup_ping_reply(void *context, void *reply)
513 SilcServerBackupPing pc = context;
514 SilcServerCommandReplyContext cmdr = reply;
516 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
517 /* Timeout error occurred, the primary is really down. */
518 SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
520 SILC_LOG_DEBUG(("PING timeout, primary is down"));
523 if (primary->user_data)
524 silc_server_free_sock_user_data(pc->server, primary, NULL);
525 SILC_SET_DISCONNECTING(primary);
526 silc_server_close_connection(pc->server, primary);
529 /* Reprocess the RESUME_ROUTER packet */
530 silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
532 /* The primary is not down, refuse to serve the server as primary */
533 SILC_LOG_DEBUG(("PING received, primary is up"));
534 silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
537 silc_socket_free(pc->sock);
538 silc_packet_context_free(pc->packet);
542 /* Processes incoming RESUME_ROUTER packet. This can give the packet
543 for processing to the protocol handler or allocate new protocol if
544 start command is received. */
546 void silc_server_backup_resume_router(SilcServer server,
547 SilcSocketConnection sock,
548 SilcPacketContext *packet)
550 SilcUInt8 type, session;
551 SilcServerBackupProtocolContext ctx;
552 SilcIDListData idata;
555 SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
557 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
558 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
559 SILC_LOG_DEBUG(("Bad packet received"));
563 idata = (SilcIDListData)sock->user_data;
565 ret = silc_buffer_unformat(packet->buffer,
566 SILC_STR_UI_CHAR(&type),
567 SILC_STR_UI_CHAR(&session),
570 SILC_LOG_ERROR(("Malformed resume router packet received"));
574 /* Check whether this packet is used to tell us that server will start
575 using us as primary router. */
576 if (type == SILC_SERVER_BACKUP_START_USE) {
578 SilcServerBackupPing pc;
580 /* If we are normal server then backup router has sent us back
581 this reply and we use the backup as primary router now. */
582 if (server->server_type == SILC_SERVER) {
583 /* Nothing to do here actually, since we have switched already. */
584 SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
588 /* Backup router following. */
590 /* If we are marked as router then the primary is down and we send
591 success START_USE back to the server. */
592 if (server->server_type == SILC_ROUTER) {
593 SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
594 silc_server_backup_send_start_use(server, sock, FALSE);
598 /* We have just lost primary, send success START_USE back */
599 if (server->standalone) {
600 SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
602 silc_server_backup_send_start_use(server, sock, FALSE);
606 /* We are backup router. This server claims that our primary is down.
607 We will check this ourselves by sending PING command to the primary. */
608 SILC_LOG_DEBUG(("Sending PING to detect status of primary router"));
609 idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
610 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
611 SILC_COMMAND_PING, ++server->cmd_ident, 1,
612 1, idp->data, idp->len);
613 silc_buffer_free(idp);
615 /* Reprocess this packet after received reply from router */
616 pc = silc_calloc(1, sizeof(*pc));
618 pc->sock = silc_socket_dup(sock);
619 pc->packet = silc_packet_context_dup(packet);
620 silc_server_command_pending_timed(server, SILC_COMMAND_PING,
622 silc_server_backup_ping_reply, pc, 15);
627 /* Start the resuming protocol if requested. */
628 if (type == SILC_SERVER_BACKUP_START) {
629 /* We have received a start for resuming protocol. We are either
630 primary router that came back online or normal server. */
631 SilcServerBackupProtocolContext proto_ctx;
633 /* If backup had closed the connection earlier we won't allow resuming
634 since we (primary router) have never gone away. */
635 if (server->server_type == SILC_ROUTER && !server->backup_router &&
636 server->backup_closed) {
637 unsigned char data[4];
638 SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
640 SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
641 silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
643 server->backup_closed = FALSE;
647 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
648 proto_ctx->server = server;
649 proto_ctx->sock = sock;
650 proto_ctx->responder = TRUE;
651 proto_ctx->type = type;
652 proto_ctx->session = session;
653 proto_ctx->start = time(0);
655 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
656 SILC_LOG_INFO(("Starting backup resuming protocol"));
658 /* Run the backup resuming protocol */
659 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
660 &sock->protocol, proto_ctx,
661 silc_server_protocol_backup_done);
662 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
663 silc_schedule_task_add(server->schedule, sock->sock,
664 silc_server_backup_timeout,
665 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
666 SILC_TASK_PRI_NORMAL);
671 /* If we are router and the packet is coming from our primary router
672 then it means we have been replaced by an backup router in our cell. */
673 if (type == SILC_SERVER_BACKUP_REPLACED &&
674 server->server_type == SILC_ROUTER &&
675 sock->type == SILC_SOCKET_TYPE_ROUTER &&
676 SILC_PRIMARY_ROUTE(server) == sock) {
677 /* We have been replaced by an backup router in our cell. We must
678 mark our primary router connection disabled since we are not allowed
679 to use it at this moment. */
680 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
681 "wait until backup resuming protocol is executed"));
682 idata->status |= SILC_IDLIST_STATUS_DISABLED;
687 /* Activate the shared protocol context for this socket connection
689 if (type == SILC_SERVER_BACKUP_RESUMED &&
690 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
691 idata->status & SILC_IDLIST_STATUS_DISABLED) {
692 SilcServerEntry backup_router;
694 if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->id,
696 SilcSocketConnection bsock =
697 (SilcSocketConnection)backup_router->connection;
698 if (bsock->protocol && bsock->protocol->protocol &&
699 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
700 sock->protocol = bsock->protocol;
701 ctx = sock->protocol->context;
708 /* Call the resuming protocol if the protocol is active. */
709 if (SILC_SERVER_IS_BACKUP(sock)) {
710 ctx = sock->protocol->context;
713 for (i = 0; i < ctx->sessions_count; i++) {
714 if (session == ctx->sessions[i].session) {
715 ctx->session = session;
716 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
721 /* If RESUMED received the session ID is zero, execute the protocol. */
722 if (type == SILC_SERVER_BACKUP_RESUMED) {
723 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
727 SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
732 /* Timeout task callback to connect to remote router */
734 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
736 SilcServer server = app_context;
737 SilcServerConnection sconn = (SilcServerConnection)context;
739 const char *server_ip;
741 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
742 sconn->remote_port));
744 /* Connect to remote host */
745 server_ip = server->config->server_info->primary == NULL ? NULL :
746 server->config->server_info->primary->server_ip;
747 sock = silc_net_create_connection(server_ip, sconn->remote_port,
750 silc_schedule_task_add(server->schedule, 0,
751 silc_server_backup_connect_to_router,
752 context, 10, 0, SILC_TASK_TIMEOUT,
753 SILC_TASK_PRI_NORMAL);
757 /* Continue with key exchange protocol */
758 silc_server_start_key_exchange(server, sconn, sock);
761 /* Constantly tries to reconnect to a primary router indicated by the
762 `ip' and `port'. The `connected' callback will be called when the
763 connection is created. */
765 void silc_server_backup_reconnect(SilcServer server,
766 const char *ip, SilcUInt16 port,
767 SilcServerConnectRouterCallback callback,
770 SilcServerConnection sconn;
772 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
774 sconn = silc_calloc(1, sizeof(*sconn));
775 sconn->remote_host = strdup(ip);
776 sconn->remote_port = port;
777 sconn->callback = callback;
778 sconn->callback_context = context;
779 sconn->no_reconnect = TRUE;
780 silc_schedule_task_add(server->schedule, 0,
781 silc_server_backup_connect_to_router,
782 sconn, 1, 0, SILC_TASK_TIMEOUT,
783 SILC_TASK_PRI_NORMAL);
786 /* Task that is called after backup router has connected back to
787 primary router and we are starting the resuming protocol */
789 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
791 SilcServerBackupProtocolContext proto_ctx =
792 (SilcServerBackupProtocolContext)context;
793 SilcServer server = proto_ctx->server;
794 SilcSocketConnection sock = proto_ctx->sock;
796 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
797 SILC_LOG_INFO(("Starting backup resuming protocol"));
799 /* Run the backup resuming protocol */
800 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
801 &sock->protocol, proto_ctx,
802 silc_server_protocol_backup_done);
803 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
805 silc_schedule_task_add(server->schedule, sock->sock,
806 silc_server_backup_timeout,
807 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
808 SILC_TASK_PRI_NORMAL);
811 /* Called when we've established connection back to our primary router
812 when we've acting as backup router and have replaced the primary router
813 in the cell. This function will start the backup resuming protocol. */
815 void silc_server_backup_connected(SilcServer server,
816 SilcServerEntry server_entry,
819 SilcServerBackupProtocolContext proto_ctx;
820 SilcSocketConnection sock;
824 SilcServerConfigRouter *primary;
825 primary = silc_server_config_get_primary_router(server);
827 silc_server_backup_reconnect(server,
828 primary->host, primary->port,
829 silc_server_backup_connected,
834 sock = (SilcSocketConnection)server_entry->connection;
835 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
836 proto_ctx->server = server;
837 proto_ctx->sock = sock;
838 proto_ctx->responder = FALSE;
839 proto_ctx->type = SILC_SERVER_BACKUP_START;
840 proto_ctx->start = time(0);
842 /* Start through scheduler */
843 silc_schedule_task_add(server->schedule, 0,
844 silc_server_backup_connected_later,
847 SILC_TASK_PRI_NORMAL);
850 /* Called when normal server has connected to its primary router after
851 backup router has sent the START packet in reusming protocol. We will
852 move the protocol context from the backup router connection to the
855 static void silc_server_backup_connect_primary(SilcServer server,
856 SilcServerEntry server_entry,
859 SilcSocketConnection backup_router = (SilcSocketConnection)context;
860 SilcServerBackupProtocolContext ctx;
861 SilcSocketConnection sock;
862 SilcIDListData idata;
863 unsigned char data[2];
867 SilcServerConfigRouter *primary;
868 primary = silc_server_config_get_primary_router(server);
870 silc_server_backup_reconnect(server,
871 primary->host, primary->port,
872 silc_server_backup_connect_primary,
877 if (!backup_router->protocol)
879 if (!server_entry->connection)
882 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
883 sock = (SilcSocketConnection)server_entry->connection;
884 idata = (SilcIDListData)server_entry;
886 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
887 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
890 /* Send the CONNECTED packet back to the backup router. */
891 data[0] = SILC_SERVER_BACKUP_CONNECTED;
892 data[1] = ctx->session;
893 silc_server_packet_send(server, backup_router,
894 SILC_PACKET_RESUME_ROUTER, 0, data, 2, FALSE);
896 /* The primary connection is disabled until it sends the RESUMED packet
898 idata->status |= SILC_IDLIST_STATUS_DISABLED;
900 /* Move this protocol context from this backup router connection to
901 the primary router connection since it will send the subsequent
902 packets in this protocol. We don't talk with backup router
904 sock->protocol = backup_router->protocol;
905 ctx->sock = (SilcSocketConnection)server_entry->connection;
906 backup_router->protocol = NULL;
909 /* Timeout callback used by the backup router to send the ENDING packet
910 to primary router to indicate that it can now resume as being primary
911 router. All CONNECTED packets has been received when we reach this. */
913 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
915 SilcProtocol protocol = (SilcProtocol)context;
916 SilcServerBackupProtocolContext ctx = protocol->context;
917 SilcServer server = ctx->server;
918 unsigned char data[2];
921 SILC_LOG_DEBUG(("Start"));
923 for (i = 0; i < ctx->sessions_count; i++)
924 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
925 ctx->session = ctx->sessions[i].session;
927 /* We've received all the CONNECTED packets and now we'll send the
928 ENDING packet to the new primary router. */
929 data[0] = SILC_SERVER_BACKUP_ENDING;
930 data[1] = ctx->session;
931 silc_server_packet_send(server, ctx->sock, SILC_PACKET_RESUME_ROUTER, 0,
932 data, sizeof(data), FALSE);
934 /* The protocol will go to END state. */
935 protocol->state = SILC_PROTOCOL_STATE_END;
938 /* Backup resuming protocol. This protocol is executed when the primary
939 router wants to resume its position as being primary router. */
941 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
943 SilcProtocol protocol = (SilcProtocol)context;
944 SilcServerBackupProtocolContext ctx = protocol->context;
945 SilcServer server = ctx->server;
946 SilcServerEntry server_entry;
947 SilcSocketConnection sock;
948 unsigned char data[2];
951 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
952 protocol->state = SILC_PROTOCOL_STATE_START;
954 switch(protocol->state) {
955 case SILC_PROTOCOL_STATE_START:
956 if (ctx->responder == FALSE) {
958 * Initiator (backup router)
961 /* Send the START packet to primary router and normal servers. The
962 packet will indicate to the primary router that it has been replaced
963 by us. For normal servers it means that we will be resigning as
964 being primary router shortly. */
965 for (i = 0; i < server->config->param.connections_max; i++) {
966 sock = server->sockets[i];
967 if (!sock || !sock->user_data ||
968 sock->user_data == server->id_entry ||
969 (sock->type != SILC_SOCKET_TYPE_ROUTER &&
970 sock->type != SILC_SOCKET_TYPE_SERVER))
973 server_entry = sock->user_data;
974 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
977 ctx->sessions = silc_realloc(ctx->sessions,
978 sizeof(*ctx->sessions) *
979 (ctx->sessions_count + 1));
980 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
981 ctx->sessions[ctx->sessions_count].connected = FALSE;
982 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
984 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
985 server_entry->server_name, ctx->sessions_count));
986 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
987 server_entry->server_name, ctx->sessions_count));
989 /* This connection is performing this protocol too now */
990 sock->protocol = protocol;
992 data[0] = SILC_SERVER_BACKUP_START;
993 data[1] = ctx->sessions_count;
994 silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
995 data, sizeof(data), FALSE);
996 ctx->sessions_count++;
999 /* If we are not standalone and our primary is not the one we're
1000 talking to now, then announce our information to it since we
1001 haven't done that yet. Standalone backup router announces
1002 these during connecting to the primary. */
1003 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
1004 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
1005 silc_server_announce_clients(server, 0, ctx->sock);
1006 silc_server_announce_channels(server, 0, ctx->sock);
1013 * Responder (all servers and routers)
1015 SilcServerConfigRouter *primary;
1017 /* We should have received START packet */
1018 if (ctx->type != SILC_SERVER_BACKUP_START) {
1019 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
1023 /* Connect to the primary router that was down that is now supposed
1024 to be back online. We send the CONNECTED packet after we've
1025 established the connection to the primary router. */
1026 primary = silc_server_config_get_primary_router(server);
1027 if (primary && server->backup_primary &&
1028 !silc_server_num_sockets_by_remote(server,
1029 silc_net_is_ip(primary->host) ?
1030 primary->host : NULL,
1031 silc_net_is_ip(primary->host) ?
1032 NULL : primary->host,
1034 SILC_SOCKET_TYPE_ROUTER)) {
1035 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
1037 silc_server_backup_reconnect(server,
1038 primary->host, primary->port,
1039 silc_server_backup_connect_primary,
1042 /* Nowhere to connect just return the CONNECTED packet */
1043 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
1045 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
1048 /* Send the CONNECTED packet back to the backup router. */
1049 data[0] = SILC_SERVER_BACKUP_CONNECTED;
1050 data[1] = ctx->session;
1051 silc_server_packet_send(server, ctx->sock,
1052 SILC_PACKET_RESUME_ROUTER, 0,
1053 data, sizeof(data), FALSE);
1056 /* Add this resuming session */
1057 ctx->sessions = silc_realloc(ctx->sessions,
1058 sizeof(*ctx->sessions) *
1059 (ctx->sessions_count + 1));
1060 ctx->sessions[ctx->sessions_count].session = ctx->session;
1061 ctx->sessions_count++;
1063 /* Normal server goes directly to the END state. */
1064 if (server->server_type == SILC_ROUTER &&
1066 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
1069 protocol->state = SILC_PROTOCOL_STATE_END;
1074 if (ctx->responder == FALSE) {
1076 * Initiator (backup router)
1079 /* We should have received CONNECTED packet */
1080 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
1081 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
1085 for (i = 0; i < ctx->sessions_count; i++) {
1086 if (ctx->sessions[i].session == ctx->session) {
1087 ctx->sessions[i].connected = TRUE;
1088 SILC_LOG_INFO(("Received CONNECTED from %s (session %d)",
1089 ctx->sessions[i].server_entry->server_name,
1091 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
1096 /* See if all returned CONNECTED, if not, then continue waiting. */
1097 for (i = 0; i < ctx->sessions_count; i++) {
1098 if (!ctx->sessions[i].connected)
1102 SILC_LOG_INFO(("All sessions have returned CONNECTED packets, "
1104 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
1106 /* The ENDING is sent with timeout, and then we continue to the
1107 END state in the protocol. */
1108 silc_schedule_task_add(server->schedule, 0,
1109 silc_server_backup_send_resumed,
1110 protocol, 1, 0, SILC_TASK_TIMEOUT,
1111 SILC_TASK_PRI_NORMAL);
1116 * Responder (primary router)
1119 /* We should have been received ENDING packet */
1120 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
1121 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
1125 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
1127 /* Switch announced informations to our primary router of using the
1129 silc_server_local_servers_toggle_enabled(server, TRUE);
1130 silc_server_update_servers_by_server(server, ctx->sock->user_data,
1132 silc_server_update_clients_by_server(server, ctx->sock->user_data,
1133 server->router, TRUE);
1135 /* We as primary router now must send RESUMED packets to all servers
1136 and routers so that they know we are back. */
1137 for (i = 0; i < server->config->param.connections_max; i++) {
1138 sock = server->sockets[i];
1139 if (!sock || !sock->user_data ||
1140 sock->user_data == server->id_entry ||
1141 (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1142 sock->type != SILC_SOCKET_TYPE_SERVER))
1145 server_entry = sock->user_data;
1146 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1148 SILC_LOG_DEBUG(("Sending RESUMED to %s", server_entry->server_name));
1149 SILC_LOG_INFO(("Sending RESUMED to %s", server_entry->server_name));
1151 /* This connection is performing this protocol too now */
1152 sock->protocol = protocol;
1154 data[0] = SILC_SERVER_BACKUP_RESUMED;
1156 silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
1157 data, sizeof(data), FALSE);
1158 silc_server_packet_queue_purge(server,sock);
1161 /* We are now resumed and are back as primary router in the cell. */
1162 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1163 server->wait_backup = FALSE;
1165 /* For us this is the end of this protocol. */
1166 if (protocol->final_callback)
1167 silc_protocol_execute_final(protocol, server->schedule);
1169 silc_protocol_free(protocol);
1173 case SILC_PROTOCOL_STATE_END:
1176 * Responder (backup router, servers, and remote router)
1178 SilcServerEntry router, backup_router;
1180 /* We should have been received RESUMED from our primary router. */
1181 if (ctx->type != SILC_SERVER_BACKUP_RESUMED) {
1182 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1186 SILC_LOG_INFO(("Received RESUMED from new primary router"));
1188 /* If we are the backup router, mark that we are no longer primary
1189 but are back to backup router status. */
1190 if (server->backup_router)
1191 server->server_type = SILC_BACKUP_ROUTER;
1193 /* We have now new primary router. All traffic goes there from now on. */
1194 router = ctx->sock->user_data;
1195 if (silc_server_backup_replaced_get(server, router->id,
1198 if (backup_router == server->router) {
1199 /* We have new primary router now */
1200 server->id_entry->router = router;
1201 server->router = router;
1202 SILC_LOG_INFO(("Switching back to primary router %s",
1203 server->router->server_name));
1205 /* We are connected to new primary and now continue using it */
1206 SILC_LOG_INFO(("Resuming the use of primary router %s",
1207 router->server_name));
1209 server->backup_primary = FALSE;
1210 sock = router->connection;
1212 /* Update the client entries of the backup router to the new
1214 silc_server_local_servers_toggle_enabled(server, FALSE);
1215 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1216 silc_server_update_servers_by_server(server, backup_router, router);
1217 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1218 if (server->server_type == SILC_SERVER)
1219 silc_server_update_channels_by_server(server, backup_router, router);
1220 silc_server_backup_replaced_del(server, backup_router);
1222 /* Announce all of our information to the router. */
1223 if (server->server_type == SILC_ROUTER)
1224 silc_server_announce_servers(server, FALSE, ctx->start, sock);
1226 /* Announce our clients and channels to the router */
1227 silc_server_announce_clients(server, ctx->start, sock);
1228 silc_server_announce_channels(server, ctx->start, sock);
1231 /* Send notify about primary router going down to local operators */
1232 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1233 SILC_NOTIFY_TYPE_NONE,
1234 ("%s resumed the use of primary router %s",
1235 server->server_name,
1236 server->router->server_name));
1238 /* Protocol has ended, call the final callback */
1239 if (protocol->final_callback)
1240 silc_protocol_execute_final(protocol, server->schedule);
1242 silc_protocol_free(protocol);
1246 case SILC_PROTOCOL_STATE_ERROR:
1247 /* Protocol has ended, call the final callback */
1248 if (protocol->final_callback)
1249 silc_protocol_execute_final(protocol, server->schedule);
1251 silc_protocol_free(protocol);
1254 case SILC_PROTOCOL_STATE_FAILURE:
1255 /* Protocol has ended, call the final callback */
1256 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1257 if (protocol->final_callback)
1258 silc_protocol_execute_final(protocol, server->schedule);
1260 silc_protocol_free(protocol);
1263 case SILC_PROTOCOL_STATE_UNKNOWN:
1268 /* Final resuming protocol completion callback */
1270 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1272 SilcProtocol protocol = (SilcProtocol)context;
1273 SilcServerBackupProtocolContext ctx = protocol->context;
1274 SilcServer server = ctx->server;
1275 SilcServerEntry server_entry;
1276 SilcSocketConnection sock;
1280 silc_schedule_task_del_by_context(server->schedule, protocol);
1282 error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1283 protocol->state == SILC_PROTOCOL_STATE_FAILURE);
1286 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1288 if (server->server_shutdown)
1291 /* Remove this protocol from all server entries that has it */
1292 for (i = 0; i < server->config->param.connections_max; i++) {
1293 sock = server->sockets[i];
1294 if (!sock || !sock->user_data ||
1295 (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1296 sock->type != SILC_SOCKET_TYPE_SERVER))
1299 server_entry = sock->user_data;
1301 /* The SilcProtocol context was shared between all connections, clear
1302 it from all connections. */
1303 if (sock->protocol == protocol) {
1304 sock->protocol = NULL;
1307 /* If we are normal server close router connections and reconnect. */
1308 if (server->server_type == SILC_SERVER &&
1309 (server_entry->server_type == SILC_BACKUP_ROUTER ||
1310 server_entry->server_type == SILC_ROUTER)) {
1311 server->backup_noswitch = TRUE;
1312 if (sock->user_data)
1313 silc_server_free_sock_user_data(server, sock, NULL);
1314 silc_server_disconnect_remote(server, sock, 0, NULL);
1315 server->backup_noswitch = FALSE;
1317 silc_server_create_connections(server);
1321 /* If error occurred and we are backup router, we close connections. */
1322 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1323 server->backup_noswitch = TRUE;
1324 server->server_type = SILC_BACKUP_ROUTER;
1325 if (ctx->sock == sock)
1328 server->backup_noswitch = TRUE;
1329 if (sock->user_data)
1330 silc_server_free_sock_user_data(server, sock, NULL);
1331 silc_server_disconnect_remote(server, sock, 0, NULL);
1332 server->backup_noswitch = FALSE;
1334 silc_server_create_connections(server);
1339 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1344 SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
1346 if (ctx->sock && ctx->sock->protocol)
1347 ctx->sock->protocol = NULL;
1348 silc_protocol_free(protocol);
1349 silc_free(ctx->sessions);