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 /* Timeout callback for protocol */
494 SILC_TASK_CALLBACK(silc_server_backup_timeout)
496 SilcProtocol protocol = context;
497 SilcServer server = app_context;
499 SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
500 silc_protocol_cancel(protocol, server->schedule);
501 protocol->state = SILC_PROTOCOL_STATE_ERROR;
502 silc_protocol_execute_final(protocol, server->schedule);
505 /* Callback to start the protocol as responder */
507 SILC_TASK_CALLBACK(silc_server_backup_responder_start)
509 SilcServerBackupProtocolContext proto_ctx = context;
510 SilcSocketConnection sock = proto_ctx->sock;
511 SilcServer server = app_context;
513 /* If other protocol is executing at the same time, start with timeout. */
514 if (sock->protocol) {
515 silc_schedule_task_add(server->schedule, sock->sock,
516 silc_server_backup_responder_start,
518 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
522 /* Run the backup resuming protocol */
523 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
524 &sock->protocol, proto_ctx,
525 silc_server_protocol_backup_done);
526 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
527 silc_schedule_task_add(server->schedule, sock->sock,
528 silc_server_backup_timeout,
529 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
530 SILC_TASK_PRI_NORMAL);
535 SilcSocketConnection sock;
536 SilcPacketContext *packet;
537 } *SilcServerBackupPing;
539 /* PING command reply callback */
541 void silc_server_backup_ping_reply(void *context, void *reply)
543 SilcServerBackupPing pc = context;
544 SilcServerCommandReplyContext cmdr = reply;
546 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
547 /* Timeout error occurred, the primary is really down. */
548 SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
550 SILC_LOG_DEBUG(("PING timeout, primary is down"));
553 if (primary->user_data)
554 silc_server_free_sock_user_data(pc->server, primary, NULL);
555 SILC_SET_DISCONNECTING(primary);
556 silc_server_close_connection(pc->server, primary);
559 /* Reprocess the RESUME_ROUTER packet */
560 silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
562 /* The primary is not down, refuse to serve the server as primary */
563 SILC_LOG_DEBUG(("PING received, primary is up"));
564 silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
567 silc_socket_free(pc->sock);
568 silc_packet_context_free(pc->packet);
572 /* Processes incoming RESUME_ROUTER packet. This can give the packet
573 for processing to the protocol handler or allocate new protocol if
574 start command is received. */
576 void silc_server_backup_resume_router(SilcServer server,
577 SilcSocketConnection sock,
578 SilcPacketContext *packet)
580 SilcUInt8 type, session;
581 SilcServerBackupProtocolContext ctx;
582 SilcIDListData idata;
585 SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
587 if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
588 sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
589 SILC_LOG_DEBUG(("Bad packet received"));
593 idata = (SilcIDListData)sock->user_data;
595 ret = silc_buffer_unformat(packet->buffer,
596 SILC_STR_UI_CHAR(&type),
597 SILC_STR_UI_CHAR(&session),
600 SILC_LOG_ERROR(("Malformed resume router packet received"));
604 /* Check whether this packet is used to tell us that server will start
605 using us as primary router. */
606 if (type == SILC_SERVER_BACKUP_START_USE) {
608 SilcServerBackupPing pc;
610 /* If we are normal server then backup router has sent us back
611 this reply and we use the backup as primary router now. */
612 if (server->server_type == SILC_SERVER) {
613 /* Nothing to do here actually, since we have switched already. */
614 SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
618 /* Backup router following. */
620 /* If we are marked as router then the primary is down and we send
621 success START_USE back to the server. */
622 if (server->server_type == SILC_ROUTER) {
623 SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
624 silc_server_backup_send_start_use(server, sock, FALSE);
628 /* We have just lost primary, send success START_USE back */
629 if (server->standalone) {
630 SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
632 silc_server_backup_send_start_use(server, sock, FALSE);
636 /* We are backup router. This server claims that our primary is down.
637 We will check this ourselves by sending PING command to the primary. */
638 SILC_LOG_DEBUG(("Sending PING to detect status of primary router"));
639 idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
640 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
641 SILC_COMMAND_PING, ++server->cmd_ident, 1,
642 1, idp->data, idp->len);
643 silc_buffer_free(idp);
645 /* Reprocess this packet after received reply from router */
646 pc = silc_calloc(1, sizeof(*pc));
648 pc->sock = silc_socket_dup(sock);
649 pc->packet = silc_packet_context_dup(packet);
650 silc_server_command_pending_timed(server, SILC_COMMAND_PING,
652 silc_server_backup_ping_reply, pc, 15);
657 /* Start the resuming protocol if requested. */
658 if (type == SILC_SERVER_BACKUP_START) {
659 /* We have received a start for resuming protocol. We are either
660 primary router that came back online or normal server. */
661 SilcServerBackupProtocolContext proto_ctx;
663 /* If backup had closed the connection earlier we won't allow resuming
664 since we (primary router) have never gone away. */
665 if (server->server_type == SILC_ROUTER && !server->backup_router &&
666 server->backup_closed) {
667 unsigned char data[4];
668 SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
670 SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
671 silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
673 server->backup_closed = FALSE;
677 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
678 proto_ctx->server = server;
679 proto_ctx->sock = silc_socket_dup(sock);
680 proto_ctx->responder = TRUE;
681 proto_ctx->type = type;
682 proto_ctx->session = session;
683 proto_ctx->start = time(0);
685 SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
686 SILC_LOG_INFO(("Starting backup resuming protocol"));
688 /* Start protocol immediately */
689 silc_schedule_task_add(server->schedule, sock->sock,
690 silc_server_backup_responder_start,
692 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
697 /* If we are router and the packet is coming from our primary router
698 then it means we have been replaced by an backup router in our cell. */
699 if (type == SILC_SERVER_BACKUP_REPLACED &&
700 server->server_type == SILC_ROUTER &&
701 sock->type == SILC_SOCKET_TYPE_ROUTER &&
702 SILC_PRIMARY_ROUTE(server) == sock) {
703 /* We have been replaced by an backup router in our cell. We must
704 mark our primary router connection disabled since we are not allowed
705 to use it at this moment. */
706 SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
707 "wait until backup resuming protocol is executed"));
708 idata->status |= SILC_IDLIST_STATUS_DISABLED;
713 /* Activate the shared protocol context for this socket connection
715 if (type == SILC_SERVER_BACKUP_RESUMED &&
716 sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
717 idata->status & SILC_IDLIST_STATUS_DISABLED) {
718 SilcServerEntry backup_router;
720 if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->id,
722 SilcSocketConnection bsock =
723 (SilcSocketConnection)backup_router->connection;
724 if (bsock->protocol && bsock->protocol->protocol &&
725 bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
726 sock->protocol = bsock->protocol;
727 ctx = sock->protocol->context;
729 silc_socket_free(ctx->sock); /* unref */
730 ctx->sock = silc_socket_dup(sock);
736 /* Call the resuming protocol if the protocol is active. */
737 if (SILC_SERVER_IS_BACKUP(sock)) {
738 ctx = sock->protocol->context;
741 for (i = 0; i < ctx->sessions_count; i++) {
742 if (session == ctx->sessions[i].session) {
743 ctx->session = session;
744 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
749 /* If RESUMED received the session ID is zero, execute the protocol. */
750 if (type == SILC_SERVER_BACKUP_RESUMED) {
751 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
755 SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
760 /* Timeout task callback to connect to remote router */
762 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
764 SilcServer server = app_context;
765 SilcServerConnection sconn = (SilcServerConnection)context;
767 const char *server_ip;
769 SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
770 sconn->remote_port));
772 /* Connect to remote host */
773 server_ip = server->config->server_info->primary == NULL ? NULL :
774 server->config->server_info->primary->server_ip;
775 sock = silc_net_create_connection(server_ip, sconn->remote_port,
778 if (server->server_type == SILC_SERVER) {
779 sconn->retry_count++;
780 if (sconn->retry_count > 3) {
781 silc_free(sconn->remote_host);
786 silc_schedule_task_add(server->schedule, 0,
787 silc_server_backup_connect_to_router,
788 context, 10, 0, SILC_TASK_TIMEOUT,
789 SILC_TASK_PRI_NORMAL);
793 /* Continue with key exchange protocol */
794 silc_server_start_key_exchange(server, sconn, sock);
797 /* Constantly tries to reconnect to a primary router indicated by the
798 `ip' and `port'. The `connected' callback will be called when the
799 connection is created. */
801 void silc_server_backup_reconnect(SilcServer server,
802 const char *ip, SilcUInt16 port,
803 SilcServerConnectRouterCallback callback,
806 SilcServerConnection sconn;
808 SILC_LOG_INFO(("Attempting to reconnect to primary router"));
810 sconn = silc_calloc(1, sizeof(*sconn));
811 sconn->remote_host = strdup(ip);
812 sconn->remote_port = port;
813 sconn->callback = callback;
814 sconn->callback_context = context;
815 sconn->no_reconnect = TRUE;
816 sconn->retry_count = 0;
817 silc_schedule_task_add(server->schedule, 0,
818 silc_server_backup_connect_to_router,
819 sconn, 1, 0, SILC_TASK_TIMEOUT,
820 SILC_TASK_PRI_NORMAL);
823 /* Task that is called after backup router has connected back to
824 primary router and we are starting the resuming protocol */
826 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
828 SilcServerBackupProtocolContext proto_ctx =
829 (SilcServerBackupProtocolContext)context;
830 SilcServer server = proto_ctx->server;
831 SilcSocketConnection sock = proto_ctx->sock;
833 /* If running other protocol already run this one a bit later. */
834 if (sock->protocol) {
835 silc_schedule_task_add(server->schedule, 0,
836 silc_server_backup_connected_later,
839 SILC_TASK_PRI_NORMAL);
843 SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
844 SILC_LOG_INFO(("Starting backup resuming protocol"));
846 /* Run the backup resuming protocol */
847 silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
848 &sock->protocol, proto_ctx,
849 silc_server_protocol_backup_done);
850 silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
852 silc_schedule_task_add(server->schedule, sock->sock,
853 silc_server_backup_timeout,
854 sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
855 SILC_TASK_PRI_NORMAL);
858 /* Called when we've established connection back to our primary router
859 when we've acting as backup router and have replaced the primary router
860 in the cell. This function will start the backup resuming protocol. */
862 void silc_server_backup_connected(SilcServer server,
863 SilcServerEntry server_entry,
866 SilcServerBackupProtocolContext proto_ctx;
867 SilcSocketConnection sock;
871 SilcServerConfigRouter *primary;
872 primary = silc_server_config_get_primary_router(server);
874 if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
875 primary->host, primary->port))
876 silc_server_backup_reconnect(server,
877 primary->host, primary->port,
878 silc_server_backup_connected,
884 sock = (SilcSocketConnection)server_entry->connection;
885 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
886 proto_ctx->server = server;
887 proto_ctx->sock = silc_socket_dup(sock);
888 proto_ctx->responder = FALSE;
889 proto_ctx->type = SILC_SERVER_BACKUP_START;
890 proto_ctx->start = time(0);
892 /* Start through scheduler */
893 silc_schedule_task_add(server->schedule, 0,
894 silc_server_backup_connected_later,
897 SILC_TASK_PRI_NORMAL);
900 /* Called when normal server has connected to its primary router after
901 backup router has sent the START packet in reusming protocol. We will
902 move the protocol context from the backup router connection to the
905 static void silc_server_backup_connect_primary(SilcServer server,
906 SilcServerEntry server_entry,
909 SilcSocketConnection backup_router = (SilcSocketConnection)context;
910 SilcServerBackupProtocolContext ctx;
911 SilcSocketConnection sock;
912 SilcIDListData idata;
913 unsigned char data[2];
915 if (SILC_IS_DISCONNECTING(backup_router) ||
916 SILC_IS_DISCONNECTED(backup_router)) {
917 silc_socket_free(backup_router);
923 SilcServerConfigRouter *primary;
924 primary = silc_server_config_get_primary_router(server);
926 if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
927 primary->host, primary->port))
928 silc_server_backup_reconnect(server,
929 primary->host, primary->port,
930 silc_server_backup_connect_primary,
936 silc_socket_free(backup_router);
938 if (!backup_router->protocol)
940 if (!server_entry->connection)
943 ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
944 sock = (SilcSocketConnection)server_entry->connection;
945 idata = (SilcIDListData)server_entry;
947 SILC_LOG_DEBUG(("Sending CONNECTED packet (session %d)", ctx->session));
948 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
951 /* Send the CONNECTED packet back to the backup router. */
952 data[0] = SILC_SERVER_BACKUP_CONNECTED;
953 data[1] = ctx->session;
954 silc_server_packet_send(server, backup_router,
955 SILC_PACKET_RESUME_ROUTER, 0, data, 2, FALSE);
957 /* The primary connection is disabled until it sends the RESUMED packet
959 idata->status |= SILC_IDLIST_STATUS_DISABLED;
961 /* Move this protocol context from this backup router connection to
962 the primary router connection since it will send the subsequent
963 packets in this protocol. We don't talk with backup router
965 sock->protocol = backup_router->protocol;
967 silc_socket_free(ctx->sock); /* unref */
968 ctx->sock = silc_socket_dup(server_entry->connection);
969 backup_router->protocol = NULL;
972 /* Timeout callback used by the backup router to send the ENDING packet
973 to primary router to indicate that it can now resume as being primary
974 router. All CONNECTED packets has been received when we reach this. */
976 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
978 SilcProtocol protocol = (SilcProtocol)context;
979 SilcServerBackupProtocolContext ctx = protocol->context;
980 SilcServer server = ctx->server;
981 unsigned char data[2];
984 SILC_LOG_DEBUG(("Start"));
986 for (i = 0; i < ctx->sessions_count; i++)
987 if (ctx->sessions[i].server_entry == ctx->sock->user_data)
988 ctx->session = ctx->sessions[i].session;
990 /* We've received all the CONNECTED packets and now we'll send the
991 ENDING packet to the new primary router. */
992 data[0] = SILC_SERVER_BACKUP_ENDING;
993 data[1] = ctx->session;
994 silc_server_packet_send(server, ctx->sock, SILC_PACKET_RESUME_ROUTER, 0,
995 data, sizeof(data), FALSE);
997 /* The protocol will go to END state. */
998 protocol->state = SILC_PROTOCOL_STATE_END;
1001 /* Backup resuming protocol. This protocol is executed when the primary
1002 router wants to resume its position as being primary router. */
1004 SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
1006 SilcProtocol protocol = (SilcProtocol)context;
1007 SilcServerBackupProtocolContext ctx = protocol->context;
1008 SilcServer server = ctx->server;
1009 SilcServerEntry server_entry;
1010 SilcSocketConnection sock = NULL;
1011 unsigned char data[2];
1014 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
1015 protocol->state = SILC_PROTOCOL_STATE_START;
1017 switch(protocol->state) {
1018 case SILC_PROTOCOL_STATE_START:
1019 if (ctx->responder == FALSE) {
1021 * Initiator (backup router)
1024 /* Send the START packet to primary router and normal servers. The
1025 packet will indicate to the primary router that it has been replaced
1026 by us. For normal servers it means that we will be resigning as
1027 being primary router shortly. */
1028 for (i = 0; i < server->config->param.connections_max; i++) {
1029 sock = server->sockets[i];
1030 if (!sock || !sock->user_data ||
1031 sock->user_data == server->id_entry ||
1032 (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1033 sock->type != SILC_SOCKET_TYPE_SERVER))
1036 server_entry = sock->user_data;
1037 if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
1040 ctx->sessions = silc_realloc(ctx->sessions,
1041 sizeof(*ctx->sessions) *
1042 (ctx->sessions_count + 1));
1043 ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
1044 ctx->sessions[ctx->sessions_count].connected = FALSE;
1045 ctx->sessions[ctx->sessions_count].server_entry = server_entry;
1047 SILC_LOG_DEBUG(("Sending START to %s (session %d)",
1048 server_entry->server_name, ctx->sessions_count));
1049 SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
1050 server_entry->server_name, ctx->sessions_count));
1052 /* This connection is performing this protocol too now */
1053 sock->protocol = protocol;
1055 data[0] = SILC_SERVER_BACKUP_START;
1056 data[1] = ctx->sessions_count;
1057 silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
1058 data, sizeof(data), FALSE);
1059 ctx->sessions_count++;
1062 /* If we are not standalone and our primary is not the one we're
1063 talking to now, then announce our information to it since we
1064 haven't done that yet. Standalone backup router announces
1065 these during connecting to the primary. */
1066 if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
1067 silc_server_announce_servers(server, TRUE, 0, ctx->sock);
1068 silc_server_announce_clients(server, 0, ctx->sock);
1069 silc_server_announce_channels(server, 0, ctx->sock);
1076 * Responder (all servers and routers)
1078 SilcServerConfigRouter *primary;
1080 /* We should have received START packet */
1081 if (ctx->type != SILC_SERVER_BACKUP_START) {
1082 SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
1086 /* Connect to the primary router that was down that is now supposed
1087 to be back online. We send the CONNECTED packet after we've
1088 established the connection to the primary router. */
1089 primary = silc_server_config_get_primary_router(server);
1090 if (primary && server->backup_primary &&
1091 !silc_server_num_sockets_by_remote(server,
1092 silc_net_is_ip(primary->host) ?
1093 primary->host : NULL,
1094 silc_net_is_ip(primary->host) ?
1095 NULL : primary->host,
1097 SILC_SOCKET_TYPE_ROUTER)) {
1098 SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
1100 silc_server_backup_reconnect(server,
1101 primary->host, primary->port,
1102 silc_server_backup_connect_primary,
1103 silc_socket_dup(ctx->sock));
1105 /* Nowhere to connect just return the CONNECTED packet */
1106 SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
1108 SILC_LOG_INFO(("Sending CONNECTED (session %d) to backup router",
1111 /* Send the CONNECTED packet back to the backup router. */
1112 data[0] = SILC_SERVER_BACKUP_CONNECTED;
1113 data[1] = ctx->session;
1114 silc_server_packet_send(server, ctx->sock,
1115 SILC_PACKET_RESUME_ROUTER, 0,
1116 data, sizeof(data), FALSE);
1119 /* Add this resuming session */
1120 ctx->sessions = silc_realloc(ctx->sessions,
1121 sizeof(*ctx->sessions) *
1122 (ctx->sessions_count + 1));
1123 ctx->sessions[ctx->sessions_count].session = ctx->session;
1124 ctx->sessions_count++;
1126 /* Normal server goes directly to the END state. */
1127 if (server->server_type == SILC_ROUTER &&
1129 server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
1132 protocol->state = SILC_PROTOCOL_STATE_END;
1137 if (ctx->responder == FALSE) {
1139 * Initiator (backup router)
1142 /* We should have received CONNECTED packet */
1143 if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
1144 SILC_LOG_ERROR(("Bad resume router packet CONNECTED %d", ctx->type));
1148 for (i = 0; i < ctx->sessions_count; i++) {
1149 if (ctx->sessions[i].session == ctx->session) {
1150 ctx->sessions[i].connected = TRUE;
1151 SILC_LOG_INFO(("Received CONNECTED from %s (session %d)",
1152 ctx->sessions[i].server_entry->server_name,
1154 SILC_LOG_DEBUG(("Received CONNECTED (session %d)", ctx->session));
1159 /* See if all returned CONNECTED, if not, then continue waiting. */
1160 for (i = 0; i < ctx->sessions_count; i++) {
1161 if (!ctx->sessions[i].connected)
1165 SILC_LOG_INFO(("All sessions have returned CONNECTED packets, "
1167 SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
1169 /* The ENDING is sent with timeout, and then we continue to the
1170 END state in the protocol. */
1171 silc_schedule_task_add(server->schedule, 0,
1172 silc_server_backup_send_resumed,
1173 protocol, 1, 0, SILC_TASK_TIMEOUT,
1174 SILC_TASK_PRI_NORMAL);
1179 * Responder (primary router)
1182 /* We should have been received ENDING packet */
1183 if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
1184 SILC_LOG_ERROR(("Bad resume router packet ENDING %d", ctx->type));
1188 SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
1190 /* Switch announced informations to our primary router of using the
1192 silc_server_local_servers_toggle_enabled(server, TRUE);
1193 silc_server_update_servers_by_server(server, ctx->sock->user_data,
1195 silc_server_update_clients_by_server(server, ctx->sock->user_data,
1196 server->router, TRUE);
1198 /* We as primary router now must send RESUMED packets to all servers
1199 and routers so that they know we are back. For backup router we
1200 send the packet last so that we give the backup as much time as
1201 possible to deal with message routing at this critical moment. */
1202 for (i = 0; i < server->config->param.connections_max; i++) {
1203 sock = server->sockets[i];
1204 if (!sock || !sock->user_data ||
1205 sock->user_data == server->id_entry ||
1206 (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1207 sock->type != SILC_SOCKET_TYPE_SERVER))
1210 /* Send to backup last */
1211 if (sock == ctx->sock)
1215 server_entry = sock->user_data;
1216 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1218 SILC_LOG_DEBUG(("Sending RESUMED to %s", server_entry->server_name));
1219 SILC_LOG_INFO(("Sending RESUMED to %s", server_entry->server_name));
1221 /* This connection is performing this protocol too now */
1222 sock->protocol = protocol;
1224 data[0] = SILC_SERVER_BACKUP_RESUMED;
1226 silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
1227 data, sizeof(data), FALSE);
1228 silc_server_packet_queue_purge(server,sock);
1231 /* Now send the same packet to backup */
1232 if (sock != ctx->sock) {
1235 goto send_to_backup;
1238 /* We are now resumed and are back as primary router in the cell. */
1239 SILC_LOG_INFO(("We are now the primary router of our cell again"));
1240 server->wait_backup = FALSE;
1242 /* For us this is the end of this protocol. */
1243 if (protocol->final_callback)
1244 silc_protocol_execute_final(protocol, server->schedule);
1246 silc_protocol_free(protocol);
1250 case SILC_PROTOCOL_STATE_END:
1253 * Responder (backup router, servers, and remote router)
1255 SilcServerEntry router, backup_router;
1257 /* We should have been received RESUMED from our primary router. */
1258 if (ctx->type != SILC_SERVER_BACKUP_RESUMED) {
1259 SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
1263 SILC_LOG_INFO(("Received RESUMED from new primary router"));
1265 /* If we are the backup router, mark that we are no longer primary
1266 but are back to backup router status. */
1267 if (server->backup_router)
1268 server->server_type = SILC_BACKUP_ROUTER;
1270 /* We have now new primary router. All traffic goes there from now on. */
1271 router = ctx->sock->user_data;
1272 if (silc_server_backup_replaced_get(server, router->id,
1275 if (backup_router == server->router) {
1276 /* We have new primary router now */
1277 server->id_entry->router = router;
1278 server->router = router;
1279 SILC_LOG_INFO(("Switching back to primary router %s",
1280 server->router->server_name));
1282 /* We are connected to new primary and now continue using it */
1283 SILC_LOG_INFO(("Resuming the use of primary router %s",
1284 router->server_name));
1286 server->backup_primary = FALSE;
1287 sock = router->connection;
1289 /* Update the client entries of the backup router to the new
1291 silc_server_local_servers_toggle_enabled(server, FALSE);
1292 router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1293 silc_server_update_servers_by_server(server, backup_router, router);
1294 silc_server_update_clients_by_server(server, NULL, router, FALSE);
1295 if (server->server_type == SILC_SERVER)
1296 silc_server_update_channels_by_server(server, backup_router, router);
1297 silc_server_backup_replaced_del(server, backup_router);
1299 /* Announce all of our information to the router. */
1300 if (server->server_type == SILC_ROUTER)
1301 silc_server_announce_servers(server, FALSE, ctx->start, sock);
1303 /* Announce our clients and channels to the router */
1304 silc_server_announce_clients(server, ctx->start, sock);
1305 silc_server_announce_channels(server, ctx->start, sock);
1308 /* Send notify about primary router going down to local operators */
1309 SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
1310 SILC_NOTIFY_TYPE_NONE,
1311 ("%s resumed the use of primary router %s",
1312 server->server_name,
1313 server->router->server_name));
1315 /* Protocol has ended, call the final callback */
1316 if (protocol->final_callback)
1317 silc_protocol_execute_final(protocol, server->schedule);
1319 silc_protocol_free(protocol);
1323 case SILC_PROTOCOL_STATE_ERROR:
1324 /* Protocol has ended, call the final callback */
1325 if (protocol->final_callback)
1326 silc_protocol_execute_final(protocol, server->schedule);
1328 silc_protocol_free(protocol);
1331 case SILC_PROTOCOL_STATE_FAILURE:
1332 /* Protocol has ended, call the final callback */
1333 SILC_LOG_ERROR(("Error during backup resume: received Failure"));
1334 if (protocol->final_callback)
1335 silc_protocol_execute_final(protocol, server->schedule);
1337 silc_protocol_free(protocol);
1340 case SILC_PROTOCOL_STATE_UNKNOWN:
1345 /* Final resuming protocol completion callback */
1347 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
1349 SilcProtocol protocol = (SilcProtocol)context;
1350 SilcServerBackupProtocolContext ctx = protocol->context;
1351 SilcServer server = ctx->server;
1352 SilcServerEntry server_entry;
1353 SilcSocketConnection sock;
1357 silc_schedule_task_del_by_context(server->schedule, protocol);
1359 error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1360 protocol->state == SILC_PROTOCOL_STATE_FAILURE);
1363 SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
1364 if (server->server_type == SILC_SERVER)
1365 silc_schedule_task_del_by_callback(server->schedule,
1366 silc_server_backup_connect_to_router);
1369 if (server->server_shutdown)
1372 /* Remove this protocol from all server entries that has it */
1373 for (i = 0; i < server->config->param.connections_max; i++) {
1374 sock = server->sockets[i];
1375 if (!sock || !sock->user_data ||
1376 (sock->type != SILC_SOCKET_TYPE_ROUTER &&
1377 sock->type != SILC_SOCKET_TYPE_SERVER))
1380 server_entry = sock->user_data;
1382 /* The SilcProtocol context was shared between all connections, clear
1383 it from all connections. */
1384 if (sock->protocol == protocol) {
1385 sock->protocol = NULL;
1388 /* If we are server close all router connections except backup,
1389 send confirmation to backup that using it is still ok and continue
1390 sending traffic there. The backup will reply with error if
1392 if (server->server_type == SILC_SERVER &&
1393 server_entry->server_type == SILC_ROUTER) {
1394 server->backup_noswitch = TRUE;
1395 if (sock->user_data)
1396 silc_server_free_sock_user_data(server, sock, NULL);
1397 silc_server_disconnect_remote(server, sock, 0, NULL);
1398 server->backup_noswitch = FALSE;
1400 /* Send START_USE just in case using backup wouldn't be ok. */
1401 silc_server_backup_send_start_use(server, server->router->connection,
1404 silc_server_create_connections(server);
1408 /* If error occurred and we are backup router, we close connections. */
1409 if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
1410 server->backup_noswitch = TRUE;
1411 server->server_type = SILC_BACKUP_ROUTER;
1412 if (ctx->sock == sock) {
1413 silc_socket_free(sock); /* unref */
1417 server->backup_noswitch = TRUE;
1418 if (sock->user_data)
1419 silc_server_free_sock_user_data(server, sock, NULL);
1420 silc_server_disconnect_remote(server, sock, 0, NULL);
1421 server->backup_noswitch = FALSE;
1423 silc_server_create_connections(server);
1428 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
1433 SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
1435 if (ctx->sock && ctx->sock->protocol)
1436 ctx->sock->protocol = NULL;
1438 silc_socket_free(ctx->sock); /* unref */
1439 silc_protocol_free(protocol);
1440 silc_free(ctx->sessions);