From: Pekka Riikonen Date: Tue, 13 Mar 2001 12:59:53 +0000 (+0000) Subject: updates. X-Git-Tag: SILC.0.1~128 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=930686030b240f2c97b401597eca710ce47f2144 updates. --- diff --git a/CHANGES b/CHANGES index 323852a9..7a1abd34 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,31 @@ +Tue Mar 13 13:26:18 EET 2001 Pekka Riikonen + + * Added support to the server to enforce that commands are not + executed more than once in 2 seconds. If server receives + commands from client more frequently, timeout is registered + to process the commands. Affected file silcd/command.c. + Added new function silc_server_command_process_timeout. + + * Changed NICK_NOTIFY handling in client library to check that + if the client's nickname was changed, so there is no need to + resolve anything from the server. + + * Removed error printing from the WHOIS and IDENTIFY commands. + If error occurs then it is ignored silently in the client library. + The application, however, may map the received error to + human readable error string. The application currently maps + the NO_SUCH_NICKNAME error to string. + + * Made the command status message public to the application. Moved + them from lib/silcclient/command_reply.c to + lib/silcclient/command_reply.h. The application can map the + received command status to the string with the + silc_client_command_status_message function. + + * Added check to the server to check that client's ID is same + as the Source ID in the packet the client sent. They must + match. + Tue Mar 13 12:49:21 EET 2001 Pekka Riikonen * Added dist-bzip hook to the Makefile.am to make bzip2 diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index 8d9566fe..2eff8bce 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -369,9 +369,6 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, SilcChannelUser chu; va_list vp; - if (!success) - return; - va_start(vp, status); switch(command) @@ -382,6 +379,22 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, int len; unsigned int idle; + if (status == SILC_STATUS_ERR_NO_SUCH_NICK) { + char *tmp; + tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload), + 3, NULL); + if (tmp) + client->ops->say(client, conn, "%s: %s", tmp, + silc_client_command_status_message(status)); + else + client->ops->say(client, conn, "%s", + silc_client_command_status_message(status)); + break; + } + + if (!success) + return; + (void)va_arg(vp, SilcClientEntry); nickname = va_arg(vp, char *); username = va_arg(vp, char *); @@ -424,6 +437,9 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, unsigned int list_count; SilcChannelEntry channel; + if (!success) + return; + app->screen->bottom_line->channel = va_arg(vp, char *); channel = va_arg(vp, SilcChannelEntry); mode = va_arg(vp, unsigned int); @@ -454,6 +470,9 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, { SilcClientEntry entry; + if (!success) + return; + entry = va_arg(vp, SilcClientEntry); silc_say(client, conn, "Your current nickname is %s", entry->nickname); app->screen->bottom_line->nickname = entry->nickname; @@ -462,6 +481,9 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, break; case SILC_COMMAND_USERS: + if (!success) + return; + silc_list_start(conn->current_channel->clients); while ((chu = silc_list_get(conn->current_channel->clients)) != SILC_LIST_END) { diff --git a/apps/silcd/command.c b/apps/silcd/command.c index a10f877b..0202f597 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -37,6 +37,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd, unsigned int arg_type, unsigned char *arg, unsigned int arg_len); +SILC_TASK_CALLBACK(silc_server_command_process_timeout); /* Server command list. */ SilcServerCommand silc_command_list[] = @@ -113,6 +114,71 @@ static int silc_server_is_registered(SilcServer server, return FALSE; } +/* Internal context to hold data when executed command with timeout. */ +typedef struct { + SilcServer server; + SilcSocketConnection sock; + SilcPacketContext *packet; +} *SilcServerCommandTimeout; + +/* Timeout callback to process commands with timeout for client. Client's + commands are always executed with timeout. */ + +SILC_TASK_CALLBACK(silc_server_command_process_timeout) +{ + SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context; + SilcServerCommandContext ctx; + SilcServerCommand *cmd; + SilcClientEntry client = (SilcClientEntry)timeout->sock->user_data; + + /* Update access time */ + client->last_command = time(NULL); + + /* Allocate command context. This must be free'd by the + command routine receiving it. */ + ctx = silc_server_command_alloc(); + ctx->server = timeout->server; + ctx->sock = timeout->sock; + ctx->packet = timeout->packet; + + /* Parse the command payload in the packet */ + ctx->payload = silc_command_payload_parse(ctx->packet->buffer); + if (!ctx->payload) { + SILC_LOG_ERROR(("Bad command payload, packet dropped")); + silc_buffer_free(ctx->packet->buffer); + silc_socket_free(ctx->sock); + silc_packet_context_free(ctx->packet); + silc_free(ctx); + silc_free(timeout); + return; + } + ctx->args = silc_command_get_args(ctx->payload); + + /* Execute command. If this fails the packet is dropped. */ + for (cmd = silc_command_list; cmd->cb; cmd++) + if (cmd->cmd == silc_command_get(ctx->payload)) { + + if (!(cmd->flags & SILC_CF_REG)) { + cmd->cb(ctx); + break; + } + + if (silc_server_is_registered(ctx->server, ctx->sock, ctx, cmd->cmd)) { + cmd->cb(ctx); + break; + } + } + + if (cmd == NULL) { + SILC_LOG_ERROR(("Unknown command, packet dropped")); + silc_server_command_free(ctx); + silc_free(timeout); + return; + } + + silc_free(timeout); +} + /* Processes received command packet. */ void silc_server_command_process(SilcServer server, @@ -122,29 +188,35 @@ void silc_server_command_process(SilcServer server, SilcServerCommandContext ctx; SilcServerCommand *cmd; -#if 0 - /* XXX allow commands in but do not execute them more than once per - two seconds. */ - - /* Check whether it is allowed for this connection to execute any - command. */ + /* Execute client's commands always with timeout. Normally they are + executed with zero (0) timeout but if client is sending command more + frequently than once in 2 seconds, then the timeout may be 0 to 2 + seconds. */ if (sock->type == SILC_SOCKET_TYPE_CLIENT) { - time_t curtime; SilcClientEntry client = (SilcClientEntry)sock->user_data; - - if (!client) - return; - - /* Allow only one command executed in 2 seconds. */ - curtime = time(NULL); - if (client->last_command && (curtime - client->last_command) < 2) - return; - - /* Update access time */ - client->last_command = curtime; + SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout)); + + timeout->server = server; + timeout->sock = silc_socket_dup(sock); + timeout->packet = silc_packet_context_dup(packet); + + if (client->last_command && (time(NULL) - client->last_command) < 2) + silc_task_register(server->timeout_queue, sock->sock, + silc_server_command_process_timeout, + (void *)timeout, + 2 - (time(NULL) - client->last_command), 0, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + else + silc_task_register(server->timeout_queue, sock->sock, + silc_server_command_process_timeout, + (void *)timeout, + 0, 1, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); + return; } -#endif - + /* Allocate command context. This must be free'd by the command routine receiving it. */ ctx = silc_server_command_alloc(); @@ -1271,6 +1343,9 @@ SILC_SERVER_CMD_FUNC(nick) SilcClientID *new_id; char *nick; + if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) + goto out; + SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1); /* Check nickname */ diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 8fafd242..d680e964 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1436,6 +1436,20 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) if (ret == SILC_PACKET_NONE) goto out; + /* Check that the the current client ID is same as in the client's packet. */ + if (sock->type == SILC_SOCKET_TYPE_CLIENT) { + SilcClientEntry client = (SilcClientEntry)sock->user_data; + if (client && client->id) { + void *id = silc_id_str2id(packet->src_id, packet->src_id_len, + packet->src_id_type); + if (SILC_ID_CLIENT_COMPARE(client->id, id)) { + silc_free(id); + goto out; + } + silc_free(id); + } + } + if (server->server_type == SILC_ROUTER) { /* Route the packet if it is not destined to us. Other ID types but server are handled separately after processing them. */ diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index a6379da1..e398d96c 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -353,8 +353,8 @@ void silc_client_notify_by_server(SilcClient client, * application. */ - /* Get new Client ID */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); + /* Get old Client ID */ + tmp = silc_argument_get_arg_type(args, 1, &tmp_len); if (!tmp) goto out; @@ -366,17 +366,14 @@ void silc_client_notify_by_server(SilcClient client, if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id)) break; - /* Find Client entry and if not found query it */ - client_entry2 = - silc_client_get_client_by_id(client, conn, client_id); - if (!client_entry2) { - silc_client_notify_by_server_resolve(client, conn, packet, client_id); + /* Find old Client entry */ + client_entry = silc_client_get_client_by_id(client, conn, client_id); + if (!client_entry) goto out; - } silc_free(client_id); - /* Get old Client ID */ - tmp = silc_argument_get_arg_type(args, 1, &tmp_len); + /* Get new Client ID */ + tmp = silc_argument_get_arg_type(args, 2, &tmp_len); if (!tmp) goto out; @@ -384,11 +381,12 @@ void silc_client_notify_by_server(SilcClient client, if (!client_id) goto out; - /* Find old Client entry */ - client_entry = - silc_client_get_client_by_id(client, conn, client_id); - if (!client_entry) + /* Find Client entry and if not found resolve it */ + client_entry2 = silc_client_get_client_by_id(client, conn, client_id); + if (!client_entry2) { + silc_client_notify_by_server_resolve(client, conn, packet, client_id); goto out; + } /* Remove the old from cache */ silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 7e450da9..5f037a62 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -351,7 +351,7 @@ SILC_CLIENT_CMD_FUNC(nick) buffer = silc_command_payload_encode(SILC_COMMAND_NICK, cmd->argc - 1, ++cmd->argv, ++cmd->argv_lens, ++cmd->argv_types, - 0); + ++cmd->conn->cmd_ident); silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); diff --git a/lib/silcclient/command.h b/lib/silcclient/command.h index 1954d457..fad67750 100644 --- a/lib/silcclient/command.h +++ b/lib/silcclient/command.h @@ -127,6 +127,7 @@ int silc_client_command_pending_check(SilcClientConnection conn, SilcClientCommandReplyContext ctx, SilcCommand command, unsigned short ident); + SILC_CLIENT_CMD_FUNC(whois); SILC_CLIENT_CMD_FUNC(whowas); SILC_CLIENT_CMD_FUNC(identify); diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 1ab387be..f05b9eca 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -67,14 +67,6 @@ SilcClientCommandReply silc_command_reply_list[] = { NULL, 0 }, }; -/* Status message structure. Messages are defined below. */ -typedef struct { - SilcCommandStatus status; - char *message; -} SilcCommandStatusMessage; - -/* Status messages returned by the server */ -#define STAT(x) SILC_STATUS_ERR_##x const SilcCommandStatusMessage silc_command_status_messages[] = { { STAT(NO_SUCH_NICK), "No such nickname" }, @@ -117,7 +109,6 @@ const SilcCommandStatusMessage silc_command_status_messages[] = { { 0, NULL } }; - /* Command reply operation that is called at the end of all command replys. Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */ #define COMMAND_REPLY(args) cmd->client->ops->command_reply args @@ -180,8 +171,7 @@ void silc_client_command_reply_process(SilcClient client, /* Returns status message string */ -static char * -silc_client_command_status_message(SilcCommandStatus status) +char *silc_client_command_status_message(SilcCommandStatus status) { int i; @@ -288,8 +278,9 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, } /* Notify application */ - COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, - NULL, idle)); + if (!cmd->callback) + COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, + NULL, idle)); } /* Received reply for WHOIS command. This maybe called several times @@ -298,7 +289,6 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, SILC_CLIENT_CMD_REPLY_FUNC(whois) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; - SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; unsigned char *tmp; @@ -310,23 +300,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois) status != SILC_STATUS_LIST_START && status != SILC_STATUS_LIST_ITEM && status != SILC_STATUS_LIST_END) { - if (status == SILC_STATUS_ERR_NO_SUCH_NICK) { - /* Take nickname which may be provided */ - tmp = silc_argument_get_arg_type(cmd->args, 3, NULL); - if (tmp) - cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp, - silc_client_command_status_message(status)); - else - cmd->client->ops->say(cmd->client, conn, "%s", - silc_client_command_status_message(status)); - COMMAND_REPLY_ERROR; - goto out; - } else { - cmd->client->ops->say(cmd->client, conn, - "%s", silc_client_command_status_message(status)); - COMMAND_REPLY_ERROR; - goto out; - } + COMMAND_REPLY_ERROR; + goto out; } /* Display one whois reply */ @@ -439,7 +414,6 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, SILC_CLIENT_CMD_REPLY_FUNC(identify) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; - SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; unsigned char *tmp; @@ -451,23 +425,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify) status != SILC_STATUS_LIST_START && status != SILC_STATUS_LIST_ITEM && status != SILC_STATUS_LIST_END) { - if (status == SILC_STATUS_ERR_NO_SUCH_NICK) { - /* Take nickname which may be provided */ - tmp = silc_argument_get_arg_type(cmd->args, 3, NULL); - if (tmp) - cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp, - silc_client_command_status_message(status)); - else - cmd->client->ops->say(cmd->client, conn, "%s", - silc_client_command_status_message(status)); - COMMAND_REPLY_ERROR; - goto out; - } else { - cmd->client->ops->say(cmd->client, conn, - "%s", silc_client_command_status_message(status)); - COMMAND_REPLY_ERROR; - goto out; - } + COMMAND_REPLY_ERROR; + goto out; } /* Save one IDENTIFY entry */ diff --git a/lib/silcclient/command_reply.h b/lib/silcclient/command_reply.h index e27fcb91..de788130 100644 --- a/lib/silcclient/command_reply.h +++ b/lib/silcclient/command_reply.h @@ -55,10 +55,21 @@ typedef struct { #define SILC_CLIENT_CMD_REPLY_FUNC(func) \ void silc_client_command_reply_##func(void *context) +/* Status message structure. Messages are defined below. */ +typedef struct { + SilcCommandStatus status; + char *message; +} SilcCommandStatusMessage; + +/* Status messages returned by the server */ +#define STAT(x) SILC_STATUS_ERR_##x +extern const SilcCommandStatusMessage silc_command_status_messages[]; + /* Prototypes */ void silc_client_command_reply_process(SilcClient client, SilcSocketConnection sock, SilcPacketContext *packet); +char *silc_client_command_status_message(SilcCommandStatus status); SILC_CLIENT_CMD_REPLY_FUNC(whois); SILC_CLIENT_CMD_REPLY_FUNC(whowas); SILC_CLIENT_CMD_REPLY_FUNC(identify);