X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fserver.c;h=c3359196fe887f7dfc30da1aeed9c6a8b751f15c;hp=93e81034a7eb663347607fc84591458234ba15f5;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=18774fe934132c6e5376757e63e43ac3f3b22577 diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 93e81034..c3359196 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1,6 +1,6 @@ /* - server.c + server.c Author: Pekka Riikonen @@ -8,8 +8,7 @@ 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 @@ -28,9 +27,9 @@ #include "server_internal.h" /* Static prototypes */ +SILC_TASK_CALLBACK(silc_server_rehash_close_connection); SILC_TASK_CALLBACK(silc_server_connect_to_router_retry); SILC_TASK_CALLBACK(silc_server_connect_router); -SILC_TASK_CALLBACK(silc_server_connect_to_router); SILC_TASK_CALLBACK(silc_server_connect_to_router_second); SILC_TASK_CALLBACK(silc_server_connect_to_router_final); SILC_TASK_CALLBACK(silc_server_accept_new_connection); @@ -42,8 +41,6 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final); SILC_TASK_CALLBACK(silc_server_free_client_data_timeout); SILC_TASK_CALLBACK(silc_server_timeout_remote); SILC_TASK_CALLBACK(silc_server_channel_key_rekey); -SILC_TASK_CALLBACK(silc_server_failure_callback); -SILC_TASK_CALLBACK(silc_server_rekey_callback); SILC_TASK_CALLBACK(silc_server_get_stats); /* Allocates a new SILC server object. This has to be done before the server @@ -77,21 +74,26 @@ int silc_server_alloc(SilcServer *new_server) void silc_server_free(SilcServer server) { + SilcIDCacheList list; + SilcIDCacheEntry cache; + if (!server) return; #ifdef SILC_SIM { SilcSim sim; - + silc_dlist_start(server->sim); while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) { silc_dlist_del(server->sim, sim); + silc_sim_close(sim); silc_sim_free(sim); } silc_dlist_uninit(server->sim); } #endif + silc_server_backup_free(server); silc_server_config_unref(&server->config_ref); if (server->rng) silc_rng_free(server->rng); @@ -106,6 +108,66 @@ void silc_server_free(SilcServer server) if (server->id_entry) silc_idlist_del_server(server->local_list, server->id_entry); + /* Delete all channels */ + list = NULL; + if (silc_idcache_get_all(server->local_list->channels, &list) && + silc_idcache_list_first(list, &cache)) { + silc_idlist_del_channel(server->local_list, cache->context); + while (silc_idcache_list_next(list, &cache)) + silc_idlist_del_channel(server->local_list, cache->context); + } + if (list) + silc_idcache_list_free(list); + list = NULL; + if (silc_idcache_get_all(server->global_list->channels, &list) && + silc_idcache_list_first(list, &cache)) { + silc_idlist_del_channel(server->global_list, cache->context); + while (silc_idcache_list_next(list, &cache)) + silc_idlist_del_channel(server->global_list, cache->context); + } + if (list) + silc_idcache_list_free(list); + + /* Delete all clients */ + list = NULL; + if (silc_idcache_get_all(server->local_list->clients, &list) && + silc_idcache_list_first(list, &cache)) { + silc_idlist_del_client(server->local_list, cache->context); + while (silc_idcache_list_next(list, &cache)) + silc_idlist_del_client(server->local_list, cache->context); + } + if (list) + silc_idcache_list_free(list); + list = NULL; + if (silc_idcache_get_all(server->global_list->clients, &list) && + silc_idcache_list_first(list, &cache)) { + silc_idlist_del_client(server->global_list, cache->context); + while (silc_idcache_list_next(list, &cache)) + silc_idlist_del_client(server->global_list, cache->context); + } + if (list) + silc_idcache_list_free(list); + + /* Delete all servers */ + list = NULL; + if (silc_idcache_get_all(server->local_list->servers, &list) && + silc_idcache_list_first(list, &cache)) { + silc_idlist_del_server(server->local_list, cache->context); + while (silc_idcache_list_next(list, &cache)) + silc_idlist_del_server(server->local_list, cache->context); + } + if (list) + silc_idcache_list_free(list); + list = NULL; + if (silc_idcache_get_all(server->global_list->servers, &list) && + silc_idcache_list_first(list, &cache)) { + silc_idlist_del_server(server->global_list, cache->context); + while (silc_idcache_list_next(list, &cache)) + silc_idlist_del_server(server->global_list, cache->context); + } + if (list) + silc_idcache_list_free(list); + silc_idcache_free(server->local_list->clients); silc_idcache_free(server->local_list->servers); silc_idcache_free(server->local_list->channels); @@ -137,7 +199,7 @@ static bool silc_server_listen(SilcServer server, const char *server_ip, { *sock = silc_net_create_server(port, server_ip); if (*sock < 0) { - SILC_LOG_ERROR(("Could not create server listener: %s on %hu", + SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu", server_ip, port)); return FALSE; } @@ -188,10 +250,10 @@ bool silc_server_init_secondary(SilcServer server) newsocket->user_data = (void *)server->id_entry; silc_schedule_task_add(server->schedule, sock_list[sock], - silc_server_accept_new_connection, - (void *)server, 0, 0, - SILC_TASK_FD, - SILC_TASK_PRI_NORMAL); + silc_server_accept_new_connection, + (void *)server, 0, 0, + SILC_TASK_FD, + SILC_TASK_PRI_NORMAL); } return TRUE; @@ -221,7 +283,7 @@ bool silc_server_init(SilcServer server) server->starttime = time(NULL); /* Take config object for us */ - silc_server_config_ref(&server->config_ref, server->config, + silc_server_config_ref(&server->config_ref, server->config, server->config); /* Steal public and private key from the config object */ @@ -256,7 +318,8 @@ bool silc_server_init(SilcServer server) silc_pkcs_private_key_set(server->pkcs, server->private_key); /* Initialize the scheduler */ - server->schedule = silc_schedule_init(server->config->param.connections_max); + server->schedule = silc_schedule_init(server->config->param.connections_max, + server); if (!server->schedule) goto err; @@ -278,7 +341,7 @@ bool silc_server_init(SilcServer server) server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL); /* Init watcher list */ - server->watcher_list = + server->watcher_list = silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL, silc_hash_data_compare, (void *)CLIENTID_HASH_LEN, NULL, NULL, TRUE); @@ -410,27 +473,23 @@ bool silc_server_init(SilcServer server) /* Clients local list */ server->purge_i = purge = silc_calloc(1, sizeof(*purge)); purge->cache = server->local_list->clients; - purge->schedule = server->schedule; purge->timeout = 600; - silc_schedule_task_add(purge->schedule, 0, - silc_idlist_purge, + silc_schedule_task_add(server->schedule, 0, silc_idlist_purge, (void *)purge, purge->timeout, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); /* Clients global list */ server->purge_g = purge = silc_calloc(1, sizeof(*purge)); purge->cache = server->global_list->clients; - purge->schedule = server->schedule; purge->timeout = 300; - silc_schedule_task_add(purge->schedule, 0, - silc_idlist_purge, + silc_schedule_task_add(server->schedule, 0, silc_idlist_purge, (void *)purge, purge->timeout, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); /* If we are normal server we'll retrieve network statisticial information once in a while from the router. */ - if (server->server_type == SILC_SERVER) - silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats, + if (server->server_type != SILC_ROUTER) + silc_schedule_task_add(server->schedule, 0, silc_server_get_stats, server, 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); @@ -448,6 +507,31 @@ bool silc_server_init(SilcServer server) return FALSE; } +/* Task callback to close a socket connection after rehash */ + +SILC_TASK_CALLBACK(silc_server_rehash_close_connection) +{ + SilcServer server = context; + SilcSocketConnection sock = server->sockets[fd]; + + if (!sock) + return; + + SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured", + 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_schedule_task_del_by_context(server->schedule, sock); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_BANNED_FROM_SERVER, + "This connection is removed from " + "configuration"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); +} + /* This function basically reads the config file again and switches the config object pointed by the server object. After that, we have to fix various things such as the server_name and the listening ports. @@ -516,6 +600,101 @@ bool silc_server_rehash(SilcServer server) silc_pkcs_private_key_set(server->pkcs, server->private_key); } + /* Check for unconfigured server and router connections and close + connections that were unconfigured. */ + + if (server->config->routers) { + SilcServerConfigRouter *ptr; + SilcServerConfigRouter *newptr; + bool found; + + for (ptr = server->config->routers; ptr; ptr = ptr->next) { + found = FALSE; + + /* Check whether new config has this one too */ + for (newptr = newconfig->routers; newptr; newptr = newptr->next) { + if (silc_string_compare(newptr->host, ptr->host) && + newptr->port == ptr->port && + newptr->initiator == ptr->initiator) { + found = TRUE; + break; + } + } + + if (!found && ptr->host) { + /* Remove this connection */ + SilcSocketConnection sock; + sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER, + ptr->host, ptr->port); + if (sock && !SILC_IS_LISTENER(sock)) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rehash_close_connection, + server, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + } + } + } + + if (server->config->servers) { + SilcServerConfigServer *ptr; + SilcServerConfigServer *newptr; + bool found; + + for (ptr = server->config->servers; ptr; ptr = ptr->next) { + found = FALSE; + + /* Check whether new config has this one too */ + for (newptr = newconfig->servers; newptr; newptr = newptr->next) { + if (silc_string_compare(newptr->host, ptr->host)) { + found = TRUE; + break; + } + } + + if (!found && ptr->host) { + /* Remove this connection */ + SilcSocketConnection sock; + sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER, + ptr->host, 0); + if (sock && !SILC_IS_LISTENER(sock)) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rehash_close_connection, + server, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + } + } + } + + if (server->config->clients) { + SilcServerConfigClient *ptr; + SilcServerConfigClient *newptr; + bool found; + + for (ptr = server->config->clients; ptr; ptr = ptr->next) { + found = FALSE; + + /* Check whether new config has this one too */ + for (newptr = newconfig->clients; newptr; newptr = newptr->next) { + if (silc_string_compare(newptr->host, ptr->host)) { + found = TRUE; + break; + } + } + + if (!found && ptr->host) { + /* Remove this connection */ + SilcSocketConnection sock; + sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_CLIENT, + ptr->host, 0); + if (sock) + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_rehash_close_connection, + server, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + } + } + } + /* Go through all configured routers after rehash */ silc_schedule_task_add(server->schedule, 0, silc_server_connect_to_router, @@ -573,21 +752,33 @@ void silc_server_run(SilcServer server) void silc_server_stop(SilcServer server) { - SILC_LOG_DEBUG(("Stopping server")); + SILC_LOG_INFO(("SILC Server shutting down")); if (server->schedule) { int i; + server->server_shutdown = TRUE; + /* Close all connections */ for (i = 0; i < server->config->param.connections_max; i++) { if (!server->sockets[i]) continue; if (!SILC_IS_LISTENER(server->sockets[i])) { + SilcSocketConnection sock = server->sockets[i]; + SilcIDListData idata = sock->user_data; + + if (idata) + idata->status &= ~SILC_IDLIST_STATUS_DISABLED; + silc_schedule_task_del_by_context(server->schedule, server->sockets[i]); silc_server_disconnect_remote(server, server->sockets[i], SILC_STATUS_OK, "Server is shutting down"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, + "Server is shutting down"); + silc_socket_free(sock); } else { silc_socket_free(server->sockets[i]); server->sockets[i] = NULL; @@ -695,12 +886,21 @@ void silc_server_start_key_exchange(SilcServer server, SILC_TASK_CALLBACK(silc_server_connect_to_router_retry) { + SilcServer server = app_context; SilcServerConnection sconn = (SilcServerConnection)context; - SilcServer server = sconn->server; SilcServerConfigRouter *conn = sconn->conn.ref_ptr; SilcServerConfigConnParams *param = (conn->param ? conn->param : &server->config->param); + /* Don't retry if we are shutting down. */ + if (server->server_shutdown) { + silc_server_config_unref(&sconn->conn); + silc_free(sconn->remote_host); + silc_free(sconn->backup_replace_ip); + silc_free(sconn); + return; + } + SILC_LOG_INFO(("Retrying connecting to a router")); /* Calculate next timeout */ @@ -726,6 +926,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry) return; } + SILC_LOG_DEBUG(("Retrying connecting to a router in %d seconds", + sconn->retry_timeout)); + /* We will lookup a fresh pointer later */ silc_server_config_unref(&sconn->conn); @@ -739,11 +942,19 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry) SILC_TASK_CALLBACK(silc_server_connect_router) { + SilcServer server = app_context; SilcServerConnection sconn = (SilcServerConnection)context; - SilcServer server = sconn->server; SilcServerConfigRouter *rconn; int sock; + /* Don't connect if we are shutting down. */ + if (server->server_shutdown) { + silc_free(sconn->remote_host); + silc_free(sconn->backup_replace_ip); + silc_free(sconn); + return; + } + SILC_LOG_INFO(("Connecting to the %s %s on port %d", (sconn->backup ? "backup router" : "router"), sconn->remote_host, sconn->remote_port)); @@ -775,8 +986,12 @@ SILC_TASK_CALLBACK(silc_server_connect_router) silc_server_connect_to_router_retry, context, 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); - else + else { silc_server_config_unref(&sconn->conn); + silc_free(sconn->remote_host); + silc_free(sconn->backup_replace_ip); + silc_free(sconn); + } return; } @@ -789,26 +1004,25 @@ SILC_TASK_CALLBACK(silc_server_connect_router) server to do authentication and key exchange with our router - called from schedule. */ -SILC_TASK_CALLBACK(silc_server_connect_to_router) +SILC_TASK_CALLBACK_GLOBAL(silc_server_connect_to_router) { SilcServer server = (SilcServer)context; SilcServerConnection sconn; SilcServerConfigRouter *ptr; - SILC_LOG_DEBUG(("Connecting to router(s)")); + /* Don't connect if we are shutting down. */ + if (server->server_shutdown) + return; - if (server->server_type == SILC_SERVER) { - SILC_LOG_DEBUG(("We are normal server")); - } else if (server->server_type == SILC_ROUTER) { - SILC_LOG_DEBUG(("We are router")); - } else { - SILC_LOG_DEBUG(("We are backup router/normal server")); - } + SILC_LOG_DEBUG(("We are %s", + (server->server_type == SILC_SERVER ? + "normal server" : server->server_type == SILC_ROUTER ? + "router" : "backup router/normal server"))); if (!server->config->routers) { /* There wasn't a configured router, we will continue but we don't have a connection to outside world. We will be standalone server. */ - SILC_LOG_DEBUG(("No router(s), server will be standalone")); + SILC_LOG_DEBUG(("No router(s), we are standalone")); server->standalone = TRUE; return; } @@ -827,6 +1041,11 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) ptr->initiator ? "Initiator" : "Responder", ptr->host, ptr->port)); + if (server->server_type == SILC_ROUTER && ptr->backup_router && + ptr->initiator == FALSE && !server->backup_router && + !silc_server_config_get_backup_router(server)) + server->wait_backup = TRUE; + if (ptr->initiator) { /* Check whether we are connected to this host already */ if (silc_server_num_sockets_by_remote(server, @@ -841,7 +1060,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) /* Allocate connection object for hold connection specific stuff. */ sconn = silc_calloc(1, sizeof(*sconn)); - sconn->server = server; sconn->remote_host = strdup(ptr->host); sconn->remote_port = ptr->port; sconn->backup = ptr->backup_router; @@ -889,14 +1107,26 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) silc_ske_free(ctx->ske); silc_free(ctx->dest_id); silc_free(ctx); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); + + /* Try reconnecting if configuration wants it */ + if (!sconn->no_reconnect) { + silc_schedule_task_add(server->schedule, 0, + silc_server_connect_to_router_retry, + sconn, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + return; + } + + /* Call completion to indicate error */ + if (sconn->callback) + (*sconn->callback)(server, NULL, sconn->callback_context); + silc_server_config_unref(&sconn->conn); silc_free(sconn->remote_host); silc_free(sconn->backup_replace_ip); silc_free(sconn); - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); return; } @@ -920,14 +1150,26 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) silc_ske_free(ctx->ske); silc_free(ctx->dest_id); silc_free(ctx); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); + + /* Try reconnecting if configuration wants it */ + if (!sconn->no_reconnect) { + silc_schedule_task_add(server->schedule, 0, + silc_server_connect_to_router_retry, + sconn, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + return; + } + + /* Call completion to indicate error */ + if (sconn->callback) + (*sconn->callback)(server, NULL, sconn->callback_context); + silc_server_config_unref(&sconn->conn); silc_free(sconn->remote_host); silc_free(sconn->backup_replace_ip); silc_free(sconn); - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); return; } silc_ske_free_key_material(ctx->keymat); @@ -982,8 +1224,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) silc_free(sconn->remote_host); silc_free(sconn->backup_replace_ip); silc_free(sconn); - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); return; @@ -1029,9 +1269,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) SilcServer server = (SilcServer)ctx->server; SilcServerConnection sconn = (SilcServerConnection)ctx->context; SilcSocketConnection sock = ctx->sock; - SilcServerEntry id_entry; + SilcServerEntry id_entry = NULL; SilcBuffer packet; - SilcServerHBContext hb_context; unsigned char *id_string; SilcUInt32 id_len; SilcIDListData idata; @@ -1046,6 +1285,16 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) silc_free(ctx->dest_id); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED, NULL); + + /* Try reconnecting if configuration wants it */ + if (!sconn->no_reconnect) { + silc_schedule_task_add(server->schedule, 0, + silc_server_connect_to_router_retry, + sconn, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + goto out2; + } + goto out; } @@ -1097,7 +1346,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) SILC_LOG_DEBUG(("New server id(%s)", silc_id_render(ctx->dest_id, SILC_ID_SERVER))); - /* Add the connected router to global server list */ + /* Add the connected router to global server list. Router is sent + as NULL since it's local to us. */ id_entry = silc_idlist_add_server(server->global_list, strdup(sock->hostname), SILC_ROUTER, ctx->dest_id, NULL, sock); @@ -1114,24 +1364,21 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) sock->user_data = (void *)id_entry; sock->type = SILC_SOCKET_TYPE_ROUTER; idata = (SilcIDListData)sock->user_data; - idata->status |= SILC_IDLIST_STATUS_REGISTERED; + idata->status |= (SILC_IDLIST_STATUS_REGISTERED | + SILC_IDLIST_STATUS_LOCAL); conn = sconn->conn.ref_ptr; param = &server->config->param; if (conn && conn->param) param = conn->param; - /* Perform keepalive. The `hb_context' will be freed automatically - when finally calling the silc_socket_free function. */ - hb_context = silc_calloc(1, sizeof(*hb_context)); - hb_context->server = server; - silc_socket_set_heartbeat(sock, param->keepalive_secs, hb_context, + /* Perform keepalive. */ + silc_socket_set_heartbeat(sock, param->keepalive_secs, server, silc_server_perform_heartbeat, server->schedule); /* Register re-key timeout */ idata->rekey->timeout = param->key_exchange_rekey; - idata->rekey->context = (void *)server; silc_schedule_task_add(server->schedule, sock->sock, silc_server_rekey_callback, (void *)sock, idata->rekey->timeout, 0, @@ -1140,25 +1387,27 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) if (!sconn->backup) { /* Mark this router our primary router if we're still standalone */ if (server->standalone) { + SILC_LOG_DEBUG(("This connection is our primary router")); server->id_entry->router = id_entry; server->router = id_entry; server->standalone = FALSE; - /* If we are router then announce our possible servers. */ + /* If we are router then announce our possible servers. Backup + router announces also global servers. */ if (server->server_type == SILC_ROUTER) - silc_server_announce_servers(server, FALSE, 0, - server->router->connection); + silc_server_announce_servers(server, + server->backup_router ? TRUE : FALSE, + 0, SILC_PRIMARY_ROUTE(server)); /* Announce our clients and channels to the router */ - silc_server_announce_clients(server, 0, server->router->connection); - silc_server_announce_channels(server, 0, server->router->connection); + silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server)); + silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server)); -#ifdef BACKUP_SINGLE_ROUTER /* If we are backup router then this primary router is whom we are backing up. */ if (server->server_type == SILC_BACKUP_ROUTER) - silc_server_backup_add(server, server->id_entry, sock->ip, 0, TRUE); -#endif /* BACKUP_SINGLE_ROUTER */ + silc_server_backup_add(server, server->id_entry, sock->ip, + sconn->remote_port, TRUE); } } else { /* Add this server to be our backup router */ @@ -1168,12 +1417,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) sock->protocol = NULL; + out: /* Call the completion callback to indicate that we've connected to the router */ - if (sconn->callback) + if (sconn && sconn->callback) (*sconn->callback)(server, id_entry, sconn->callback_context); - out: /* Free the temporary connection data context */ if (sconn) { silc_server_config_unref(&sconn->conn); @@ -1184,6 +1433,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) if (sconn == server->router_conn) server->router_conn = NULL; + out2: /* Free the protocol object */ if (sock->protocol == protocol) sock->protocol = NULL; @@ -1215,10 +1465,6 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, SilcServerConfigDeny *deny; int port; - context = (void *)server; - - SILC_LOG_DEBUG(("Start")); - /* Check whether we could resolve both IP and FQDN. */ if (!sock->ip || (!strcmp(sock->ip, sock->hostname) && server->config->require_reverse_lookup)) { @@ -1239,6 +1485,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, However, this doesn't set the scheduler for outgoing traffic, it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT, later when outgoing data is available. */ + context = (void *)server; SILC_REGISTER_CONNECTION_FOR_IO(sock->sock); SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname, @@ -1319,6 +1566,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, initiator of the protocol thus we will wait for initiation from there before we start the protocol. */ server->stat.auth_attempts++; + SILC_LOG_DEBUG(("Starting key exchange protocol")); silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, &sock->protocol, proto_ctx, silc_server_accept_new_connection_second); @@ -1404,6 +1652,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) || (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) { /* Error occured during protocol */ + SILC_LOG_DEBUG(("Error key exchange protocol")); silc_protocol_free(protocol); sock->protocol = NULL; silc_ske_free_key_material(ctx->keymat); @@ -1416,8 +1665,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) silc_server_config_unref(&ctx->sconfig); silc_server_config_unref(&ctx->rconfig); silc_free(ctx); - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); @@ -1436,6 +1683,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) ctx->ske->prop->hmac, ctx->ske->prop->group, ctx->responder)) { + SILC_LOG_ERROR(("Error setting key material in use")); silc_protocol_free(protocol); sock->protocol = NULL; silc_ske_free_key_material(ctx->keymat); @@ -1448,8 +1696,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) silc_server_config_unref(&ctx->sconfig); silc_server_config_unref(&ctx->rconfig); silc_free(ctx); - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL); server->stat.auth_failures++; @@ -1481,6 +1727,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) but we won't start it yet. We will be receiving party of this protocol thus we will wait that connecting party will make their first move. */ + SILC_LOG_DEBUG(("Starting connection authentication protocol")); silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH, &sock->protocol, proto_ctx, silc_server_accept_new_connection_final); @@ -1496,6 +1743,16 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) SILC_TASK_PRI_LOW); } +/* After this is called, server don't wait for backup router anymore. + This gets called automatically even after we have backup router + connection established. */ + +SILC_TASK_CALLBACK(silc_server_backup_router_wait) +{ + SilcServer server = context; + server->wait_backup = FALSE; +} + /* Final part of accepting new connection. The connection has now been authenticated and keys has been exchanged. We also know whether this is client or server connection. */ @@ -1507,16 +1764,14 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) (SilcServerConnAuthInternalContext *)protocol->context; SilcServer server = (SilcServer)ctx->server; SilcSocketConnection sock = ctx->sock; - SilcServerHBContext hb_context; SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data; void *id_entry; - SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs; - - SILC_LOG_DEBUG(("Start")); + SilcServerConfigConnParams *param = &server->config->param; if (protocol->state == SILC_PROTOCOL_STATE_ERROR || protocol->state == SILC_PROTOCOL_STATE_FAILURE) { /* Error occured during protocol */ + SILC_LOG_DEBUG(("Error during authentication protocol")); silc_protocol_free(protocol); sock->protocol = NULL; if (ctx->packet) @@ -1528,8 +1783,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) silc_server_config_unref(&ctx->sconfig); silc_server_config_unref(&ctx->rconfig); silc_free(ctx); - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED, NULL); server->stat.auth_failures++; @@ -1552,6 +1805,36 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) goto out; } + /* If we are primary router and we have backup router configured + but it has not connected to use yet, do not accept any other + connection. */ + if (server->wait_backup && server->server_type == SILC_ROUTER && + !server->backup_router) { + SilcServerConfigRouter *router; + router = silc_server_config_get_backup_router(server); + if (router && strcmp(server->config->server_info->primary->server_ip, + sock->ip) && + silc_server_find_socket_by_host(server, + SILC_SOCKET_TYPE_SERVER, + router->backup_replace_ip, 0)) { + SILC_LOG_INFO(("Will not accept connections because we do " + "not have backup router connection established")); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_PERM_DENIED, + "We do not have connection to backup " + "router established, try later"); + silc_free(sock->user_data); + server->stat.auth_failures++; + + /* From here on, wait 10 seconds for the backup router to appear. */ + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_router_wait, + (void *)server, 10, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + goto out; + } + } + SILC_LOG_DEBUG(("Remote host is client")); SILC_LOG_INFO(("Connection %s (%s) is client", sock->hostname, sock->ip)); @@ -1569,6 +1852,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) server->stat.auth_failures++; goto out; } + entry->data.status |= SILC_IDLIST_STATUS_LOCAL; /* Statistics */ server->stat.my_clients++; @@ -1577,8 +1861,22 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) /* Get connection parameters */ if (conn->param) { - if (conn->param->keepalive_secs) - hearbeat_timeout = conn->param->keepalive_secs; + param = conn->param; + + if (!param->keepalive_secs) + param->keepalive_secs = server->config->param.keepalive_secs; + + if (!param->qos && server->config->param.qos) { + param->qos = server->config->param.qos; + param->qos_rate_limit = server->config->param.qos_rate_limit; + param->qos_bytes_limit = server->config->param.qos_bytes_limit; + param->qos_limit_sec = server->config->param.qos_limit_sec; + param->qos_limit_usec = server->config->param.qos_limit_usec; + } + + /* Check if to be anonymous connection */ + if (param->anonymous) + client->mode |= SILC_UMODE_ANONYMOUS; } id_entry = (void *)client; @@ -1596,20 +1894,48 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr; SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr; + /* If we are backup router and this is incoming server connection + and we do not have connection to primary router, do not allow + the connection. */ + if (server->server_type == SILC_BACKUP_ROUTER && + ctx->conn_type == SILC_SOCKET_TYPE_SERVER && + !SILC_PRIMARY_ROUTE(server)) { + SILC_LOG_INFO(("Will not accept server connection because we do " + "not have primary router connection established")); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_PERM_DENIED, + "We do not have connection to primary " + "router established, try later"); + silc_free(sock->user_data); + server->stat.auth_failures++; + goto out; + } + if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) { /* Verify whether this connection is after all allowed to connect */ if (!silc_server_connection_allowed(server, sock, ctx->conn_type, &server->config->param, rconn ? rconn->param : NULL, ctx->ske)) { + silc_free(sock->user_data); server->stat.auth_failures++; goto out; } if (rconn) { if (rconn->param) { - if (rconn->param->keepalive_secs) - hearbeat_timeout = rconn->param->keepalive_secs; + param = rconn->param; + + if (!param->keepalive_secs) + param->keepalive_secs = server->config->param.keepalive_secs; + + if (!param->qos && server->config->param.qos) { + param->qos = server->config->param.qos; + param->qos_rate_limit = server->config->param.qos_rate_limit; + param->qos_bytes_limit = server->config->param.qos_bytes_limit; + param->qos_limit_sec = server->config->param.qos_limit_sec; + param->qos_limit_usec = server->config->param.qos_limit_usec; + } } initiator = rconn->initiator; @@ -1626,19 +1952,60 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) &server->config->param, sconn ? sconn->param : NULL, ctx->ske)) { + silc_free(sock->user_data); server->stat.auth_failures++; goto out; } if (sconn) { if (sconn->param) { - if (sconn->param->keepalive_secs) - hearbeat_timeout = sconn->param->keepalive_secs; + param = sconn->param; + + if (!param->keepalive_secs) + param->keepalive_secs = server->config->param.keepalive_secs; + + if (!param->qos && server->config->param.qos) { + param->qos = server->config->param.qos; + param->qos_rate_limit = server->config->param.qos_rate_limit; + param->qos_bytes_limit = server->config->param.qos_bytes_limit; + param->qos_limit_sec = server->config->param.qos_limit_sec; + param->qos_limit_usec = server->config->param.qos_limit_usec; + } } backup_router = sconn->backup_router; } } + /* If we are primary router and we have backup router configured + but it has not connected to use yet, do not accept any other + connection. */ + if (server->wait_backup && server->server_type == SILC_ROUTER && + !server->backup_router && !backup_router) { + SilcServerConfigRouter *router; + router = silc_server_config_get_backup_router(server); + if (router && strcmp(server->config->server_info->primary->server_ip, + sock->ip) && + silc_server_find_socket_by_host(server, + SILC_SOCKET_TYPE_SERVER, + router->backup_replace_ip, 0)) { + SILC_LOG_INFO(("Will not accept connections because we do " + "not have backup router connection established")); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_PERM_DENIED, + "We do not have connection to backup " + "router established, try later"); + silc_free(sock->user_data); + server->stat.auth_failures++; + + /* From here on, wait 10 seconds for the backup router to appear. */ + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_router_wait, + (void *)server, 10, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + goto out; + } + } + SILC_LOG_DEBUG(("Remote host is %s", ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? "server" : (backup_router ? @@ -1673,30 +2040,37 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) server->stat.auth_failures++; goto out; } - - /* Statistics */ - if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) { - server->stat.my_servers++; - } else { - server->stat.my_routers++; - server->stat.routers++; - } - server->stat.servers++; + entry->data.status |= SILC_IDLIST_STATUS_LOCAL; id_entry = (void *)new_server; /* If the incoming connection is router and marked as backup router then add it to be one of our backups */ if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && backup_router) { - silc_server_backup_add(server, new_server, backup_replace_ip, - backup_replace_port, backup_local); - /* Change it back to SERVER type since that's what it really is. */ if (backup_local) ctx->conn_type = SILC_SOCKET_TYPE_SERVER; - new_server->server_type = SILC_BACKUP_ROUTER; + + SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE, + ("Backup router %s is now online", + sock->hostname)); + + /* Remove the backup waiting with timeout */ + silc_schedule_task_add(server->schedule, 0, + silc_server_backup_router_wait, + (void *)server, 5, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + } + + /* Statistics */ + if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) { + server->stat.my_servers++; + } else { + server->stat.my_routers++; + server->stat.routers++; } + server->stat.servers++; /* Check whether this connection is to be our primary router connection if we do not already have the primary route. */ @@ -1732,17 +2106,19 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) /* Connection has been fully established now. Everything is ok. */ SILC_LOG_DEBUG(("New connection authenticated")); - /* Perform keepalive. The `hb_context' will be freed automatically - when finally calling the silc_socket_free function. */ - hb_context = silc_calloc(1, sizeof(*hb_context)); - hb_context->server = server; - silc_socket_set_heartbeat(sock, hearbeat_timeout, hb_context, - silc_server_perform_heartbeat, - server->schedule); + /* Perform keepalive. */ + if (param->keepalive_secs) + silc_socket_set_heartbeat(sock, param->keepalive_secs, server, + silc_server_perform_heartbeat, + server->schedule); + + /* Perform Quality of Service */ + if (param->qos) + silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit, + param->qos_limit_sec, param->qos_limit_usec, + server->schedule); out: - silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); silc_protocol_free(protocol); if (ctx->packet) silc_packet_context_free(ctx->packet); @@ -1767,19 +2143,22 @@ SILC_TASK_CALLBACK(silc_server_packet_process) SilcCipher cipher = NULL; SilcHmac hmac = NULL; SilcUInt32 sequence = 0; + bool local_is_router; int ret; - if (!sock) + if (!sock) { + SILC_LOG_DEBUG(("Unknown socket connection")); return; - - SILC_LOG_DEBUG(("Processing packet")); + } /* Packet sending */ if (type == SILC_TASK_WRITE) { /* Do not send data to disconnected connection */ - if (SILC_IS_DISCONNECTED(sock)) + if (SILC_IS_DISCONNECTED(sock)) { + SILC_LOG_DEBUG(("Disconnected socket connection, cannot send")); return; + } server->stat.packets_sent++; @@ -1791,6 +2170,14 @@ SILC_TASK_CALLBACK(silc_server_packet_process) if (ret == -2) return; + /* The packet has been sent and now it is time to set the connection + back to only for input. When there is again some outgoing data + available for this connection it will be set for output as well. + This call clears the output setting and sets it only for input. */ + SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd); + SILC_UNSET_OUTBUF_PENDING(sock); + silc_buffer_clear(sock->outbuf); + if (ret == -1) { SILC_LOG_ERROR(("Error sending packet to connection " "%s:%d [%s]", sock->hostname, sock->port, @@ -1798,17 +2185,12 @@ SILC_TASK_CALLBACK(silc_server_packet_process) sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : "Router"))); - return; - } - /* The packet has been sent and now it is time to set the connection - back to only for input. When there is again some outgoing data - available for this connection it will be set for output as well. - This call clears the output setting and sets it only for input. */ - SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd); - SILC_UNSET_OUTBUF_PENDING(sock); - - silc_buffer_clear(sock->outbuf); + SILC_SET_DISCONNECTING(sock); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + silc_server_close_connection(server, sock); + } return; } @@ -1818,13 +2200,19 @@ SILC_TASK_CALLBACK(silc_server_packet_process) ret = silc_packet_receive(sock); if (ret < 0) { - if (ret == -1) + if (ret == -1) { SILC_LOG_ERROR(("Error receiving packet from connection " "%s:%d [%s] %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"), strerror(errno))); + + SILC_SET_DISCONNECTING(sock); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + silc_server_close_connection(server, sock); + } return; } @@ -1851,7 +2239,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process) else silc_server_free_sock_user_data(server, sock, NULL); } else if (server->router_conn && server->router_conn->sock == sock && - !server->router && server->standalone) + !server->router && server->standalone) silc_schedule_task_add(server->schedule, 0, silc_server_connect_to_router, server, 1, 0, @@ -1869,8 +2257,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process) return; } - server->stat.packets_received++; - /* Get keys and stuff from ID entry */ idata = (SilcIDListData)sock->user_data; if (idata) { @@ -1879,20 +2265,29 @@ SILC_TASK_CALLBACK(silc_server_packet_process) sequence = idata->psn_receive; } - /* Process the packet. This will call the parser that will then + /* Then, process the packet. This will call the parser that will then decrypt and parse the packet. */ - ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? - TRUE : FALSE, cipher, hmac, sequence, + + local_is_router = (server->server_type == SILC_ROUTER); + + /* If socket connection is our primary, we are backup and we are doing + backup resuming, we won't process the packet as being a router + (affects channel message decryption). */ + if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) && + SILC_PRIMARY_ROUTE(server) == sock) + local_is_router = FALSE; + + ret = silc_packet_receive_process(sock, local_is_router, + cipher, hmac, sequence, silc_server_packet_parse, server); - /* If this socket connection is not authenticated yet and the packet - processing failed we will drop the connection since it can be - a malicious flooder. */ - if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE && - (!sock->protocol || sock->protocol->protocol->type == - SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) { - SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock)); - SILC_SET_DISCONNECTING(sock); + /* If processing failed the connection is closed. */ + if (!ret) { + /* On packet processing errors we may close our primary router + connection but won't become primary router if we are the backup + since this is local error condition. */ + if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) + server->backup_noswitch = TRUE; if (sock->user_data) silc_server_free_sock_user_data(server, sock, NULL); @@ -1911,7 +2306,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) SilcIDListData idata = (SilcIDListData)sock->user_data; int ret; - SILC_LOG_DEBUG(("Start")); + server->stat.packets_received++; /* Parse the packet */ if (parse_ctx->normal) @@ -1920,23 +2315,27 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL); /* If entry is disabled ignore what we got. */ - if (ret != SILC_PACKET_RESUME_ROUTER && - idata && idata->status & SILC_IDLIST_STATUS_DISABLED) { + if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED && + ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER && + ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE) { SILC_LOG_DEBUG(("Connection is disabled")); goto out; } - if (ret == SILC_PACKET_NONE) + if (ret == SILC_PACKET_NONE) { + SILC_LOG_DEBUG(("Error parsing packet")); goto out; + } /* Check that the the current client ID is same as in the client's packet. */ if (sock->type == SILC_SOCKET_TYPE_CLIENT) { SilcClientEntry client = (SilcClientEntry)sock->user_data; - if (client && client->id) { + if (client && client->id && packet->src_id) { void *id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type); if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) { silc_free(id); + SILC_LOG_DEBUG(("Packet source is not same as sender")); goto out; } silc_free(id); @@ -1946,7 +2345,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) if (server->server_type == SILC_ROUTER) { /* Route the packet if it is not destined to us. Other ID types but server are handled separately after processing them. */ - if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) && + if (packet->dst_id && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) && packet->dst_id_type == SILC_ID_SERVER && sock->type != SILC_SOCKET_TYPE_CLIENT && memcmp(packet->dst_id, server->id_string, server->id_string_len)) { @@ -1968,19 +2367,17 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) /* Parse the incoming packet type */ silc_server_packet_parse_type(server, sock, packet); - if (server->server_type == SILC_ROUTER) { - /* Broadcast packet if it is marked as broadcast packet and it is - originated from router and we are router. */ - if (sock->type == SILC_SOCKET_TYPE_ROUTER && - packet->flags & SILC_PACKET_FLAG_BROADCAST && - !server->standalone) { - /* Broadcast to our primary route */ - silc_server_packet_broadcast(server, server->router->connection, packet); - - /* If we have backup routers then we need to feed all broadcast - data to those servers. */ - silc_server_backup_broadcast(server, sock, packet); - } + /* Broadcast packet if it is marked as broadcast packet and it is + originated from router and we are router. */ + if (server->server_type == SILC_ROUTER && + sock->type == SILC_SOCKET_TYPE_ROUTER && + packet->flags & SILC_PACKET_FLAG_BROADCAST) { + /* Broadcast to our primary route */ + silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet); + + /* If we have backup routers then we need to feed all broadcast + data to those servers. */ + silc_server_backup_broadcast(server, sock, packet); } out: @@ -1997,6 +2394,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context, SilcServer server = (SilcServer)context; SilcSocketConnection sock = parser_context->sock; SilcIDListData idata = (SilcIDListData)sock->user_data; + bool ret; if (idata) idata->psn_receive = parser_context->packet->sequence + 1; @@ -2010,21 +2408,36 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context, (sock->protocol && sock->protocol->protocol && (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE || sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY))) { - silc_server_packet_parse_real(server->schedule, 0, sock->sock, + silc_server_packet_parse_real(server->schedule, server, 0, sock->sock, parser_context); /* Reprocess data since we'll return FALSE here. This is because the idata->receive_key might have become valid in the last packet and we want to call this processor with valid cipher. */ if (idata) - silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? - TRUE : FALSE, idata->receive_key, + ret = silc_packet_receive_process( + sock, server->server_type == SILC_ROUTER, + idata->receive_key, idata->hmac_receive, idata->psn_receive, silc_server_packet_parse, server); else - silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? - TRUE : FALSE, NULL, NULL, 0, + ret = silc_packet_receive_process( + sock, server->server_type == SILC_ROUTER, + NULL, NULL, 0, silc_server_packet_parse, server); + + if (!ret) { + /* On packet processing errors we may close our primary router + connection but won't become primary router if we are the backup + since this is local error condition. */ + if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) + server->backup_noswitch = TRUE; + + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + silc_server_close_connection(server, sock); + } + return FALSE; } @@ -2041,7 +2454,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context, case SILC_SOCKET_TYPE_SERVER: case SILC_SOCKET_TYPE_ROUTER: /* Packets from servers are parsed immediately */ - silc_server_packet_parse_real(server->schedule, 0, sock->sock, + silc_server_packet_parse_real(server->schedule, server, 0, sock->sock, parser_context); break; default: @@ -2061,7 +2474,8 @@ void silc_server_packet_parse_type(SilcServer server, SilcPacketType type = packet->type; SilcIDListData idata = (SilcIDListData)sock->user_data; - SILC_LOG_DEBUG(("Parsing packet type %d", type)); + SILC_LOG_DEBUG(("Received %s packet [flags %d]", + silc_get_packet_name(type), packet->flags)); /* Parse the packet type */ switch (type) { @@ -2070,8 +2484,6 @@ void silc_server_packet_parse_type(SilcServer server, SilcStatus status; char *message = NULL; - SILC_LOG_DEBUG(("Disconnect packet")); - if (packet->flags & SILC_PACKET_FLAG_LIST) break; if (packet->buffer->len < 1) @@ -2083,11 +2495,16 @@ void silc_server_packet_parse_type(SilcServer server, message = silc_memdup(packet->buffer->data + 1, packet->buffer->len - 1); - SILC_LOG_ERROR(("Disconnected by %s (%s): %s (%d) %s", - sock->ip, sock->hostname, - silc_get_status_message(status), status, - message ? message : "")); + SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", + sock->ip, sock->hostname, + silc_get_status_message(status), status, + message ? message : "")); silc_free(message); + + /* Handle the disconnection from our end too */ + if (sock->user_data && SILC_IS_LOCAL(sock->user_data)) + silc_server_free_sock_user_data(server, sock, NULL); + silc_server_close_connection(server, sock); } break; @@ -2097,7 +2514,6 @@ void silc_server_packet_parse_type(SilcServer server, * one protocol for connection executing at once hence this * success message is for whatever protocol is executing currently. */ - SILC_LOG_DEBUG(("Success packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; if (sock->protocol) @@ -2110,24 +2526,15 @@ void silc_server_packet_parse_type(SilcServer server, * one protocol for connection executing at once hence this * failure message is for whatever protocol is executing currently. */ - SILC_LOG_DEBUG(("Failure packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; if (sock->protocol) { - SilcServerFailureContext f; - f = silc_calloc(1, sizeof(*f)); - f->server = server; - f->sock = sock; - - /* We will wait 5 seconds to process this failure packet */ - silc_schedule_task_add(server->schedule, sock->sock, - silc_server_failure_callback, (void *)f, 5, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE; + silc_protocol_execute(sock->protocol, server->schedule, 0, 0); } break; case SILC_PACKET_REJECT: - SILC_LOG_DEBUG(("Reject packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; return; @@ -2138,7 +2545,6 @@ void silc_server_packet_parse_type(SilcServer server, * Received notify packet. Server can receive notify packets from * router. Server then relays the notify messages to clients if needed. */ - SILC_LOG_DEBUG(("Notify packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) silc_server_notify_list(server, sock, packet); else @@ -2154,7 +2560,6 @@ void silc_server_packet_parse_type(SilcServer server, * (although probably most common ones) thus they are handled * specially. */ - SILC_LOG_DEBUG(("Channel Message packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; idata->last_receive = time(NULL); @@ -2168,7 +2573,6 @@ void silc_server_packet_parse_type(SilcServer server, * locally connected clients on the particular channel. Router * never receives this channel and thus is ignored. */ - SILC_LOG_DEBUG(("Channel Key packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_channel_key(server, sock, packet); @@ -2182,7 +2586,6 @@ void silc_server_packet_parse_type(SilcServer server, * Recived command. Processes the command request and allocates the * command context and calls the command. */ - SILC_LOG_DEBUG(("Command packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_command_process(server, sock, packet); @@ -2194,7 +2597,6 @@ void silc_server_packet_parse_type(SilcServer server, * may be reply to command sent by us or reply to command sent by client * that we've routed further. */ - SILC_LOG_DEBUG(("Command Reply packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_command_reply(server, sock, packet); @@ -2208,7 +2610,6 @@ void silc_server_packet_parse_type(SilcServer server, * Received private message packet. The packet is coming from either * client or server. */ - SILC_LOG_DEBUG(("Private Message packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; idata->last_receive = time(NULL); @@ -2228,7 +2629,6 @@ void silc_server_packet_parse_type(SilcServer server, * Key Exchange protocol packets */ case SILC_PACKET_KEY_EXCHANGE: - SILC_LOG_DEBUG(("KE packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; @@ -2248,7 +2648,6 @@ void silc_server_packet_parse_type(SilcServer server, break; case SILC_PACKET_KEY_EXCHANGE_1: - SILC_LOG_DEBUG(("KE 1 packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; @@ -2292,7 +2691,6 @@ void silc_server_packet_parse_type(SilcServer server, break; case SILC_PACKET_KEY_EXCHANGE_2: - SILC_LOG_DEBUG(("KE 2 packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; @@ -2342,7 +2740,6 @@ void silc_server_packet_parse_type(SilcServer server, * authentication method for the connection. This packet maybe received * at any time. */ - SILC_LOG_DEBUG(("Connection authentication request packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_connection_auth_request(server, sock, packet); @@ -2354,7 +2751,6 @@ void silc_server_packet_parse_type(SilcServer server, case SILC_PACKET_CONNECTION_AUTH: /* Start of the authentication protocol. We receive here the authentication data and will verify it. */ - SILC_LOG_DEBUG(("Connection auth packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; @@ -2381,7 +2777,6 @@ void silc_server_packet_parse_type(SilcServer server, * to distribute information about new registered entities in the * SILC network. */ - SILC_LOG_DEBUG(("New ID packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) silc_server_new_id_list(server, sock, packet); else @@ -2394,7 +2789,6 @@ void silc_server_packet_parse_type(SilcServer server, * we will use to create initial client ID. After creating new * ID we will send it to the client. */ - SILC_LOG_DEBUG(("New Client packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_new_client(server, sock, packet); @@ -2406,7 +2800,6 @@ void silc_server_packet_parse_type(SilcServer server, * information that we may save. This is received after server has * connected to us. */ - SILC_LOG_DEBUG(("New Server packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_new_server(server, sock, packet); @@ -2417,7 +2810,6 @@ void silc_server_packet_parse_type(SilcServer server, * Received new channel packet. Information about new channel in the * network are distributed using this packet. */ - SILC_LOG_DEBUG(("New Channel packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) silc_server_new_channel_list(server, sock, packet); else @@ -2428,7 +2820,6 @@ void silc_server_packet_parse_type(SilcServer server, /* * Received heartbeat. */ - SILC_LOG_DEBUG(("Heartbeat packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; break; @@ -2437,7 +2828,6 @@ void silc_server_packet_parse_type(SilcServer server, /* * Received heartbeat. */ - SILC_LOG_DEBUG(("Key agreement packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_key_agreement(server, sock, packet); @@ -2448,7 +2838,6 @@ void silc_server_packet_parse_type(SilcServer server, * Received re-key packet. The sender wants to regenerate the session * keys. */ - SILC_LOG_DEBUG(("Re-key packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_rekey(server, sock, packet); @@ -2458,7 +2847,6 @@ void silc_server_packet_parse_type(SilcServer server, /* * The re-key is done. */ - SILC_LOG_DEBUG(("Re-key done packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; @@ -2483,7 +2871,6 @@ void silc_server_packet_parse_type(SilcServer server, case SILC_PACKET_FTP: /* FTP packet */ - SILC_LOG_DEBUG(("FTP packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_ftp(server, sock, packet); @@ -2491,7 +2878,6 @@ void silc_server_packet_parse_type(SilcServer server, case SILC_PACKET_RESUME_CLIENT: /* Resume client */ - SILC_LOG_DEBUG(("Resume Client packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_resume_client(server, sock, packet); @@ -2500,7 +2886,6 @@ void silc_server_packet_parse_type(SilcServer server, case SILC_PACKET_RESUME_ROUTER: /* Resume router packet received. This packet is received for backup router resuming protocol. */ - SILC_LOG_DEBUG(("Resume router packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; silc_server_backup_resume_router(server, sock, packet); @@ -2510,7 +2895,6 @@ void silc_server_packet_parse_type(SilcServer server, SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type)); break; } - } /* Creates connection to a remote router. */ @@ -2522,7 +2906,6 @@ void silc_server_create_connection(SilcServer server, /* Allocate connection object for hold connection specific stuff. */ sconn = silc_calloc(1, sizeof(*sconn)); - sconn->server = server; sconn->remote_host = strdup(remote_host); sconn->remote_port = port; sconn->no_reconnect = TRUE; @@ -2535,7 +2918,7 @@ void silc_server_create_connection(SilcServer server, SILC_TASK_CALLBACK(silc_server_close_connection_final) { - silc_socket_free((SilcSocketConnection)context); + silc_socket_free(context); } /* Closes connection to socket connection */ @@ -2543,18 +2926,26 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final) void silc_server_close_connection(SilcServer server, SilcSocketConnection sock) { - if (!server->sockets[sock->sock]) + char tmp[128]; + + if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) { + silc_schedule_unset_listen_fd(server->schedule, sock->sock); + silc_schedule_task_del_by_fd(server->schedule, sock->sock); + silc_schedule_task_add(server->schedule, sock->sock, + silc_server_close_connection_final, + (void *)sock, 0, 1, SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); return; + } - SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname, + memset(tmp, 0, sizeof(tmp)); + silc_socket_get_error(sock, tmp, sizeof(tmp)); + SILC_LOG_INFO(("Closing connection %s:%d [%s] %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"))); - - /* We won't listen for this connection anymore */ - silc_schedule_unset_listen_fd(server->schedule, sock->sock); + "Router"), tmp[0] ? tmp : "")); /* Unregister all tasks */ silc_schedule_task_del_by_fd(server->schedule, sock->sock); @@ -2569,7 +2960,9 @@ void silc_server_close_connection(SilcServer server, if (!sock->user_data) { /* If any protocol is active cancel its execution. It will call the final callback which will finalize the disconnection. */ - if (sock->protocol) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) { + SILC_LOG_DEBUG(("Cancelling protocol, calling final callback")); silc_protocol_cancel(sock->protocol, server->schedule); sock->protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute_final(sock->protocol, server->schedule); @@ -2578,7 +2971,10 @@ void silc_server_close_connection(SilcServer server, } } - silc_schedule_task_add(server->schedule, 0, + /* We won't listen for this connection anymore */ + silc_schedule_unset_listen_fd(server->schedule, sock->sock); + + silc_schedule_task_add(server->schedule, sock->sock, silc_server_close_connection_final, (void *)sock, 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); @@ -2597,7 +2993,7 @@ void silc_server_disconnect_remote(SilcServer server, char *cp; int len; - if (!sock) + if (!sock || SILC_IS_DISCONNECTED(sock)) return; memset(buf, 0, sizeof(buf)); @@ -2638,18 +3034,15 @@ void silc_server_disconnect_remote(SilcServer server, silc_server_close_connection(server, sock); } -typedef struct { - SilcServer server; - SilcClientEntry client; -} *FreeClientInternal; - SILC_TASK_CALLBACK(silc_server_free_client_data_timeout) { - FreeClientInternal i = (FreeClientInternal)context; + SilcServer server = app_context; + SilcClientEntry client = context; + + assert(!silc_hash_table_count(client->channels)); - silc_idlist_del_data(i->client); - silc_idcache_purge_by_context(i->server->local_list->clients, i->client); - silc_free(i); + silc_idlist_del_data(client); + silc_idcache_purge_by_context(server->local_list->clients, client); } /* Frees client data and notifies about client's signoff. */ @@ -2660,7 +3053,7 @@ void silc_server_free_client_data(SilcServer server, int notify, const char *signoff) { - FreeClientInternal i = silc_calloc(1, sizeof(*i)); + SILC_LOG_DEBUG(("Freeing client data")); /* If there is pending outgoing data for the client then purge it to the network before removing the client entry. */ @@ -2673,23 +3066,23 @@ void silc_server_free_client_data(SilcServer server, SILC_NOTIFY_TYPE_SIGNOFF); /* Send SIGNOFF notify to routers. */ - if (notify && !server->standalone && server->router) - silc_server_send_notify_signoff(server, server->router->connection, - server->server_type == SILC_SERVER ? - FALSE : TRUE, client->id, signoff); - - /* Remove client from all channels */ if (notify) - silc_server_remove_from_channels(server, NULL, client, - TRUE, (char *)signoff, TRUE); - else - silc_server_remove_from_channels(server, NULL, client, - FALSE, NULL, FALSE); - - /* Remove this client from watcher list if it is */ - silc_server_del_from_watcher_list(server, client); + silc_server_send_notify_signoff(server, SILC_PRIMARY_ROUTE(server), + SILC_BROADCAST(server), client->id, + signoff); } + /* Remove client from all channels */ + if (notify) + silc_server_remove_from_channels(server, NULL, client, + TRUE, (char *)signoff, TRUE, FALSE); + else + silc_server_remove_from_channels(server, NULL, client, + FALSE, NULL, FALSE, FALSE); + + /* Remove this client from watcher list if it is */ + silc_server_del_from_watcher_list(server, client); + /* Update statistics */ server->stat.my_clients--; server->stat.clients--; @@ -2700,17 +3093,23 @@ void silc_server_free_client_data(SilcServer server, silc_schedule_task_del_by_context(server->schedule, client); /* We will not delete the client entry right away. We will take it - into history (for WHOWAS command) for 5 minutes */ - i->server = server; - i->client = client; - silc_schedule_task_add(server->schedule, 0, - silc_server_free_client_data_timeout, - (void *)i, 300, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); - client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; - client->mode = 0; - client->router = NULL; - client->connection = NULL; + into history (for WHOWAS command) for 5 minutes, unless we're + shutting down server. */ + if (!server->server_shutdown) { + silc_schedule_task_add(server->schedule, 0, + silc_server_free_client_data_timeout, + client, 300, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); + client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + client->data.status &= ~SILC_IDLIST_STATUS_LOCAL; + client->mode = 0; + client->router = NULL; + client->connection = NULL; + } else { + /* Delete directly since we're shutting down server */ + silc_idlist_del_data(client); + silc_idlist_del_client(server->local_list, client); + } } /* Frees user_data pointer from socket connection object. This also sends @@ -2721,8 +3120,6 @@ void silc_server_free_sock_user_data(SilcServer server, SilcSocketConnection sock, const char *signoff_message) { - SILC_LOG_DEBUG(("Start")); - switch (sock->type) { case SILC_SOCKET_TYPE_CLIENT: { @@ -2737,9 +3134,19 @@ void silc_server_free_sock_user_data(SilcServer server, SilcServerEntry user_data = (SilcServerEntry)sock->user_data; SilcServerEntry backup_router = NULL; + SILC_LOG_DEBUG(("Freeing server data")); + if (user_data->id) backup_router = silc_server_backup_get(server, user_data->id); + if (!server->backup_router && server->server_type == SILC_ROUTER && + backup_router == server->id_entry && + sock->type != SILC_SOCKET_TYPE_ROUTER) + backup_router = NULL; + + if (server->server_shutdown || server->backup_noswitch) + backup_router = NULL; + /* If this was our primary router connection then we're lost to the outside world. */ if (server->router == user_data) { @@ -2754,26 +3161,25 @@ void silc_server_free_sock_user_data(SilcServer server, server->id_entry->router = NULL; server->router = NULL; server->standalone = TRUE; + server->backup_primary = FALSE; backup_router = NULL; } else { - SILC_LOG_INFO(("New primary router is backup router %s", - backup_router->server_name)); - SILC_LOG_DEBUG(("New primary router is backup router %s", - backup_router->server_name)); -#ifdef BACKUP_SINGLE_ROUTER if (server->id_entry != backup_router) { -#endif /* BACKUP_SINGLE_ROUTER */ + SILC_LOG_INFO(("New primary router is backup router %s", + backup_router->server_name)); server->id_entry->router = backup_router; server->router = backup_router; server->router_connect = time(0); server->backup_primary = TRUE; -#ifdef BACKUP_SINGLE_ROUTER } else { + SILC_LOG_INFO(("We are now new primary router in this cell")); server->id_entry->router = NULL; server->router = NULL; server->standalone = TRUE; + + /* We stop here to take a breath */ + sleep(2); } -#endif /* BACKUP_SINGLE_ROUTER */ if (server->server_type == SILC_BACKUP_ROUTER) { server->server_type = SILC_ROUTER; @@ -2792,32 +3198,90 @@ void silc_server_free_sock_user_data(SilcServer server, } else if (backup_router) { SILC_LOG_INFO(("Enabling the use of backup router %s", backup_router->server_name)); - SILC_LOG_DEBUG(("Enabling the use of backup router %s", - backup_router->server_name)); /* Mark this connection as replaced */ silc_server_backup_replaced_add(server, user_data->id, backup_router); + } else if (server->server_type == SILC_SERVER && + sock->type == SILC_SOCKET_TYPE_ROUTER) { + /* Reconnect to the router (backup) */ + silc_schedule_task_add(server->schedule, 0, + silc_server_connect_to_router, + server, 1, 0, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); } + SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE, + ("Server %s signoff", user_data->server_name)); + if (!backup_router) { - /* Free all client entries that this server owns as they will - become invalid now as well. */ - if (user_data->id) - silc_server_remove_clients_by_server(server, user_data, TRUE); + /* Remove all servers that are originated from this server, and + remove the clients of those servers too. */ + silc_server_remove_servers_by_server(server, user_data, TRUE); + +#if 0 + /* Remove the clients that this server owns as they will become + invalid now too. For backup router the server is actually + coming from the primary router, so mark that as the owner + of this entry. */ + if (server->server_type == SILC_BACKUP_ROUTER && + sock->type == SILC_SOCKET_TYPE_SERVER) + silc_server_remove_clients_by_server(server, server->router, + user_data, TRUE); + else +#endif + silc_server_remove_clients_by_server(server, user_data, + user_data, TRUE); + + /* Remove channels owned by this server */ if (server->server_type == SILC_SERVER) silc_server_remove_channels_by_server(server, user_data); } else { + /* Enable local server connections that may be disabled */ + silc_server_local_servers_toggle_enabled(server, TRUE); + /* Update the client entries of this server to the new backup - router. This also removes the clients that *really* was owned - by the primary router and went down with the router. */ - silc_server_update_clients_by_server(server, user_data, backup_router, - TRUE, TRUE); + router. If we are the backup router we also resolve the real + servers for the clients. After updating is over this also + removes the clients that this server explicitly owns. */ + silc_server_update_clients_by_server(server, user_data, + backup_router, TRUE); + + /* If we are router and just lost our primary router (now standlaone) + we remove everything that was behind it, since we don't know + any better. */ + if (server->server_type == SILC_ROUTER && server->standalone) + /* Remove all servers that are originated from this server, and + remove the clients of those servers too. */ + silc_server_remove_servers_by_server(server, user_data, TRUE); + + /* Finally remove the clients that are explicitly owned by this + server. They go down with the server. */ + silc_server_remove_clients_by_server(server, user_data, + user_data, TRUE); + + /* Update our server cache to use the new backup router too. */ silc_server_update_servers_by_server(server, user_data, backup_router); if (server->server_type == SILC_SERVER) silc_server_update_channels_by_server(server, user_data, backup_router); + + /* Send notify about primary router going down to local operators */ + if (server->backup_router) + SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, + SILC_NOTIFY_TYPE_NONE, + ("%s switched to backup router %s " + "(we are primary router now)", + server->server_name, server->server_name)); + else if (server->router) + SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, + SILC_NOTIFY_TYPE_NONE, + ("%s switched to backup router %s", + server->server_name, + server->router->server_name)); } + server->backup_noswitch = FALSE; /* Free the server entry */ silc_server_backup_del(server, user_data); @@ -2835,7 +3299,7 @@ void silc_server_free_sock_user_data(SilcServer server, if (server->server_type == SILC_ROUTER) server->stat.cell_servers--; - if (backup_router) { + if (backup_router && backup_router != server->id_entry) { /* Announce all of our stuff that was created about 5 minutes ago. The backup router knows all the other stuff already. */ if (server->server_type == SILC_ROUTER) @@ -2854,6 +3318,8 @@ void silc_server_free_sock_user_data(SilcServer server, { SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data; + SILC_LOG_DEBUG(("Freeing unknown connection data")); + silc_idlist_del_data(user_data); silc_free(user_data); break; @@ -2861,7 +3327,9 @@ void silc_server_free_sock_user_data(SilcServer server, } /* If any protocol is active cancel its execution */ - if (sock->protocol) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) { + SILC_LOG_DEBUG(("Cancelling protocol, calling final callback")); silc_protocol_cancel(sock->protocol, server->schedule); sock->protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute_final(sock->protocol, server->schedule); @@ -2880,22 +3348,28 @@ void silc_server_remove_from_channels(SilcServer server, SilcClientEntry client, bool notify, const char *signoff_message, - bool keygen) + bool keygen, + bool killed) { SilcChannelEntry channel; SilcChannelClientEntry chl; SilcHashTableList htl; - SilcBuffer clidp; + SilcBuffer clidp = NULL; - SILC_LOG_DEBUG(("Start")); - - if (!client || !client->id) + if (!client) return; - clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); - if (!clidp) + SILC_LOG_DEBUG(("Removing client from joined channels")); + + if (notify && !client->id) notify = FALSE; + if (notify) { + clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); + if (!clidp) + notify = FALSE; + } + /* Remove the client from all channels. The client is removed from the channels' user list. */ silc_hash_table_list(client->channels, &htl); @@ -2904,26 +3378,27 @@ void silc_server_remove_from_channels(SilcServer server, /* Remove channel if this is last client leaving the channel, unless the channel is permanent. */ - if (server->server_type == SILC_ROUTER && + if (server->server_type != SILC_SERVER && silc_hash_table_count(channel->user_list) < 2) { silc_server_channel_delete(server, channel); continue; } silc_hash_table_del(client->channels, channel); - silc_hash_table_del(channel->user_list, chl->client); + silc_hash_table_del(channel->user_list, client); channel->user_count--; /* If there is no global users on the channel anymore mark the channel as local channel. Do not check if the removed client is local client. */ - if (server->server_type != SILC_ROUTER && channel->global_users && + if (server->server_type == SILC_SERVER && channel->global_users && chl->client->router && !silc_server_channel_has_global(channel)) channel->global_users = FALSE; + memset(chl, 'A', sizeof(*chl)); silc_free(chl); /* Update statistics */ - if (client->connection) + if (SILC_IS_LOCAL(client)) server->stat.my_chanclients--; if (server->server_type == SILC_ROUTER) { server->stat.cell_chanclients--; @@ -2933,7 +3408,7 @@ void silc_server_remove_from_channels(SilcServer server, /* If there is not at least one local user on the channel then we don't need the channel entry anymore, we can remove it safely, unless the channel is permanent channel */ - if (server->server_type != SILC_ROUTER && + if (server->server_type == SILC_SERVER && !silc_server_channel_has_local(channel)) { /* Notify about leaving client if this channel has global users. */ if (notify && channel->global_users) @@ -2958,6 +3433,25 @@ void silc_server_remove_from_channels(SilcServer server, signoff_message, signoff_message ? strlen(signoff_message) : 0); + if (killed && clidp) { + /* Remove the client from channel's invite list */ + if (channel->invite_list && + silc_hash_table_count(channel->invite_list)) { + SilcBuffer ab; + SilcArgumentPayload iargs; + ab = silc_argument_payload_encode_one(NULL, clidp->data, + clidp->len, 3); + iargs = silc_argument_payload_parse(ab->data, ab->len, 1); + silc_server_inviteban_process(server, channel->invite_list, 1, iargs); + silc_buffer_free(ab); + silc_argument_payload_free(iargs); + } + } + + /* Don't create keys if we are shutting down */ + if (server->server_shutdown) + continue; + /* Re-generate channel key if needed */ if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) { if (!silc_server_create_channel_key(server, channel, 0)) @@ -2972,7 +3466,8 @@ void silc_server_remove_from_channels(SilcServer server, } silc_hash_table_list_reset(&htl); - silc_buffer_free(clidp); + if (clidp) + silc_buffer_free(clidp); } /* Removes client from one channel. This is used for example when client @@ -3001,26 +3496,27 @@ bool silc_server_remove_from_one_channel(SilcServer server, /* Remove channel if this is last client leaving the channel, unless the channel is permanent. */ - if (server->server_type == SILC_ROUTER && + if (server->server_type != SILC_SERVER && silc_hash_table_count(channel->user_list) < 2) { silc_server_channel_delete(server, channel); return FALSE; } - silc_hash_table_del(client->channels, chl->channel); - silc_hash_table_del(channel->user_list, chl->client); + silc_hash_table_del(client->channels, channel); + silc_hash_table_del(channel->user_list, client); channel->user_count--; /* If there is no global users on the channel anymore mark the channel as local channel. Do not check if the client is local client. */ - if (server->server_type != SILC_ROUTER && channel->global_users && + if (server->server_type == SILC_SERVER && channel->global_users && chl->client->router && !silc_server_channel_has_global(channel)) channel->global_users = FALSE; + memset(chl, 'O', sizeof(*chl)); silc_free(chl); /* Update statistics */ - if (client->connection) + if (SILC_IS_LOCAL(client)) server->stat.my_chanclients--; if (server->server_type == SILC_ROUTER) { server->stat.cell_chanclients--; @@ -3034,7 +3530,7 @@ bool silc_server_remove_from_one_channel(SilcServer server, /* If there is not at least one local user on the channel then we don't need the channel entry anymore, we can remove it safely, unless the channel is permanent channel */ - if (server->server_type != SILC_ROUTER && + if (server->server_type == SILC_SERVER && !silc_server_channel_has_local(channel)) { /* Notify about leaving client if this channel has global users. */ if (notify && channel->global_users) @@ -3078,7 +3574,8 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote) /* If we have protocol active we must assure that we call the protocol's final callback so that all the memory is freed. */ - if (sock->protocol) { + if (sock->protocol && sock->protocol->protocol && + sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) { protocol = sock->protocol->protocol->type; silc_protocol_cancel(sock->protocol, server->schedule); sock->protocol->state = SILC_PROTOCOL_STATE_ERROR; @@ -3087,15 +3584,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote) return; } - if (sock->user_data) - silc_server_free_sock_user_data(server, sock, NULL); - silc_server_disconnect_remote(server, sock, protocol == SILC_PROTOCOL_SERVER_CONNECTION_AUTH ? SILC_STATUS_ERR_AUTH_FAILED : SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, "Connection timeout"); + + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); } /* Creates new channel. Sends NEW_CHANNEL packet to primary route. This @@ -3115,7 +3612,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, SilcCipher key; SilcHmac newhmac; - SILC_LOG_DEBUG(("Creating new channel")); + SILC_LOG_DEBUG(("Creating new channel %s", channel_name)); if (!cipher) cipher = SILC_DEFAULT_CIPHER; @@ -3167,8 +3664,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server, /* Notify other routers about the new channel. We send the packet to our primary route. */ - if (broadcast && server->standalone == FALSE) - silc_server_send_new_channel(server, server->router->connection, TRUE, + if (broadcast) + silc_server_send_new_channel(server, SILC_PRIMARY_ROUTE(server), TRUE, channel_name, entry->id, silc_id_get_len(entry->id, SILC_ID_CHANNEL), entry->mode); @@ -3213,7 +3710,7 @@ silc_server_create_new_channel_with_id(SilcServer server, SilcCipher key; SilcHmac newhmac; - SILC_LOG_DEBUG(("Creating new channel")); + SILC_LOG_DEBUG(("Creating new channel %s", channel_name)); if (!cipher) cipher = SILC_DEFAULT_CIPHER; @@ -3252,8 +3749,8 @@ silc_server_create_new_channel_with_id(SilcServer server, /* Notify other routers about the new channel. We send the packet to our primary route. */ - if (broadcast && server->standalone == FALSE) - silc_server_send_new_channel(server, server->router->connection, TRUE, + if (broadcast) + silc_server_send_new_channel(server, SILC_PRIMARY_ROUTE(server), TRUE, channel_name, entry->id, silc_id_get_len(entry->id, SILC_ID_CHANNEL), entry->mode); @@ -3288,11 +3785,15 @@ silc_server_create_new_channel_with_id(SilcServer server, SILC_TASK_CALLBACK(silc_server_channel_key_rekey) { + SilcServer server = app_context; SilcServerChannelRekey rekey = (SilcServerChannelRekey)context; - SilcServer server = (SilcServer)rekey->context; rekey->task = NULL; + /* Return now if we are shutting down */ + if (server->server_shutdown) + return; + if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len)) return; @@ -3311,13 +3812,13 @@ bool silc_server_create_channel_key(SilcServer server, unsigned char channel_key[32], hash[32]; SilcUInt32 len; - SILC_LOG_DEBUG(("Generating channel key")); - if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) { SILC_LOG_DEBUG(("Channel has private keys, will not generate new key")); return TRUE; } + SILC_LOG_DEBUG(("Generating channel %s key", channel->channel_name)); + if (!channel->channel_key) if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) { channel->channel_key = NULL; @@ -3359,7 +3860,6 @@ bool silc_server_create_channel_key(SilcServer server, if (server->server_type == SILC_ROUTER) { if (!channel->rekey) channel->rekey = silc_calloc(1, sizeof(*channel->rekey)); - channel->rekey->context = (void *)server; channel->rekey->channel = channel; channel->rekey->key_len = key_len; if (channel->rekey->task) @@ -3391,8 +3891,6 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, SilcUInt32 tmp_len; char *cipher; - SILC_LOG_DEBUG(("Start")); - /* Decode channel key payload */ payload = silc_channel_key_payload_parse(key_payload->data, key_payload->len); @@ -3417,13 +3915,16 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, if (!channel) { channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL); if (!channel) { - SILC_LOG_ERROR(("Received key for non-existent channel %s", - silc_id_render(id, SILC_ID_CHANNEL))); + if (server->server_type == SILC_ROUTER) + SILC_LOG_ERROR(("Received key for non-existent channel %s", + silc_id_render(id, SILC_ID_CHANNEL))); goto out; } } } + SILC_LOG_DEBUG(("Saving new channel %s key", channel->channel_name)); + tmp = silc_channel_key_get_key(payload, &tmp_len); if (!tmp) { channel = NULL; @@ -3472,7 +3973,6 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, if (server->server_type == SILC_ROUTER) { if (!channel->rekey) channel->rekey = silc_calloc(1, sizeof(*channel->rekey)); - channel->rekey->context = (void *)server; channel->rekey->channel = channel; if (channel->rekey->task) silc_schedule_task_del(server->schedule, channel->rekey->task); @@ -3501,12 +4001,13 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, void silc_server_perform_heartbeat(SilcSocketConnection sock, void *hb_context) { - SilcServerHBContext hb = (SilcServerHBContext)hb_context; + SilcServer server = hb_context; - SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip)); + SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname, + sock->port, sock->ip)); /* Send the heartbeat */ - silc_server_send_heartbeat(hb->server, sock); + silc_server_send_heartbeat(server, sock); } /* Returns assembled of all servers in the given ID list. The packet's @@ -3636,6 +4137,12 @@ static void silc_server_announce_get_clients(SilcServer server, break; continue; } + if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) && + !client->connection && !client->router && !SILC_IS_LOCAL(client)) { + if (!silc_idcache_list_next(list, &id_cache)) + break; + continue; + } idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); @@ -3648,9 +4155,10 @@ static void silc_server_announce_get_clients(SilcServer server, silc_buffer_pull(*clients, idp->len); SILC_PUT32_MSB(client->mode, mode); - tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE, - 2, idp->data, idp->len, - mode, 4); + tmp = + silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE, + 2, idp->data, idp->len, + mode, 4); *umodes = silc_buffer_realloc(*umodes, (*umodes ? (*umodes)->truelen + tmp->len : @@ -3748,10 +4256,9 @@ void silc_server_announce_get_channel_users(SilcServer server, SilcChannelClientEntry chl; SilcHashTableList htl; SilcBuffer chidp, clidp, csidp; - SilcBuffer tmp; + SilcBuffer tmp, fkey = NULL; int len; - unsigned char mode[4], *fkey = NULL; - SilcUInt32 fkey_len = 0; + unsigned char mode[4]; char *hmac; SILC_LOG_DEBUG(("Start")); @@ -3763,7 +4270,7 @@ void silc_server_announce_get_channel_users(SilcServer server, SILC_PUT32_MSB(channel->mode, mode); hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL; if (channel->founder_key) - fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(channel->founder_key); tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE, 6, csidp->data, csidp->len, @@ -3773,7 +4280,8 @@ void silc_server_announce_get_channel_users(SilcServer server, channel->passphrase, channel->passphrase ? strlen(channel->passphrase) : 0, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); len = tmp->len; *channel_modes = silc_buffer_realloc(*channel_modes, @@ -3785,9 +4293,8 @@ void silc_server_announce_get_channel_users(SilcServer server, silc_buffer_put(*channel_modes, tmp->data, tmp->len); silc_buffer_pull(*channel_modes, len); silc_buffer_free(tmp); - silc_free(fkey); + silc_buffer_free(fkey); fkey = NULL; - fkey_len = 0; /* Now find all users on the channel */ silc_hash_table_list(channel->user_list, &htl); @@ -3814,12 +4321,13 @@ void silc_server_announce_get_channel_users(SilcServer server, /* CUMODE notify for mode change on the channel */ SILC_PUT32_MSB(chl->mode, mode); if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key) - fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len); + fkey = silc_pkcs_public_key_payload_encode(channel->founder_key); tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4, csidp->data, csidp->len, mode, sizeof(mode), clidp->data, clidp->len, - fkey, fkey_len); + fkey ? fkey->data : NULL, + fkey ? fkey->len : 0); len = tmp->len; *channel_users_modes = silc_buffer_realloc(*channel_users_modes, @@ -3832,9 +4340,8 @@ void silc_server_announce_get_channel_users(SilcServer server, silc_buffer_put(*channel_users_modes, tmp->data, tmp->len); silc_buffer_pull(*channel_users_modes, len); silc_buffer_free(tmp); - silc_free(fkey); + silc_buffer_free(fkey); fkey = NULL; - fkey_len = 0; silc_buffer_free(clidp); } silc_hash_table_list_reset(&htl); @@ -3903,36 +4410,45 @@ void silc_server_announce_get_channels(SilcServer server, silc_buffer_pull(*channels, len); } - /* Channel user modes */ - *channel_users_modes = silc_realloc(*channel_users_modes, - sizeof(**channel_users_modes) * - (i + 1)); - (*channel_users_modes)[i] = NULL; - *channel_modes = silc_realloc(*channel_modes, - sizeof(**channel_modes) * (i + 1)); - (*channel_modes)[i] = NULL; - *channel_ids = silc_realloc(*channel_ids, - sizeof(**channel_ids) * (i + 1)); - (*channel_ids)[i] = NULL; - silc_server_announce_get_channel_users(server, channel, - &(*channel_modes)[i], - channel_users, - &(*channel_users_modes)[i]); - (*channel_ids)[i] = channel->id; - - /* Channel's topic */ - *channel_topics = silc_realloc(*channel_topics, - sizeof(**channel_topics) * (i + 1)); - (*channel_topics)[i] = NULL; - silc_server_announce_get_channel_topic(server, channel, - &(*channel_topics)[i]); - i++; + if (creation_time && channel->updated < creation_time) + announce = FALSE; + else + announce = TRUE; + + if (announce) { + /* Channel user modes */ + *channel_users_modes = silc_realloc(*channel_users_modes, + sizeof(**channel_users_modes) * + (i + 1)); + (*channel_users_modes)[i] = NULL; + *channel_modes = silc_realloc(*channel_modes, + sizeof(**channel_modes) * (i + 1)); + (*channel_modes)[i] = NULL; + *channel_ids = silc_realloc(*channel_ids, + sizeof(**channel_ids) * (i + 1)); + (*channel_ids)[i] = NULL; + silc_server_announce_get_channel_users(server, channel, + &(*channel_modes)[i], + channel_users, + &(*channel_users_modes)[i]); + (*channel_ids)[i] = channel->id; + + /* Channel's topic */ + *channel_topics = silc_realloc(*channel_topics, + sizeof(**channel_topics) * (i + 1)); + (*channel_topics)[i] = NULL; + silc_server_announce_get_channel_topic(server, channel, + &(*channel_topics)[i]); + (*channel_users_modes_c)++; + + silc_free(cid); + + i++; + } if (!silc_idcache_list_next(list, &id_cache)) break; } - - *channel_users_modes_c += i; } silc_idcache_list_free(list); @@ -3990,6 +4506,20 @@ void silc_server_announce_channels(SilcServer server, silc_buffer_free(channels); } + if (channel_users) { + silc_buffer_push(channel_users, channel_users->data - channel_users->head); + SILC_LOG_HEXDUMP(("channel users"), channel_users->data, + channel_users->len); + + /* Send the packet */ + silc_server_packet_send(server, remote, + SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, + channel_users->data, channel_users->len, + FALSE); + + silc_buffer_free(channel_users); + } + if (channel_modes) { int i; @@ -4012,20 +4542,6 @@ void silc_server_announce_channels(SilcServer server, silc_free(channel_modes); } - if (channel_users) { - silc_buffer_push(channel_users, channel_users->data - channel_users->head); - SILC_LOG_HEXDUMP(("channel users"), channel_users->data, - channel_users->len); - - /* Send the packet */ - silc_server_packet_send(server, remote, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - channel_users->data, channel_users->len, - FALSE); - - silc_buffer_free(channel_users); - } - if (channel_users_modes) { int i; @@ -4074,25 +4590,6 @@ void silc_server_announce_channels(SilcServer server, silc_free(channel_ids); } -/* Failure timeout callback. If this is called then we will immediately - process the received failure. We always process the failure with timeout - since we do not want to blindly trust to received failure packets. - This won't be called (the timeout is cancelled) if the failure was - bogus (it is bogus if remote does not close the connection after sending - the failure). */ - -SILC_TASK_CALLBACK(silc_server_failure_callback) -{ - SilcServerFailureContext f = (SilcServerFailureContext)context; - - if (f->sock->protocol) { - f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE; - silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0); - } - - silc_free(f); -} - /* Assembles user list and users mode list from the `channel'. */ bool silc_server_get_users_on_channel(SilcServer server, @@ -4165,9 +4662,9 @@ void silc_server_save_users_on_channel(SilcServer server, SilcClientEntry client; SilcIDCacheEntry cache; SilcChannelClientEntry chl; - bool global; - SILC_LOG_DEBUG(("Start")); + SILC_LOG_DEBUG(("Saving %d users on %s channel", user_count, + channel->channel_name)); for (i = 0; i < user_count; i++) { /* Client ID */ @@ -4187,21 +4684,19 @@ void silc_server_save_users_on_channel(SilcServer server, continue; } - global = FALSE; + cache = NULL; /* Check if we have this client cached already. */ client = silc_idlist_find_client_by_id(server->local_list, client_id, server->server_type, &cache); - if (!client) { + if (!client) client = silc_idlist_find_client_by_id(server->global_list, client_id, server->server_type, &cache); - global = TRUE; - } if (!client) { /* If router did not find such Client ID in its lists then this must be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) { + if (server->server_type != SILC_SERVER) { silc_free(client_id); continue; } @@ -4219,15 +4714,18 @@ void silc_server_save_users_on_channel(SilcServer server, } client->data.status |= SILC_IDLIST_STATUS_REGISTERED; - } else { - /* Found, if it is from global list we'll assure that we won't - expire it now that the entry is on channel. */ - if (global) - cache->expire = 0; } + if (cache) + cache->expire = 0; silc_free(client_id); + if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) { + SILC_LOG_ERROR(("Attempting to add unregistered client to channel ", + "%s", channel->channel_name)); + continue; + } + if (!silc_server_client_on_channel(client, channel, &chl)) { /* Client was not on the channel, add it. */ chl = silc_calloc(1, sizeof(*chl)); @@ -4265,7 +4763,8 @@ void silc_server_save_user_channels(SilcServer server, char *name; int i = 0; - if (!channels ||!channels_user_modes) + if (!channels || !channels_user_modes || + !(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) goto out; ch = silc_channel_payload_parse_list(channels->data, channels->len); @@ -4414,7 +4913,7 @@ silc_server_get_client_route(SilcServer server, silc_free(id); if (idata) *idata = (SilcIDListData)server->router; - return server->router->connection; + return SILC_PRIMARY_ROUTE(server); } /* We are router and we will perform route lookup for the destination @@ -4510,74 +5009,17 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, return buffer; } -/* Finds client entry by Client ID and if it is not found then resolves - it using WHOIS command. */ - -SilcClientEntry silc_server_get_client_resolve(SilcServer server, - SilcClientID *client_id, - bool always_resolve, - bool *resolved) -{ - SilcClientEntry client; - - if (resolved) - *resolved = FALSE; - - client = silc_idlist_find_client_by_id(server->local_list, client_id, - TRUE, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, - client_id, TRUE, NULL); - if (!client && server->server_type == SILC_ROUTER) - return NULL; - } - - if (!client && server->standalone) - return NULL; - - if (!client || !client->nickname || !client->username || - always_resolve) { - SilcBuffer buffer, idp; - - if (client) { - client->data.status |= SILC_IDLIST_STATUS_RESOLVING; - client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED; - client->resolve_cmd_ident = ++server->cmd_ident; - } - - idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT); - buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, - server->cmd_ident, 1, - 4, idp->data, idp->len); - silc_server_packet_send(server, client ? client->router->connection : - server->router->connection, - SILC_PACKET_COMMAND, 0, - buffer->data, buffer->len, FALSE); - silc_buffer_free(idp); - silc_buffer_free(buffer); - - if (resolved) - *resolved = TRUE; - - return NULL; - } - - return client; -} - /* A timeout callback for the re-key. We will be the initiator of the re-key protocol. */ -SILC_TASK_CALLBACK(silc_server_rekey_callback) +SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback) { + SilcServer server = app_context; SilcSocketConnection sock = (SilcSocketConnection)context; SilcIDListData idata = (SilcIDListData)sock->user_data; - SilcServer server = (SilcServer)idata->rekey->context; SilcProtocol protocol; SilcServerRekeyInternalContext *proto_ctx; - SILC_LOG_DEBUG(("Start")); - /* Allocate internal protocol context. This is sent as context to the protocol. */ proto_ctx = silc_calloc(1, sizeof(*proto_ctx)); @@ -4595,6 +5037,8 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback) /* Run the protocol */ silc_protocol_execute(protocol, server->schedule, 0, 0); + SILC_LOG_DEBUG(("Rekey protocol completed")); + /* Re-register re-key timeout */ silc_schedule_task_add(server->schedule, sock->sock, silc_server_rekey_callback, @@ -4618,7 +5062,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final) if (protocol->state == SILC_PROTOCOL_STATE_ERROR || protocol->state == SILC_PROTOCOL_STATE_FAILURE) { /* Error occured during protocol */ - SILC_LOG_ERROR(("Error occurred during rekey protocol")); + SILC_LOG_ERROR(("Error occurred during rekey protocol with + %s (%s)", sock->hostname, sock->ip)); silc_protocol_cancel(protocol, server->schedule); silc_protocol_free(protocol); sock->protocol = NULL; @@ -4659,7 +5104,7 @@ SILC_TASK_CALLBACK(silc_server_get_stats) packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, ++server->cmd_ident, 1, 1, idp->data, idp->len); - silc_server_packet_send(server, server->router->connection, + silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), SILC_PACKET_COMMAND, 0, packet->data, packet->len, FALSE); silc_buffer_free(packet);