updates.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 13 Mar 2001 12:59:53 +0000 (12:59 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 13 Mar 2001 12:59:53 +0000 (12:59 +0000)
CHANGES
apps/silc/client_ops.c
apps/silcd/command.c
apps/silcd/server.c
lib/silcclient/client_notify.c
lib/silcclient/command.c
lib/silcclient/command.h
lib/silcclient/command_reply.c
lib/silcclient/command_reply.h

diff --git a/CHANGES b/CHANGES
index 323852a9c777bee2a4128ed9afd027f125007dbc..7a1abd34ac735552904f294a85b696bde3b186bd 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,31 @@
+Tue Mar 13 13:26:18 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * 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 <priikone@poseidon.pspt.fi>
 
        * Added dist-bzip hook to the Makefile.am to make bzip2
index 8d9566fe14a84ecf91d455799e7b26e2bb42ab47..2eff8bcef21ab4719198a45f3fa57f37a2b90b49 100644 (file)
@@ -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) {
index a10f877b10bd850447b718e7a08f3139c5da2bca..0202f59752c5146c675cf50f360584188d24b42b 100644 (file)
@@ -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 */
index 8fafd2428a6fab8213e43dccc0fff2d9a8bb51c0..d680e964bc5bcb206b17012c1498fbc7e8507aae 100644 (file)
@@ -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. */
index a6379da13e8cc8e35c135294dfa8194dc4ae0156..e398d96c25e8fcc1bc807354e1ea69a7a0f5619f 100644 (file)
@@ -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, 
index 7e450da9627a07599c0e62a663d8f8bb56c913a1..5f037a62b85b0abf7ed4a9e40f753b81b7053a52 100644 (file)
@@ -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);
index 1954d4578347ec6f0582c97d1bed0766d6a809dd..fad677509858c2500843ece9ac3dd30761b07410 100644 (file)
@@ -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);
index 1ab387bee7ff1eff30a62169a7d044473d928f70..f05b9eca85f7826e9858a47663c367cdc7b6aa5e 100644 (file)
@@ -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 */
index e27fcb9165fb3c57b4ac68766f276d3ca470cbe9..de788130172d2f8716bc61094ec33ffebbbeddb9 100644 (file)
@@ -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);