From: Pekka Riikonen Date: Sun, 12 Oct 2003 17:52:50 +0000 (+0000) Subject: Fixed SERVER_SIGNOFF handling on server to remove the client from X-Git-Tag: silc.client.0.9.13~6 X-Git-Url: http://git.silcnet.org/gitweb/?a=commitdiff_plain;h=f41ad3d6e1579f777796491a4a55c2311cd520dd;p=silc.git Fixed SERVER_SIGNOFF handling on server to remove the client from correct list. It caused clients to remain network after SERVER_SIGNOFF. Added timeout callback handling to rekey protocol. Do not execute rekey to disabled connections. Backup router fixes (tests continue). --- diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 7e5e99b9..2562c0f0 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -292,8 +292,10 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) { if (entry) { /* Remove from cache */ - if (!silc_idcache_del_by_context(id_list->servers, entry)) + if (!silc_idcache_del_by_context(id_list->servers, entry)) { + SILC_LOG_DEBUG(("Unknown server, did not delete")); return FALSE; + } SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ? entry->server_name : "", @@ -367,8 +369,10 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) if (entry) { /* Remove from cache */ - if (!silc_idcache_del_by_context(id_list->clients, entry)) + if (!silc_idcache_del_by_context(id_list->clients, entry)) { + SILC_LOG_DEBUG(("Unknown client, did not delete")); return FALSE; + } assert(!silc_hash_table_count(entry->channels)); @@ -657,8 +661,10 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) { if (entry) { /* Remove from cache */ - if (!silc_idcache_del_by_context(id_list->channels, entry)) + if (!silc_idcache_del_by_context(id_list->channels, entry)) { + SILC_LOG_DEBUG(("Unknown channel, did not delete")); return FALSE; + } SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name)); diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 1e60853d..6d12cefa 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -1322,11 +1322,11 @@ void silc_server_notify(SilcServer server, /* Get client entry */ client = silc_idlist_find_client_by_id(server->global_list, client_id, TRUE, &cache); - local = TRUE; + local = FALSE; if (!client) { client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, &cache); - local = FALSE; + local = TRUE; if (!client) { silc_free(client_id); continue; @@ -2565,11 +2565,12 @@ SilcServerEntry silc_server_new_server(SilcServer server, server_id, TRUE, NULL); if (server_entry) { if (SILC_IS_LOCAL(server_entry)) { - silc_server_disconnect_remote(server, server_entry->connection, + silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_OPERATION_ALLOWED, "Too many registrations"); - if (((SilcSocketConnection)server_entry->connection)->user_data) + if (sock->user_data) silc_server_free_sock_user_data(server, sock, NULL); + return NULL; } else { silc_idcache_del_by_context(server->local_list->servers, server_entry); } @@ -2578,12 +2579,12 @@ SilcServerEntry silc_server_new_server(SilcServer server, server_id, TRUE, NULL); if (server_entry) { if (SILC_IS_LOCAL(server_entry)) { - silc_server_disconnect_remote(server, server_entry->connection, + silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_OPERATION_ALLOWED, "Too many registrations"); - if (((SilcSocketConnection)server_entry->connection)->user_data) - silc_server_free_sock_user_data(server, server_entry->connection, - NULL); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + return NULL; } else { silc_idcache_del_by_context(server->global_list->servers, server_entry); @@ -3415,7 +3416,7 @@ void silc_server_rekey(SilcServer server, to the protocol. */ proto_ctx = silc_calloc(1, sizeof(*proto_ctx)); proto_ctx->server = (void *)server; - proto_ctx->sock = sock; + proto_ctx->sock = silc_socket_dup(sock); proto_ctx->responder = TRUE; proto_ctx->pfs = idata->rekey->pfs; diff --git a/apps/silcd/protocol.h b/apps/silcd/protocol.h index 75e58c7d..3c184abc 100644 --- a/apps/silcd/protocol.h +++ b/apps/silcd/protocol.h @@ -4,13 +4,12 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2003 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -98,6 +97,7 @@ typedef struct { bool pfs; /* TRUE if PFS is to be used */ SilcSKE ske; /* Defined if PFS is used */ SilcPacketContext *packet; + SilcTask timeout_task; } SilcServerRekeyInternalContext; /* Prototypes */ diff --git a/apps/silcd/server.c b/apps/silcd/server.c index d9e756d8..291b0922 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1441,6 +1441,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) server->router = id_entry; server->router->server_type = SILC_ROUTER; server->standalone = FALSE; + server->backup_primary = FALSE; /* If we are router then announce our possible servers. Backup router announces also global servers. */ @@ -3316,7 +3317,8 @@ void silc_server_free_sock_user_data(SilcServer server, if (server->router == user_data) { /* Check whether we have a backup router connection */ if (!backup_router || backup_router == user_data) { - silc_server_create_connections(server); + if (!server->no_reconnect) + silc_server_create_connections(server); server->id_entry->router = NULL; server->router = NULL; server->standalone = TRUE; @@ -3370,7 +3372,8 @@ void silc_server_free_sock_user_data(SilcServer server, } else if (server->server_type == SILC_SERVER && sock->type == SILC_SOCKET_TYPE_ROUTER) { /* Reconnect to the router (backup) */ - silc_server_create_connections(server); + if (!server->no_reconnect) + silc_server_create_connections(server); } if (user_data->server_name) @@ -3511,11 +3514,12 @@ void silc_server_remove_from_channels(SilcServer server, if (!client) return; - SILC_LOG_DEBUG(("Removing client from joined channels")); - if (notify && !client->id) notify = FALSE; + SILC_LOG_DEBUG(("Removing client %s from joined channels", + notify ? silc_id_render(client->id, SILC_ID_CLIENT) : "")); + if (notify) { clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); if (!clidp) @@ -5299,6 +5303,42 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, return buffer; } +/* Timeout callback for unsuccessful rekey. The rekey did not go through + for some reason. */ + +SILC_TASK_CALLBACK(silc_server_rekey_timeout) +{ + SilcServerRekeyInternalContext *ctx = context; + SilcServer server = app_context; + SilcSocketConnection sock = ctx->sock; + + SILC_LOG_DEBUG(("Timeout occurred in rekey protocol with %s:%d [%s]", + sock->hostname, sock->port, + (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : + sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : + sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : + "Router"))); + + SILC_LOG_WARNING(("Timeout occurred in rekey protocol with %s:%d [%s]", + sock->hostname, sock->port, + (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : + sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : + sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : + "Router"))); + + if (sock->protocol) { + silc_protocol_cancel(sock->protocol, server->schedule); + silc_protocol_free(sock->protocol); + sock->protocol = NULL; + } + if (ctx->packet) + silc_packet_context_free(ctx->packet); + if (ctx->ske) + silc_ske_free(ctx->ske); + silc_socket_free(sock); + silc_free(ctx); +} + /* A timeout callback for the re-key. We will be the initiator of the re-key protocol. */ @@ -5310,6 +5350,11 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback) SilcProtocol protocol; SilcServerRekeyInternalContext *proto_ctx; + /* Do not execute rekey with disabled connections, as it would not + go through anyway. */ + if (idata->status & SILC_IDLIST_STATUS_DISABLED) + return; + /* If rekey protocol is active already wait for it to finish */ if (sock->protocol && sock->protocol->protocol && sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) @@ -5325,13 +5370,18 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback) return; } - SILC_LOG_DEBUG(("Executing rekey protocol")); + SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]", + sock->hostname, sock->port, + (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : + sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : + sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : + "Router"))); /* Allocate internal protocol context. This is sent as context to the protocol. */ proto_ctx = silc_calloc(1, sizeof(*proto_ctx)); proto_ctx->server = (void *)server; - proto_ctx->sock = sock; + proto_ctx->sock = silc_socket_dup(sock); proto_ctx->responder = FALSE; proto_ctx->pfs = idata->rekey->pfs; @@ -5341,6 +5391,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback) &protocol, proto_ctx, silc_server_rekey_final); sock->protocol = protocol; + /* Register timeout callback in case the rekey does not go through. */ + proto_ctx->timeout_task = + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rekey_timeout, + proto_ctx, + server->config->key_exchange_timeout, 0, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_LOW); + /* Run the protocol */ silc_protocol_execute(protocol, server->schedule, 0, 0); } @@ -5357,6 +5416,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final) SilcSocketConnection sock = ctx->sock; SilcIDListData idata = (SilcIDListData)sock->user_data; + if (ctx->timeout_task) + silc_schedule_task_del(server->schedule, ctx->timeout_task); + if (protocol->state == SILC_PROTOCOL_STATE_ERROR || protocol->state == SILC_PROTOCOL_STATE_FAILURE) { /* Error occured during protocol */ @@ -5369,6 +5431,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final) silc_packet_context_free(ctx->packet); if (ctx->ske) silc_ske_free(ctx->ske); + silc_socket_free(sock); silc_free(ctx); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); @@ -5379,7 +5442,12 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final) return; } - SILC_LOG_DEBUG(("Rekey protocol completed")); + SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]", + sock->hostname, sock->port, + (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : + sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : + sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : + "Router"))); /* Purge the outgoing data queue to assure that all rekey packets really go to the network before we quit the protocol. */ @@ -5399,6 +5467,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final) silc_packet_context_free(ctx->packet); if (ctx->ske) silc_ske_free(ctx->ske); + silc_socket_free(sock); silc_free(ctx); } diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index 7bf72544..876eba20 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -63,12 +63,14 @@ typedef struct { typedef struct { SilcServer server; SilcSocketConnection sock; - bool responder; SilcUInt8 type; SilcUInt8 session; SilcServerBackupProtocolSession *sessions; SilcUInt32 sessions_count; long start; + unsigned int responder : 1; + unsigned int received_failure : 1; + unsigned int timeout : 1; } *SilcServerBackupProtocolContext; @@ -494,9 +496,11 @@ void silc_server_backup_send_replaced(SilcServer server, SILC_TASK_CALLBACK(silc_server_backup_timeout) { SilcProtocol protocol = context; + SilcServerBackupProtocolContext ctx = protocol->context; SilcServer server = app_context; SILC_LOG_INFO(("Timeout occurred during backup resuming protocol")); + ctx->timeout = TRUE; silc_protocol_cancel(protocol, server->schedule); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute_final(protocol, server->schedule); @@ -512,6 +516,7 @@ SILC_TASK_CALLBACK(silc_server_backup_responder_start) /* If other protocol is executing at the same time, start with timeout. */ if (sock->protocol) { + SILC_LOG_DEBUG(("Other protocol is executing, wait for it to finish")); silc_schedule_task_add(server->schedule, sock->sock, silc_server_backup_responder_start, proto_ctx, 2, 0, @@ -530,6 +535,22 @@ SILC_TASK_CALLBACK(silc_server_backup_responder_start) SILC_TASK_PRI_NORMAL); } +/* Callback to send START_USE to backup to check whether using backup + is ok. */ + +SILC_TASK_CALLBACK(silc_server_backup_check_status) +{ + SilcSocketConnection sock = context; + SilcServer server = app_context; + + /* Check whether we are still using backup */ + if (!server->backup_primary) + return; + + silc_server_backup_send_start_use(server, sock, FALSE); + silc_socket_free(sock); /* unref */ +} + typedef struct { SilcServer server; SilcSocketConnection sock; @@ -832,6 +853,7 @@ SILC_TASK_CALLBACK(silc_server_backup_connected_later) /* If running other protocol already run this one a bit later. */ if (sock->protocol) { + SILC_LOG_DEBUG(("Other protocol is running, wait for it to finish")); silc_schedule_task_add(server->schedule, 0, silc_server_backup_connected_later, proto_ctx, 10, 0, @@ -1295,14 +1317,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) if (server->server_type == SILC_SERVER) silc_server_update_channels_by_server(server, backup_router, router); silc_server_backup_replaced_del(server, backup_router); - - /* Announce all of our information to the router. */ - if (server->server_type == SILC_ROUTER) - silc_server_announce_servers(server, FALSE, ctx->start, sock); - - /* Announce our clients and channels to the router */ - silc_server_announce_clients(server, ctx->start, sock); - silc_server_announce_channels(server, ctx->start, sock); } /* Send notify about primary router going down to local operators */ @@ -1331,6 +1345,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) case SILC_PROTOCOL_STATE_FAILURE: /* Protocol has ended, call the final callback */ SILC_LOG_ERROR(("Error during backup resume: received Failure")); + ctx->received_failure = TRUE; if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); else @@ -1385,42 +1400,52 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done) sock->protocol = NULL; if (error) { - /* If we are server close all router connections except backup, - send confirmation to backup that using it is still ok and continue - sending traffic there. The backup will reply with error if - it's not ok. */ + if (server->server_type == SILC_SERVER && - server_entry->server_type == SILC_ROUTER) { - server->backup_noswitch = TRUE; - if (sock->user_data) - silc_server_free_sock_user_data(server, sock, NULL); - silc_server_disconnect_remote(server, sock, 0, NULL); - server->backup_noswitch = FALSE; - - /* Send START_USE just in case using backup wouldn't be ok. */ - silc_server_backup_send_start_use(server, server->router->connection, - FALSE); - - silc_server_create_connections(server); + server_entry->server_type == SILC_ROUTER) continue; - } - /* If error occurred and we are backup router, we close connections. */ + /* Backup router */ if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) { - server->backup_noswitch = TRUE; - server->server_type = SILC_BACKUP_ROUTER; if (ctx->sock == sock) { silc_socket_free(sock); /* unref */ ctx->sock = NULL; } - server->backup_noswitch = TRUE; - if (sock->user_data) - silc_server_free_sock_user_data(server, sock, NULL); - silc_server_disconnect_remote(server, sock, 0, NULL); - server->backup_noswitch = FALSE; + if (!ctx->received_failure) { + /* Protocol error, probably timeout. Just restart the protocol. */ + SilcServerBackupProtocolContext proto_ctx; + + /* Restart the protocol. */ + proto_ctx = silc_calloc(1, sizeof(*proto_ctx)); + proto_ctx->server = server; + proto_ctx->sock = silc_socket_dup(sock); + proto_ctx->responder = FALSE; + proto_ctx->type = SILC_SERVER_BACKUP_START; + proto_ctx->start = time(0); + + /* Start through scheduler */ + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_connected_later, + proto_ctx, 2, 0, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + } else { + /* If failure was received, switch back to normal backup router. + For some reason primary wouldn't accept that we were supposed + to perfom resuming protocol. */ + server->server_type = SILC_BACKUP_ROUTER; + silc_server_local_servers_toggle_enabled(server, FALSE); + silc_server_update_servers_by_server(server, server->id_entry, + sock->user_data); + silc_server_update_clients_by_server(server, NULL, + sock->user_data, FALSE); + + /* Announce our clients and channels to the router */ + silc_server_announce_clients(server, ctx->start, sock); + silc_server_announce_channels(server, ctx->start, sock); + } - silc_server_create_connections(server); continue; } } @@ -1429,9 +1454,53 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done) } } - if (!error) + if (!error) { SILC_LOG_INFO(("Backup resuming protocol ended successfully")); + if (ctx->type == SILC_SERVER_BACKUP_RESUMED && server->router) { + /* Announce all of our information to the router. */ + if (server->server_type == SILC_ROUTER) + silc_server_announce_servers(server, FALSE, ctx->start, + server->router->connection); + + /* Announce our clients and channels to the router */ + silc_server_announce_clients(server, ctx->start, + server->router->connection); + silc_server_announce_channels(server, ctx->start, + server->router->connection); + } + } else { + /* Error */ + + if (server->server_type == SILC_SERVER) { + /* If we are still using backup router Send confirmation to backup + that using it is still ok and continue sending traffic there. + The backup will reply with error if it's not ok. */ + if (server->router && server->backup_primary) { + /* Send START_USE just in case using backup wouldn't be ok. */ + silc_server_backup_send_start_use(server, server->router->connection, + FALSE); + + /* Check couple of times same START_USE just in case. */ + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_check_status, + silc_socket_dup(server->router->connection), + 5, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_check_status, + silc_socket_dup(server->router->connection), + 20, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_check_status, + silc_socket_dup(server->router->connection), + 60, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + } + } + } + if (ctx->sock && ctx->sock->protocol) ctx->sock->protocol = NULL; if (ctx->sock) diff --git a/apps/silcd/server_internal.h b/apps/silcd/server_internal.h index bd601f9e..7cf42a8e 100644 --- a/apps/silcd/server_internal.h +++ b/apps/silcd/server_internal.h @@ -92,6 +92,8 @@ struct SilcServerStruct { unsigned int wait_backup : 1; /* Set if we are waiting for backup router to connect to us. */ unsigned int server_shutdown: 1; /* Set when shutting down */ + unsigned int no_reconnect : 1; /* If set, server won't reconnect to + router after disconnection. */ SilcServerEntry router; /* Pointer to the primary router */ unsigned long router_connect; /* Time when router was connected */ diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index 1bc86f7c..8405f7e9 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -650,7 +650,16 @@ void silc_server_update_servers_by_server(SilcServer server, whether this server is in our cell, but not connected to us (in which case we must remove it). */ - if (server_entry->router == from) { + if (from) { + if (server_entry->router == from) { + SILC_LOG_DEBUG(("Updating server (local) %s", + server_entry->server_name ? + server_entry->server_name : "")); + server_entry->router = to; + server_entry->connection = to->connection; + } + } else { + /* Update all */ SILC_LOG_DEBUG(("Updating server (local) %s", server_entry->server_name ? server_entry->server_name : "")); @@ -696,7 +705,16 @@ void silc_server_update_servers_by_server(SilcServer server, whether this server is in our cell, but not connected to us (in which case we must remove it). */ - if (server_entry->router == from) { + if (from) { + if (server_entry->router == from) { + SILC_LOG_DEBUG(("Updating server (global) %s", + server_entry->server_name ? + server_entry->server_name : "")); + server_entry->router = to; + server_entry->connection = to->connection; + } + } else { + /* Update all */ SILC_LOG_DEBUG(("Updating server (global) %s", server_entry->server_name ? server_entry->server_name : "")); @@ -885,8 +903,13 @@ void silc_server_update_channels_by_server(SilcServer server, if (silc_idcache_list_first(list, &id_cache)) { while (id_cache) { channel = (SilcChannelEntry)id_cache->context; - if (channel->router == from) + if (from) { + if (channel->router == from) + channel->router = to; + } else { + /* Update all */ channel->router = to; + } if (!silc_idcache_list_next(list, &id_cache)) break; } @@ -1837,7 +1860,7 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list, if (type == 1) { /* Invite string. Get the old invite string from hash table and append this at the end of the existing one. */ - if (!silc_hash_table_find(list, (void *)1, NULL, (void **)&tmp2)) { + if (!silc_hash_table_find(list, (void *)1, NULL, (void *)&tmp2)) { tmp2 = silc_calloc(1, sizeof(*tmp2)); silc_hash_table_add(list, (void *)1, tmp2); }