From f88b3f268a6f1e8f4adb1c2bd742a6ee41612241 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 16 Sep 2002 10:21:28 +0000 Subject: [PATCH] Added support for removing unconfigured client connections in rehash in server. Added support for aborting automatically pending commands that never receives the reply (to avoid memory leaks). Preliminary support for handling Rrequested Attributes in WHOIS. --- CHANGES | 22 +++ TODO | 4 - apps/silcd/command.c | 301 ++++++++++++++++++++++++----------- apps/silcd/command.h | 9 +- apps/silcd/command_reply.c | 8 +- apps/silcd/idlist.c | 4 +- apps/silcd/idlist.h | 2 - apps/silcd/server.c | 124 +++++++-------- apps/silcd/server.h | 3 - apps/silcd/server_backup.c | 3 +- apps/silcd/server_internal.h | 6 - 11 files changed, 305 insertions(+), 181 deletions(-) diff --git a/CHANGES b/CHANGES index 0c4b060a..e0861f00 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,25 @@ +Mon Sep 16 12:02:54 EEST 2002 Pekka Riikonen + + * Added 'app_context' to silc_schedule_init. It is an + application specific context that is delivered to application + in task callback functions. Affected files are + lib/silcutil/silcutil.[ch]. + +Sun Sep 15 22:16:19 EEST 2002 Pekka Riikonen + + * Added support for removing explicitly added client connections + in rehash and closing the client connections if they were + unconfigured in the rehash. Affected file silcd/server.c. + + * Added support for aborting automatically pending commands + that never receives the reply (to avoid memory leaks). + Added also silc_server_command_pending_timed to set the + specific timeout for pending command. Affected files are + silcd/command[_reply].[ch]. + + * Added SILC_STATUS_ERR_TIMEDOUT status. Updated protocol + specs and lib/silccore/silcstatus.h. + Sun Sep 15 12:25:10 EEST 2002 Pekka Riikonen * Changed the silc_get_time to accept time value as argument diff --git a/TODO b/TODO index 3b78256b..a1e9ed62 100644 --- a/TODO +++ b/TODO @@ -36,10 +36,6 @@ TODO/bugs In SILC Server o Testing - o Close unconfigured client connections in rehash. When client - connections are removed from the config file and rehashed the - connections matching those removed, should be closed. - o Add a timeout to handling incoming JOIN commands. It should be enforced that JOIN command is executed only once in a second or two seconds. Now it is possible to accept n incoming JOIN commands diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 086836c5..d5353d81 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -325,6 +325,46 @@ silc_server_command_dup(SilcServerCommandContext ctx) return ctx; } +/* Timeout for pending command. If reply to pending command never arrives + this is called to free resources. */ + +SILC_TASK_CALLBACK(silc_server_command_pending_timeout) +{ + SilcServer server = app_context; + SilcServerCommandPending *reply = context; + SilcServerCommandReplyContext cmdr; + SilcBuffer tmpreply; + int i; + + SILC_LOG_DEBUG(("Timeout pending command")); + + /* Allocate temporary and bogus command reply context */ + cmdr = silc_calloc(1, sizeof(*cmdr)); + cmdr->server = server; + cmdr->ident = reply->ident; + + /* Check for pending commands and mark to be exeucted */ + cmdr->callbacks = + silc_server_command_pending_check(server, reply->reply_cmd, + reply->ident, &cmdr->callbacks_count); + + /* Create bogus command reply with an error inside */ + tmpreply = + silc_command_reply_payload_encode_va(reply->reply_cmd, + SILC_STATUS_ERR_TIMEDOUT, 0, + reply->ident, 0); + cmdr->payload = silc_command_payload_parse(tmpreply->data, tmpreply->len); + silc_buffer_free(tmpreply); + + /* Call all callbacks. Same as SILC_SERVER_PENDING_EXEC macro. */ + for (i = 0; i < cmdr->callbacks_count; i++) + if (cmdr->callbacks[i].callback) + (*cmdr->callbacks[i].callback)(cmdr->callbacks[i].context, cmdr); + + silc_server_command_pending_del(server, reply->reply_cmd, reply->ident); + silc_server_command_reply_free(cmdr); +} + /* Add new pending command to be executed when reply to a command has been received. The `reply_cmd' is the command that will call the `callback' with `context' when reply has been received. It can be SILC_COMMAND_NONE @@ -339,6 +379,20 @@ bool silc_server_command_pending(SilcServer server, SilcUInt16 ident, SilcCommandCb callback, void *context) +{ + return silc_server_command_pending_timed(server, reply_cmd, ident, callback, + context, 0); +} + +/* Same as silc_server_command_pending with specific timeout for pending + commands. If the `timeout' is zero default timeout is used. */ + +bool silc_server_command_pending_timed(SilcServer server, + SilcCommand reply_cmd, + SilcUInt16 ident, + SilcCommandCb callback, + void *context, + SilcUInt16 timeout) { SilcServerCommandPending *reply; @@ -357,6 +411,11 @@ bool silc_server_command_pending(SilcServer server, reply->ident = ident; reply->context = context; reply->callback = callback; + reply->timeout = + silc_schedule_task_add(server->schedule, 0, + silc_server_command_pending_timeout, reply, + timeout ? timeout : 10, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); silc_dlist_add(server->pending_commands, reply); return TRUE; @@ -376,6 +435,8 @@ void silc_server_command_pending_del(SilcServer server, r->reply_check)) && r->ident == ident) { silc_dlist_del(server->pending_commands, r); + if (r->timeout) + silc_schedule_task_del(server->schedule, r->timeout); silc_free(r); } } @@ -386,7 +447,6 @@ void silc_server_command_pending_del(SilcServer server, SilcServerCommandPendingCallbacks silc_server_command_pending_check(SilcServer server, - SilcServerCommandReplyContext ctx, SilcCommand command, SilcUInt16 ident, SilcUInt32 *callbacks_count) @@ -403,7 +463,6 @@ silc_server_command_pending_check(SilcServer server, callbacks[i].context = r->context; callbacks[i].callback = r->callback; r->reply_check = TRUE; - ctx->ident = ident; i++; } } @@ -477,6 +536,7 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd, SilcBuffer buffer; /* Send the same command reply payload */ + silc_command_set_command(cmdr->payload, silc_command_get(cmd->payload)); silc_command_set_ident(cmdr->payload, silc_command_get_ident(cmd->payload)); buffer = silc_command_payload_encode_payload(cmdr->payload); @@ -523,7 +583,8 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, char **server_name, int *count, ResolveError *error_client, - SilcUInt32 *error_client_count) + SilcUInt32 *error_client_count, + SilcDList *attrs) { unsigned char *tmp; SilcUInt32 len; @@ -571,23 +632,30 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, else *count = 0; + /* Get requested attributes if set */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp && attrs) + *attrs = silc_attribute_payload_parse_list(tmp, len); + return TRUE; } /* Resolve context used by both WHOIS and IDENTIFY commands */ typedef struct { - SilcServerEntry router; + SilcSocketConnection sock; SilcUInt16 ident; unsigned char **res_argv; SilcUInt32 *res_argv_lens; SilcUInt32 *res_argv_types; SilcUInt32 res_argc; + SilcUInt32 res_timeout; } *SilcServerResolveContext; static bool silc_server_command_whois_check(SilcServerCommandContext cmd, SilcClientEntry *clients, - SilcUInt32 clients_count) + SilcUInt32 clients_count, + SilcDList attrs) { SilcServer server = cmd->server; SilcClientEntry entry; @@ -603,31 +671,46 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, if (!entry) continue; - if ((entry->nickname && entry->username && entry->userinfo) || - !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) { - if (!entry->router) - continue; - - /* If we are normal server, and we've not resolved this client from - router and it is global client, we'll check whether it is on some - channel. If not then we cannot be sure about its validity, and - we'll resolve it from router. */ - if (cmd->server->server_type != SILC_SERVER || cmd->pending || - entry->connection || silc_hash_table_count(entry->channels)) - continue; + /* If requested attributes is set then we always resolve the client + information, if not then check whether the entry is complete or not + and decide whether we need to resolve or not. Usually attributes + are not present so the this test is performed all the time. */ + if (!attrs) { + if ((entry->nickname && entry->username && entry->userinfo) || + !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) { + if (!entry->router) + continue; + + /* If we are normal server, and we've not resolved this client from + router and it is global client, we'll check whether it is on some + channel. If not then we cannot be sure about its validity, and + we'll resolve it from router. */ + if (cmd->server->server_type != SILC_SERVER || cmd->pending || + entry->connection || silc_hash_table_count(entry->channels)) + continue; + } } + /* When requested attributes is present and local client is detached + we cannot send the command to the client, we'll reply on behalf of + the client instead. */ + if (attrs && SILC_IS_LOCAL(entry) && entry->mode & SILC_UMODE_DETACHED) + continue; + /* We need to resolve this entry since it is not complete */ if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) { /* The entry is being resolved (and we are not the resolver) so attach to the command reply and we're done with this one. */ - silc_server_command_pending(server, SILC_COMMAND_NONE, + silc_server_command_pending(server, SILC_COMMAND_NONE, entry->resolve_cmd_ident, silc_server_command_whois, silc_server_command_dup(cmd)); no_res = FALSE; } else { + SilcBuffer idp; + SilcSocketConnection sock; + if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) { /* We've resolved this and it still is not ready. We'll return and are that this will be handled again after it is resolved. */ @@ -640,28 +723,72 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, } silc_free(resolve); return FALSE; - } else { - /* We'll resolve this client */ - SilcBuffer idp; + } - r = NULL; - for (k = 0; k < resolve_count; k++) { - if (resolve[k].router == entry->router) { - r = &resolve[k]; - break; - } - } + /* We'll resolve this client now */ - if (!r) { - resolve = silc_realloc(resolve, sizeof(*resolve) * - (resolve_count + 1)); - r = &resolve[resolve_count]; - memset(r, 0, sizeof(*r)); - r->router = entry->router; - r->ident = ++server->cmd_ident; - resolve_count++; + sock = (SILC_IS_LOCAL(entry) ? entry->connection : + entry->router->connection); + if (!sock) + continue; + + r = NULL; + for (k = 0; k < resolve_count; k++) { + if (resolve[k].sock == sock) { + r = &resolve[k]; + break; } + } + + if (!r) { + resolve = silc_realloc(resolve, sizeof(*resolve) * + (resolve_count + 1)); + r = &resolve[resolve_count]; + memset(r, 0, sizeof(*r)); + r->sock = sock; + r->ident = ++server->cmd_ident; + if (SILC_IS_LOCAL(entry)) + r->res_timeout = 2; + else + r->res_timeout = 0; + resolve_count++; + } + + r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) * + (r->res_argc + 1)); + r->res_argv_lens = silc_realloc(r->res_argv_lens, + sizeof(*r->res_argv_lens) * + (r->res_argc + 1)); + r->res_argv_types = silc_realloc(r->res_argv_types, + sizeof(*r->res_argv_types) * + (r->res_argc + 1)); + idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); + r->res_argv[r->res_argc] = silc_calloc(idp->len, + sizeof(**r->res_argv)); + memcpy(r->res_argv[r->res_argc], idp->data, idp->len); + r->res_argv_lens[r->res_argc] = idp->len; + r->res_argv_types[r->res_argc] = r->res_argc + 4; + r->res_argc++; + silc_buffer_free(idp); + entry->resolve_cmd_ident = r->ident; + entry->data.status |= SILC_IDLIST_STATUS_RESOLVING; + entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED; + } + } + + /* Do the resolving */ + for (i = 0; i < resolve_count; i++) { + SilcBuffer res_cmd; + unsigned char *attrs_buf; + SilcUInt32 attrs_buf_len; + + r = &resolve[i]; + + /* If attributes were present put them to this resolving as well */ + if (attrs) { + attrs_buf = silc_argument_get_arg_type(cmd->args, 3, &attrs_buf_len); + if (attrs_buf) { r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) * (r->res_argc + 1)); r->res_argv_lens = silc_realloc(r->res_argv_lens, @@ -670,44 +797,28 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, r->res_argv_types = silc_realloc(r->res_argv_types, sizeof(*r->res_argv_types) * (r->res_argc + 1)); - idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); - r->res_argv[r->res_argc] = silc_calloc(idp->len, - sizeof(**r->res_argv)); - memcpy(r->res_argv[r->res_argc], idp->data, idp->len); - r->res_argv_lens[r->res_argc] = idp->len; - r->res_argv_types[r->res_argc] = r->res_argc + 4; + r->res_argv[r->res_argc] = silc_memdup(attrs_buf, attrs_buf_len); + r->res_argv_lens[r->res_argc] = attrs_buf_len; + r->res_argv_types[r->res_argc] = 3; r->res_argc++; - silc_buffer_free(idp); - - entry->resolve_cmd_ident = r->ident; - entry->data.status |= SILC_IDLIST_STATUS_RESOLVING; - entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED; } } - } - /* Do the resolving */ - for (i = 0; i < resolve_count; i++) { - SilcBuffer res_cmd; - - r = &resolve[i]; - - /* Send WHOIS request. We send WHOIS since we're doing the requesting - now anyway so make it a good one. */ + /* Send WHOIS command */ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS, r->res_argc, r->res_argv, r->res_argv_lens, r->res_argv_types, r->ident); - silc_server_packet_send(server, r->router->connection, - SILC_PACKET_COMMAND, cmd->packet->flags, - res_cmd->data, res_cmd->len, FALSE); + silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, + cmd->packet->flags, res_cmd->data, + res_cmd->len, FALSE); /* Reprocess this packet after received reply */ - silc_server_command_pending(server, SILC_COMMAND_WHOIS, - r->ident, - silc_server_command_whois, - silc_server_command_dup(cmd)); + silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS, r->ident, + silc_server_command_whois, + silc_server_command_dup(cmd), + r->res_timeout); cmd->pending = TRUE; silc_buffer_free(res_cmd); @@ -937,13 +1048,15 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) SilcClientID **client_id = NULL; SilcUInt32 client_id_count = 0, clients_count = 0, error_client_count = 0; ResolveError error_client = NULL; + SilcDList attrs = NULL; int i, ret = 0; bool check_global = FALSE; /* Parse the whois request */ - if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, + if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, &nick, &server_name, &count, - &error_client, &error_client_count)) + &error_client, &error_client_count, + &attrs)) return 0; /* Send the WHOIS request to the router only if it included nickname. @@ -967,43 +1080,43 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) if (client_id_count) { /* Check all Client ID's received in the command packet */ for (i = 0; i < client_id_count; i++) { - entry = silc_idlist_find_client_by_id(server->local_list, + entry = silc_idlist_find_client_by_id(server->local_list, client_id[i], TRUE, NULL); if (!entry && check_global) - entry = silc_idlist_find_client_by_id(server->global_list, + entry = silc_idlist_find_client_by_id(server->global_list, client_id[i], TRUE, NULL); if (entry) { - clients = silc_realloc(clients, sizeof(*clients) * + clients = silc_realloc(clients, sizeof(*clients) * (clients_count + 1)); clients[clients_count++] = entry; } else { /* If we are normal server and did not send the request first to router do it now, since we do not have the Client ID information. */ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && - server->server_type == SILC_SERVER && !cmd->pending && + server->server_type == SILC_SERVER && !cmd->pending && !server->standalone) { silc_server_command_whois_send_router(cmd); ret = -1; goto out; } - ADD_ERROR(error_client, error_client_count, client_id[i], + ADD_ERROR(error_client, error_client_count, client_id[i], SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); } } } else if (nick) { /* Find by nickname */ - if (!silc_idlist_get_clients_by_hash(server->local_list, + if (!silc_idlist_get_clients_by_hash(server->local_list, nick, server->md5hash, &clients, &clients_count)) - silc_idlist_get_clients_by_nickname(server->local_list, + silc_idlist_get_clients_by_nickname(server->local_list, nick, server_name, &clients, &clients_count); if (check_global) { - if (!silc_idlist_get_clients_by_hash(server->global_list, + if (!silc_idlist_get_clients_by_hash(server->global_list, nick, server->md5hash, &clients, &clients_count)) - silc_idlist_get_clients_by_nickname(server->global_list, + silc_idlist_get_clients_by_nickname(server->global_list, nick, server_name, &clients, &clients_count); } @@ -1013,7 +1126,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) /* If we are normal server and did not send the request first to router do it now, since we do not have the information. */ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && - server->server_type == SILC_SERVER && !cmd->pending && + server->server_type == SILC_SERVER && !cmd->pending && !server->standalone) { silc_server_command_whois_send_router(cmd); ret = -1; @@ -1037,7 +1150,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) mandatory fields that WHOIS command reply requires. Check for these and make query from the server who owns the client if some fields are missing. */ - if (!silc_server_command_whois_check(cmd, clients, clients_count)) { + if (!silc_server_command_whois_check(cmd, clients, clients_count, attrs)) { ret = -1; goto out; } @@ -1057,6 +1170,8 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) silc_free(error_client); silc_free(nick); silc_free(server_name); + if (attrs) + silc_attribute_payload_list_free(attrs); return ret; } @@ -1707,7 +1822,7 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd, r = NULL; for (k = 0; k < resolve_count; k++) { - if (resolve[k].router == entry->router) { + if (resolve[k].sock == entry->router->connection) { r = &resolve[k]; break; } @@ -1718,7 +1833,7 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd, (resolve_count + 1)); r = &resolve[resolve_count]; memset(r, 0, sizeof(*r)); - r->router = entry->router; + r->sock = entry->router->connection; r->ident = ++server->cmd_ident; resolve_count++; } @@ -1760,9 +1875,9 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd, r->res_argv_lens, r->res_argv_types, r->ident); - silc_server_packet_send(server, r->router->connection, - SILC_PACKET_COMMAND, cmd->packet->flags, - res_cmd->data, res_cmd->len, FALSE); + silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, + cmd->packet->flags, res_cmd->data, + res_cmd->len, FALSE); /* Reprocess this packet after received reply */ silc_server_command_pending(server, SILC_COMMAND_WHOIS, @@ -2727,7 +2842,6 @@ SILC_SERVER_CMD_FUNC(invite) } typedef struct { - SilcServer server; SilcSocketConnection sock; char *signoff; } *QuitInternal; @@ -2737,17 +2851,19 @@ typedef struct { SILC_TASK_CALLBACK(silc_server_command_quit_cb) { + SilcServer server = app_context; QuitInternal q = (QuitInternal)context; /* Free all client specific data, such as client entry and entires on channels this client may be on. */ - silc_server_free_client_data(q->server, q->sock, q->sock->user_data, + silc_server_free_client_data(server, q->sock, q->sock->user_data, TRUE, q->signoff); q->sock->user_data = NULL; /* Close the connection on our side */ - silc_server_close_connection(q->server, q->sock); + silc_server_close_connection(server, q->sock); + silc_socket_free(q->sock); silc_free(q->signoff); silc_free(q); } @@ -2774,8 +2890,7 @@ SILC_SERVER_CMD_FUNC(quit) tmp = NULL; q = silc_calloc(1, sizeof(*q)); - q->server = server; - q->sock = sock; + q->sock = silc_socket_dup(sock); q->signoff = tmp ? strdup(tmp) : NULL; /* We quit the connection with little timeout */ @@ -4990,25 +5105,26 @@ SILC_SERVER_CMD_FUNC(oper) SILC_TASK_CALLBACK(silc_server_command_detach_cb) { + SilcServer server = app_context; QuitInternal q = (QuitInternal)context; SilcClientID *client_id = (SilcClientID *)q->sock; SilcClientEntry client; SilcSocketConnection sock; - client = silc_idlist_find_client_by_id(q->server->local_list, client_id, + client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, NULL); if (client && client->connection) { sock = client->connection; /* If there is pending outgoing data for the client then purge it to the network before closing connection. */ - silc_server_packet_queue_purge(q->server, sock); + silc_server_packet_queue_purge(server, sock); /* Close the connection on our side */ client->router = NULL; client->connection = NULL; sock->user_data = NULL; - silc_server_close_connection(q->server, sock); + silc_server_close_connection(server, sock); } silc_free(client_id); @@ -5017,15 +5133,16 @@ SILC_TASK_CALLBACK(silc_server_command_detach_cb) SILC_TASK_CALLBACK(silc_server_command_detach_timeout) { + SilcServer server = app_context; QuitInternal q = (QuitInternal)context; SilcClientID *client_id = (SilcClientID *)q->sock; SilcClientEntry client; - client = silc_idlist_find_client_by_id(q->server->local_list, client_id, + client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, NULL); if (client && client->mode & SILC_UMODE_DETACHED) { SILC_LOG_DEBUG(("Detach timeout")); - silc_server_free_client_data(q->server, NULL, client, TRUE, + silc_server_free_client_data(server, NULL, client, TRUE, "Detach timeout"); } @@ -5075,14 +5192,12 @@ SILC_SERVER_CMD_FUNC(detach) SILC_NOTIFY_TYPE_UMODE_CHANGE); q = silc_calloc(1, sizeof(*q)); - q->server = server; q->sock = silc_id_dup(client->id, SILC_ID_CLIENT); silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_cb, q, 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); if (server->config->detach_timeout) { q = silc_calloc(1, sizeof(*q)); - q->server = server; q->sock = silc_id_dup(client->id, SILC_ID_CLIENT); silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_timeout, diff --git a/apps/silcd/command.h b/apps/silcd/command.h index 2e3273d6..9cd04d79 100644 --- a/apps/silcd/command.h +++ b/apps/silcd/command.h @@ -61,12 +61,12 @@ typedef struct { /* Structure holding pending commands. If command is pending it will be executed after command reply has been received and executed. */ typedef struct SilcServerCommandPendingStruct { - SilcServer server; SilcCommand reply_cmd; SilcUInt16 ident; unsigned int reply_check : 8; SilcCommandCb callback; void *context; + SilcTask timeout; struct SilcServerCommandPendingStruct *next; } SilcServerCommandPending; @@ -111,12 +111,17 @@ bool silc_server_command_pending(SilcServer server, SilcUInt16 ident, SilcCommandCb callback, void *context); +bool silc_server_command_pending_timed(SilcServer server, + SilcCommand reply_cmd, + SilcUInt16 ident, + SilcCommandCb callback, + void *context, + SilcUInt16 timeout); void silc_server_command_pending_del(SilcServer server, SilcCommand reply_cmd, SilcUInt16 ident); SilcServerCommandPendingCallbacks silc_server_command_pending_check(SilcServer server, - SilcServerCommandReplyContext ctx, SilcCommand command, SilcUInt16 ident, SilcUInt32 *callbacks_count); diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index ecf6f3c2..bff81fa6 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -66,7 +66,6 @@ void silc_server_command_reply_process(SilcServer server, SilcServerCommandReplyContext ctx; SilcCommandPayload payload; SilcCommand command; - SilcUInt16 ident; SILC_LOG_DEBUG(("Start")); @@ -85,13 +84,12 @@ void silc_server_command_reply_process(SilcServer server, ctx->sock = silc_socket_dup(sock); ctx->payload = payload; ctx->args = silc_command_get_args(ctx->payload); - ident = silc_command_get_ident(ctx->payload); + ctx->ident = silc_command_get_ident(ctx->payload); /* Check for pending commands and mark to be exeucted */ ctx->callbacks = - silc_server_command_pending_check(server, ctx, - silc_command_get(ctx->payload), - ident, &ctx->callbacks_count); + silc_server_command_pending_check(server, silc_command_get(ctx->payload), + ctx->ident, &ctx->callbacks_count); /* Execute command reply */ command = silc_command_get(ctx->payload); diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 88331903..900092bf 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -90,13 +90,13 @@ void silc_idlist_del_data(void *entry) SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge) { + SilcServer server = app_context; SilcIDListPurge i = (SilcIDListPurge)context; SILC_LOG_DEBUG(("Purging cache")); silc_idcache_purge(i->cache); - silc_schedule_task_add(i->schedule, 0, - silc_idlist_purge, + silc_schedule_task_add(server->schedule, 0, silc_idlist_purge, (void *)i, i->timeout, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); } diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 64171f7d..ac417a79 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -30,13 +30,11 @@ typedef struct SilcChannelEntryStruct *SilcChannelEntry; the cache. */ typedef struct { SilcIDCache cache; - SilcSchedule schedule; SilcUInt32 timeout; } *SilcIDListPurge; /* Channel key re-key context. */ typedef struct { - void *context; SilcChannelEntry channel; SilcUInt32 key_len; SilcTask task; diff --git a/apps/silcd/server.c b/apps/silcd/server.c index f5e6b7fc..d75fdd80 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -320,7 +320,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; @@ -474,27 +475,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, + silc_schedule_task_add(server->schedule, 0, silc_server_get_stats, server, 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); @@ -618,14 +615,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, @@ -649,13 +647,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, @@ -669,6 +667,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, @@ -860,8 +888,8 @@ 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); @@ -916,8 +944,8 @@ 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; @@ -1030,7 +1058,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; @@ -1248,7 +1275,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; @@ -1352,15 +1378,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final) /* 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, + 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, @@ -1750,7 +1773,6 @@ 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; @@ -2063,9 +2085,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) /* 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_socket_set_heartbeat(sock, hearbeat_timeout, server, silc_server_perform_heartbeat, server->schedule); @@ -2341,7 +2361,7 @@ 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 @@ -2372,7 +2392,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: @@ -2449,13 +2469,12 @@ void silc_server_packet_parse_type(SilcServer server, if (sock->protocol) { SilcServerFailureContext f; f = silc_calloc(1, sizeof(*f)); - f->server = server; - f->sock = sock; + f->sock = silc_socket_dup(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); + silc_server_failure_callback, (void *)f, 5, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } break; @@ -2831,7 +2850,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; @@ -2957,20 +2975,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(i->client->channels)); + 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. */ @@ -2983,16 +2996,6 @@ void silc_server_free_client_data(SilcServer server, { 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); @@ -3034,12 +3037,9 @@ void silc_server_free_client_data(SilcServer server, into history (for WHOWAS command) for 5 minutes, unless we're shutting down server. */ if (!server->server_shutdown) { - FreeClientInternal i = silc_calloc(1, sizeof(*i)); - i->server = server; - i->client = client; silc_schedule_task_add(server->schedule, 0, silc_server_free_client_data_timeout, - (void *)i, 300, 0, + client, 300, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; client->data.status &= ~SILC_IDLIST_STATUS_LOCAL; @@ -3693,8 +3693,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; @@ -3768,7 +3768,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) @@ -3882,7 +3881,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); @@ -3911,13 +3909,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:%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 @@ -4507,13 +4505,15 @@ void silc_server_announce_channels(SilcServer server, SILC_TASK_CALLBACK(silc_server_failure_callback) { + SilcServer server = app_context; 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_protocol_execute(f->sock->protocol, server->schedule, 0, 0); } + silc_socket_free(f->sock); silc_free(f); } @@ -4996,9 +4996,9 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server, SILC_TASK_CALLBACK(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; diff --git a/apps/silcd/server.h b/apps/silcd/server.h index 3fec0d75..5757fefc 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -50,9 +50,6 @@ typedef struct { SilcUInt32 retry_count; SilcUInt32 retry_timeout; - /* Back pointer to server */ - SilcServer server; - SilcServerConnectRouterCallback callback; void *callback_context; } *SilcServerConnection; diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index ae8d0a76..196ab565 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -541,8 +541,8 @@ void silc_server_backup_resume_router(SilcServer server, SILC_TASK_CALLBACK(silc_server_backup_connect_to_router) { + SilcServer server = app_context; SilcServerConnection sconn = (SilcServerConnection)context; - SilcServer server = sconn->server; int sock; const char *server_ip; @@ -578,7 +578,6 @@ void silc_server_backup_reconnect(SilcServer server, SilcServerConnection sconn; sconn = silc_calloc(1, sizeof(*sconn)); - sconn->server = server; sconn->remote_host = strdup(ip); sconn->remote_port = port; sconn->callback = callback; diff --git a/apps/silcd/server_internal.h b/apps/silcd/server_internal.h index 35eb1d89..64141a70 100644 --- a/apps/silcd/server_internal.h +++ b/apps/silcd/server_internal.h @@ -146,16 +146,10 @@ struct SilcServerStruct { #endif }; -/* Server's heartbeat context */ -typedef struct { - SilcServer server; -} *SilcServerHBContext; - /* Failure context. This is allocated when failure packet is received. Failure packets are processed with timeout and data is saved in this structure. */ typedef struct { - SilcServer server; SilcSocketConnection sock; SilcUInt32 failure; } *SilcServerFailureContext; -- 2.24.0