X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fserver.c;h=c3359196fe887f7dfc30da1aeed9c6a8b751f15c;hp=1f0decd988d48674127eafcbbc12c97aba04cb7d;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=f69221d0cfcfc146f762c495c590e6c701c68c38 diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 1f0decd9..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 @@ -31,7 +30,6 @@ 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); @@ -43,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 @@ -78,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); @@ -107,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); @@ -138,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; } @@ -189,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; @@ -222,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 */ @@ -257,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; @@ -279,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); @@ -411,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); @@ -459,7 +517,7 @@ SILC_TASK_CALLBACK(silc_server_rehash_close_connection) if (!sock) return; - SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured", + 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" : @@ -555,14 +613,15 @@ bool silc_server_rehash(SilcServer server) /* Check whether new config has this one too */ for (newptr = newconfig->routers; newptr; newptr = newptr->next) { - if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port && + if (silc_string_compare(newptr->host, ptr->host) && + newptr->port == ptr->port && newptr->initiator == ptr->initiator) { found = TRUE; break; } } - if (!found) { + if (!found && ptr->host) { /* Remove this connection */ SilcSocketConnection sock; sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER, @@ -586,13 +645,13 @@ bool silc_server_rehash(SilcServer server) /* Check whether new config has this one too */ for (newptr = newconfig->servers; newptr; newptr = newptr->next) { - if (!strcmp(newptr->host, ptr->host)) { + if (silc_string_compare(newptr->host, ptr->host)) { found = TRUE; break; } } - if (!found) { + if (!found && ptr->host) { /* Remove this connection */ SilcSocketConnection sock; sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER, @@ -606,6 +665,36 @@ bool silc_server_rehash(SilcServer server) } } + 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, @@ -663,7 +752,7 @@ 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; @@ -675,7 +764,8 @@ void silc_server_stop(SilcServer server) if (!server->sockets[i]) continue; if (!SILC_IS_LISTENER(server->sockets[i])) { - SilcIDListData idata = server->sockets[i]->user_data; + SilcSocketConnection sock = server->sockets[i]; + SilcIDListData idata = sock->user_data; if (idata) idata->status &= ~SILC_IDLIST_STATUS_DISABLED; @@ -685,6 +775,10 @@ void silc_server_stop(SilcServer server) 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; @@ -792,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 */ @@ -839,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)); @@ -875,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; } @@ -889,12 +1004,16 @@ 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; + /* Don't connect if we are shutting down. */ + if (server->server_shutdown) + return; + SILC_LOG_DEBUG(("We are %s", (server->server_type == SILC_SERVER ? "normal server" : server->server_type == SILC_ROUTER ? @@ -941,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; @@ -989,8 +1107,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) silc_ske_free(ctx->ske); silc_free(ctx->dest_id); 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); @@ -1034,8 +1150,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) silc_ske_free(ctx->ske); silc_free(ctx->dest_id); 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); @@ -1110,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; @@ -1159,7 +1271,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) SilcSocketConnection sock = ctx->sock; SilcServerEntry id_entry = NULL; SilcBuffer packet; - SilcServerHBContext hb_context; unsigned char *id_string; SilcUInt32 id_len; SilcIDListData idata; @@ -1261,17 +1372,13 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) 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, @@ -1280,6 +1387,7 @@ 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; @@ -1298,7 +1406,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) /* 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); + silc_server_backup_add(server, server->id_entry, sock->ip, + sconn->remote_port, TRUE); } } else { /* Add this server to be our backup router */ @@ -1311,7 +1420,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) 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); /* Free the temporary connection data context */ @@ -1356,8 +1465,6 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock, SilcServerConfigDeny *deny; int port; - context = (void *)server; - /* Check whether we could resolve both IP and FQDN. */ if (!sock->ip || (!strcmp(sock->ip, sock->hostname) && server->config->require_reverse_lookup)) { @@ -1378,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, @@ -1557,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); @@ -1590,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++; @@ -1660,10 +1764,9 @@ 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; + SilcServerConfigConnParams *param = &server->config->param; if (protocol->state == SILC_PROTOCOL_STATE_ERROR || protocol->state == SILC_PROTOCOL_STATE_FAILURE) { @@ -1680,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++; @@ -1760,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; @@ -1809,8 +1924,18 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) 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; @@ -1833,8 +1958,18 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) } 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; @@ -1917,6 +2052,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) 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, @@ -1967,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); @@ -2002,6 +2143,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process) SilcCipher cipher = NULL; SilcHmac hmac = NULL; SilcUInt32 sequence = 0; + bool local_is_router; int ret; if (!sock) { @@ -2028,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, @@ -2035,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; } @@ -2055,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; } @@ -2088,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, @@ -2114,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); @@ -2155,13 +2315,9 @@ 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) { - SILC_LOG_DEBUG(("Connection is disabled")); - goto out; - } - if (ret != SILC_PACKET_HEARTBEAT && - 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; } @@ -2238,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; @@ -2251,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; } @@ -2282,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: @@ -2357,15 +2529,8 @@ void silc_server_packet_parse_type(SilcServer server, 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; @@ -2741,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; @@ -2762,23 +2926,26 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final) void silc_server_close_connection(SilcServer server, SilcSocketConnection sock) { + char tmp[128]; + if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) { - silc_schedule_task_add(server->schedule, 0, + 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); @@ -2793,7 +2960,8 @@ 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; @@ -2803,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); @@ -2822,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)); @@ -2863,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. */ @@ -2885,20 +3053,8 @@ 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 1 - if (!client->router && !client->connection && - !(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) { - SILC_LOG_ERROR(("****** freeing data for already unregistered client -s")); - SILC_LOG_ERROR(("****** Contact Pekka")); - SILC_LOG_ERROR(("****** freeing data for already unregistered client -e")); - return; - } -#endif - /* If there is pending outgoing data for the client then purge it to the network before removing the client entry. */ silc_server_packet_queue_purge(server, sock); @@ -2919,10 +3075,10 @@ void silc_server_free_client_data(SilcServer server, /* Remove client from all channels */ if (notify) silc_server_remove_from_channels(server, NULL, client, - TRUE, (char *)signoff, TRUE); + TRUE, (char *)signoff, TRUE, FALSE); else silc_server_remove_from_channels(server, NULL, client, - FALSE, NULL, FALSE); + FALSE, NULL, FALSE, FALSE); /* Remove this client from watcher list if it is */ silc_server_del_from_watcher_list(server, client); @@ -2937,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 @@ -2982,6 +3144,9 @@ void silc_server_free_sock_user_data(SilcServer server, 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) { @@ -2996,6 +3161,7 @@ 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 { if (server->id_entry != backup_router) { @@ -3032,23 +3198,41 @@ 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) { /* 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. */ - silc_server_remove_clients_by_server(server, user_data, - user_data, TRUE); + 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) @@ -3097,6 +3281,7 @@ void silc_server_free_sock_user_data(SilcServer server, server->server_name, server->router->server_name)); } + server->backup_noswitch = FALSE; /* Free the server entry */ silc_server_backup_del(server, user_data); @@ -3142,7 +3327,8 @@ 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; @@ -3162,7 +3348,8 @@ 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; @@ -3198,7 +3385,7 @@ void silc_server_remove_from_channels(SilcServer server, } 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 @@ -3207,6 +3394,7 @@ void silc_server_remove_from_channels(SilcServer server, chl->client->router && !silc_server_channel_has_global(channel)) channel->global_users = FALSE; + memset(chl, 'A', sizeof(*chl)); silc_free(chl); /* Update statistics */ @@ -3245,6 +3433,21 @@ 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; @@ -3299,8 +3502,8 @@ bool silc_server_remove_from_one_channel(SilcServer server, 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 @@ -3309,6 +3512,7 @@ bool silc_server_remove_from_one_channel(SilcServer server, chl->client->router && !silc_server_channel_has_global(channel)) channel->global_users = FALSE; + memset(chl, 'O', sizeof(*chl)); silc_free(chl); /* Update statistics */ @@ -3370,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; @@ -3379,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 @@ -3580,8 +3785,8 @@ 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; @@ -3655,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) @@ -3711,8 +3915,9 @@ 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; } } @@ -3768,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); @@ -3797,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 @@ -3932,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); @@ -4045,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")); @@ -4060,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, @@ -4070,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, @@ -4082,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); @@ -4111,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, @@ -4129,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); @@ -4230,6 +4440,9 @@ void silc_server_announce_get_channels(SilcServer server, silc_server_announce_get_channel_topic(server, channel, &(*channel_topics)[i]); (*channel_users_modes_c)++; + + silc_free(cid); + i++; } @@ -4377,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, @@ -4468,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 */ @@ -4490,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; } @@ -4522,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)); @@ -4568,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); @@ -4813,69 +5009,14 @@ 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 : - SILC_PRIMARY_ROUTE(server), - 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; @@ -4921,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;