updates.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 7 Apr 2002 15:31:36 +0000 (15:31 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 7 Apr 2002 15:31:36 +0000 (15:31 +0000)
18 files changed:
CHANGES
TODO
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server_internal.h
apps/silcd/server_util.c
doc/draft-riikonen-silc-commands-03.nroff
doc/draft-riikonen-silc-pp-05.nroff
lib/silcclient/client_notify.c
lib/silcclient/command_reply.c
lib/silccore/silcchannel.c
lib/silccore/silccommand.h
lib/silcske/silcske.c
lib/silcske/silcske.h

diff --git a/CHANGES b/CHANGES
index fc475d7047f607fda2d2c1ebae4ac0ae1af1cff6..45db30e115fc6e1415f60c1f7a8063f5f013857a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,34 @@
+Sun Apr  7 17:07:59 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added STATS command to the protocol after all, to return
+         various statistical information about the network.  It can
+         be used by clients to retrieve statistical information, and
+         servers may use it to to fetch cell and network wide 
+         statistics from router.  Updated the protocol specs and
+         implemented it to the server.  Protocol TODO #16.
+         Affected files are lib/silccore/silccommand, silcd/command.[ch],
+         silcd/command_reply.[ch].
+
+Sat Apr  6 17:08:58 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * The LIST command reply in client libary now adds new channel
+         entry if the returned channel doesn't exist yet in cache, 
+         and returns the channel entry to the application in the
+         command_reply client operation.  Affected file is
+         lib/silcclient/command_reply.c.
+
+       * Changed the channel message payload's MAC generation to
+         include the IV in the MAC as well.  This way all relevant
+         parts of the channel message payload are authenticated also
+         with the channel message MAC (and not only by packet MAC).
+         Causes incompatibility with 1.0 protocol.  Protocol TODO #7.
+         Affected file is lib/silccore/silcchannel.c.
+
+       * Fixed the SKE to save the remote version, since the
+         silc_ske_parse_version mistakenly checked wrong version,
+         after it replaced the start payload.  Affected files are
+         lib/silcske/silcske.[ch].
+
 Fri Apr  5 16:03:03 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Splitted lib/silcutil/silcutil.h into silcstrutil.h for
diff --git a/TODO b/TODO
index 17012127fad146ee612928824033a495914264fb..26c7660513134fde66ca703bd48721f9a2be9dfe 100644 (file)
--- a/TODO
+++ b/TODO
@@ -135,26 +135,15 @@ describe new stuff to be added to protocol versions 1.x.
     new features without always making the command incompatible to previous
     version.  To be included in protocol version 1.1.
 
- 5. Inviting and banning by public key should be made possible.  To be
-    included in protocol version 1.x.
-
- 7. Channel Message Payload needs slight redesining to include the IV
-    field to the MAC generation of the payload.  It is authenticated
-    by the packet's MAC but not by the payload's MAC.  Since the IV
-    belongs to the payload, its integrity should be protected by the
-    payload MAC and not alone by packet MAC.  To be included in protocol 
-    version 1.1.
-
- 16. Add STATS command after all to the protocol for providing practically
-     same information client gets when connects to a server.  Normal
-     server would send this to router always when received from client.
-
  17. Cell wide channel founder support, and permanent channels when
      founder mode set.
 
  18. Describe the SSH public key, X509, OpenPGP and SPKI certificates
      encoding format in SKE (from their respective definitions).
 
+ o Inviting and banning by public key should be made possible.  To be
+   included in protocol version 1.2.
+
  o UTF-8 support/requirement for nicknames & channel names.  UTF-8 support
    in terminals and OS's are so hazy that this matter is left for
    consideration in next version of the protocol (1.2).  For good UTF-8
index 98f1a29cbf73b1f609a36ff9455296a28e0b7756..d2622a084f5179d651b7a11a30cd3ad977f88cc9 100644 (file)
@@ -56,6 +56,7 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(stats, STATS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
@@ -2776,7 +2777,7 @@ SILC_SERVER_CMD_FUNC(kill)
     /* Update statistics */
     if (remote_client->connection)
       server->stat.my_clients--;
-    if (server->server_type == SILC_ROUTER)
+    if (server->stat.cell_clients)
       server->stat.cell_clients--;
     SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -2990,6 +2991,102 @@ SILC_SERVER_CMD_FUNC(ping)
   silc_server_command_free(cmd);
 }
 
+/* Server side of command STATS. */
+
+SILC_SERVER_CMD_FUNC(stats)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcServerID *server_id;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBuffer packet, stats;
+  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  SilcUInt32 uptime;
+
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_STATS, cmd, 1, 1);
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                         SILC_STATUS_ERR_NO_SERVER_ID);
+    goto out;
+  }
+  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+  if (!server_id)
+    goto out;
+
+  /* The ID must be ours */
+  if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                         SILC_STATUS_ERR_NO_SUCH_SERVER);
+    silc_free(server_id);
+    goto out;
+  }
+  silc_free(server_id);
+
+  /* If we are router then just send everything we got. If we are normal
+     server then we'll send this to our router to get all the latest
+     statistical information. */
+  if (!cmd->pending && server->server_type != SILC_ROUTER && 
+      !server->standalone) {
+    /* Send request to our router */
+    SilcBuffer idp = silc_id_payload_encode(server->router->id, 
+                                           SILC_ID_SERVER);
+    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
+                                           ++server->cmd_ident, 1,
+                                           1, idp->data, idp->len);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, 0, packet->data,
+                           packet->len, FALSE);
+
+    /* Reprocess this packet after received reply from router */
+    silc_server_command_pending(server, SILC_COMMAND_STATS, 
+                               server->cmd_ident,
+                               silc_server_command_stats,
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
+    goto out;
+  }
+
+  /* Send our reply to sender */
+  uptime = time(NULL) - server->starttime;
+
+  stats = silc_buffer_alloc_size(60);
+  silc_buffer_format(stats,
+                    SILC_STR_UI_INT(server->starttime),
+                    SILC_STR_UI_INT(uptime),
+                    SILC_STR_UI_INT(server->stat.my_clients),
+                    SILC_STR_UI_INT(server->stat.my_channels),
+                    SILC_STR_UI_INT(server->stat.my_server_ops),
+                    SILC_STR_UI_INT(server->stat.my_router_ops),
+                    SILC_STR_UI_INT(server->stat.cell_clients),
+                    SILC_STR_UI_INT(server->stat.cell_channels),
+                    SILC_STR_UI_INT(server->stat.cell_servers),
+                    SILC_STR_UI_INT(server->stat.clients),
+                    SILC_STR_UI_INT(server->stat.channels),
+                    SILC_STR_UI_INT(server->stat.servers),
+                    SILC_STR_UI_INT(server->stat.routers),
+                    SILC_STR_UI_INT(server->stat.server_ops),
+                    SILC_STR_UI_INT(server->stat.router_ops),
+                    SILC_STR_END);
+
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_STATS, 
+                                               SILC_STATUS_OK, ident, 2,
+                                               2, tmp, tmp_len,
+                                               3, stats->data, stats->len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+                         0, packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+  silc_buffer_free(stats);
+
+ out:
+  silc_server_command_free(cmd);
+}
+
 /* Internal routine to join channel. The channel sent to this function
    has been either created or resolved from ID lists. This joins the sent
    client to the channel. */
@@ -3470,8 +3567,7 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Check whether the channel was created by our router */
   if (cmd->pending && context2) {
-    SilcServerCommandReplyContext reply = 
-      (SilcServerCommandReplyContext)context2;
+    SilcServerCommandReplyContext reply = context2;
 
     if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
       tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
index 0b59e75fdff04721326443b511ad81985996fe45..b8441b7f11329e06286c2b3398c21272c035c710 100644 (file)
@@ -130,6 +130,7 @@ SILC_SERVER_CMD_FUNC(invite);
 SILC_SERVER_CMD_FUNC(quit);
 SILC_SERVER_CMD_FUNC(kill);
 SILC_SERVER_CMD_FUNC(info);
+SILC_SERVER_CMD_FUNC(stats);
 SILC_SERVER_CMD_FUNC(ping);
 SILC_SERVER_CMD_FUNC(oper);
 SILC_SERVER_CMD_FUNC(join);
index 099d03d902817fb4051849a909f25c0faad1d97f..6300ebc10d40c0614d96a8a7d9be324a8968c1ee 100644 (file)
@@ -55,6 +55,7 @@ SilcServerCommandReply silc_command_reply_list[] =
   SILC_SERVER_CMD_REPLY(info, INFO),
   SILC_SERVER_CMD_REPLY(motd, MOTD),
   SILC_SERVER_CMD_REPLY(join, JOIN),
+  SILC_SERVER_CMD_REPLY(stats, STATS),
   SILC_SERVER_CMD_REPLY(users, USERS),
   SILC_SERVER_CMD_REPLY(getkey, GETKEY),
   SILC_SERVER_CMD_REPLY(list, LIST),
@@ -872,19 +873,14 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
     /* If the channel is found from global list we must move it to the
        local list. */
-    entry = silc_idlist_find_channel_by_name(server->global_list, 
+    entry = silc_idlist_find_channel_by_name(server->global_list,
                                             channel_name, &cache);
-    if (entry) {
-      if (entry->rekey) {
-       silc_schedule_task_del_by_context(server->schedule, entry->rekey);
-       SILC_LOG_ERROR(("global_list->channels: entry->rekey != NULL, inform Pekka now!!!"));
-      }
+    if (entry)
       silc_idlist_del_channel(server->global_list, entry);
-    }
 
     /* Add the channel to our local list. */
-    entry = silc_idlist_add_channel(server->local_list, strdup(channel_name), 
-                                   SILC_CHANNEL_MODE_NONE, id, 
+    entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
+                                   SILC_CHANNEL_MODE_NONE, id,
                                    server->router, NULL, hmac, 0);
     if (!entry) {
       silc_free(id);
@@ -972,6 +968,46 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     silc_buffer_free(client_mode_list);
 }
 
+/* Received reply to STATS command.  */
+
+SILC_SERVER_CMD_REPLY_FUNC(stats)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcServer server = cmd->server;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBufferStruct buf;
+
+  COMMAND_CHECK_STATUS;
+
+  /* Get statistics structure */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  if (server->server_type == SILC_SERVER && tmp) {
+    silc_buffer_set(&buf, tmp, tmp_len);
+    silc_buffer_unformat(&buf,
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(&server->stat.cell_clients),
+                        SILC_STR_UI_INT(&server->stat.cell_channels),
+                        SILC_STR_UI_INT(&server->stat.cell_servers),
+                        SILC_STR_UI_INT(&server->stat.clients),
+                        SILC_STR_UI_INT(&server->stat.channels),
+                        SILC_STR_UI_INT(&server->stat.servers),
+                        SILC_STR_UI_INT(&server->stat.routers),
+                        SILC_STR_UI_INT(&server->stat.server_ops),
+                        SILC_STR_UI_INT(&server->stat.router_ops),
+                        SILC_STR_END);
+  }
+
+ out:
+  SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+}
+
 SILC_SERVER_CMD_REPLY_FUNC(users)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
index 17422bf4fcafec9d561c4caa06120950c68b9388..9156e298413da14a0da6f0a48371e69ff040b118 100644 (file)
@@ -72,6 +72,7 @@ SILC_SERVER_CMD_REPLY_FUNC(identify);
 SILC_SERVER_CMD_REPLY_FUNC(info);
 SILC_SERVER_CMD_REPLY_FUNC(motd);
 SILC_SERVER_CMD_REPLY_FUNC(join);
+SILC_SERVER_CMD_REPLY_FUNC(stats);
 SILC_SERVER_CMD_REPLY_FUNC(users);
 SILC_SERVER_CMD_REPLY_FUNC(getkey);
 SILC_SERVER_CMD_REPLY_FUNC(list);
index 56f015696817a1290285cb917453799a6934157f..f58aadcbfd58c5d615062841e6b37ba935f9dd8f 100644 (file)
@@ -331,7 +331,7 @@ void silc_server_notify(SilcServer server,
 
     /* Update statistics */
     server->stat.clients--;
-    if (server->server_type == SILC_ROUTER)
+    if (server->stat.cell_clients)
       server->stat.cell_clients--;
     SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -1039,7 +1039,7 @@ void silc_server_notify(SilcServer server,
 
            /* Update statistics */
            server->stat.clients--;
-           if (server->server_type == SILC_ROUTER)
+           if (server->stat.cell_clients)
              server->stat.cell_clients--;
            SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
            SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -1917,15 +1917,18 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your host is %s, running version %s",
                           server->server_name, server_version));
-  if (server->server_type == SILC_ROUTER) {
+
+  if (server->stat.clients && server->stat.servers + 1)
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d clients on %d servers in SILC "
                             "Network", server->stat.clients,
                             server->stat.servers + 1));
+  if (server->stat.cell_clients && server->stat.cell_servers + 1)
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d clients on %d server in our cell",
                             server->stat.cell_clients,
                             server->stat.cell_servers + 1));
+  if (server->server_type == SILC_ROUTER) {
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("I have %d clients, %d channels, %d servers and "
                             "%d routers",
@@ -1933,24 +1936,25 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                             server->stat.my_channels,
                             server->stat.my_servers,
                             server->stat.my_routers));
+  } else {
+    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                           ("I have %d clients and %d channels formed",
+                            server->stat.my_clients,
+                            server->stat.my_channels));
+  }
+
+  if (server->stat.server_ops || server->stat.router_ops)
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d server operators and %d router "
                             "operators online",
                             server->stat.server_ops,
                             server->stat.router_ops));
+  if (server->stat.my_router_ops + server->stat.my_server_ops)
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("I have %d operators online",
                             server->stat.my_router_ops +
                             server->stat.my_server_ops));
-  } else {
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("I have %d clients and %d channels formed",
-                            server->stat.my_clients,
-                            server->stat.my_channels));
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("%d operators online",
-                            server->stat.my_server_ops));
-  }
+
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your connection is secured with %s cipher, "
                           "key length %d bits",
index 6f22636a7b21a078ee5a59dc49f14253276347d3..306cb07f78f34a9fd2b619bb32fbcc5472c68fd6 100644 (file)
@@ -44,6 +44,7 @@ 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
    can be used. After allocation one must call silc_server_init to initialize
@@ -148,6 +149,8 @@ bool silc_server_init(SilcServer server)
 
   SILC_LOG_DEBUG(("Initializing server"));
 
+  server->starttime = time(NULL);
+
   /* Take config object for us */
   silc_server_config_ref(&server->config_ref, server->config, 
                         server->config);
@@ -338,6 +341,13 @@ bool silc_server_init(SilcServer server)
                         (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,
+                          server, 10, 0, SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
@@ -1425,8 +1435,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* Statistics */
       server->stat.my_clients++;
       server->stat.clients++;
-      if (server->server_type == SILC_ROUTER)
-       server->stat.cell_clients++;
+      server->stat.cell_clients++;
 
       /* Get connection parameters */
       if (conn->param) {
@@ -2492,7 +2501,7 @@ void silc_server_free_client_data(SilcServer server,
   /* Update statistics */
   server->stat.my_clients--;
   server->stat.clients--;
-  if (server->server_type == SILC_ROUTER)
+  if (server->stat.cell_clients)
     server->stat.cell_clients--;
   SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
   SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -4207,3 +4216,30 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     silc_ske_free(ctx->ske);
   silc_free(ctx);
 }
+
+/* Task callback used to retrieve network statistical information from
+   router server once in a while. */
+
+SILC_TASK_CALLBACK(silc_server_get_stats)
+{
+  SilcServer server = (SilcServer)context;
+  SilcBuffer idp, packet;
+
+  SILC_LOG_DEBUG(("Retrieving stats from router"));
+
+  if (!server->standalone) {
+    idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
+                                           ++server->cmd_ident, 1,
+                                           1, idp->data, idp->len);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, 0, packet->data,
+                           packet->len, FALSE);
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
+  }
+
+  silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
+                        server, 120, 0, SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_LOW);
+}
index f84566fc2f12e617ea69977b562bb4be80dcf991..7a6a9253c6bcb7b02b23a03696bdea81cc64ef09 100644 (file)
@@ -69,6 +69,7 @@ struct SilcServerStruct {
   SilcUInt32 id_string_len;
   SilcIdType id_type;
 
+  SilcUInt32 starttime;
   bool standalone;                  /* TRUE if server is standalone, and
                                        does not have connection to network. */
   bool listenning;                  /* TRUE if server is listenning for
index 01870b9593dd545d81e6c7f0d18937bc3177c2f8..5e9bdbd7c41d6b9db8c8f74ad6d4e0f85a6b8f66 100644 (file)
@@ -216,7 +216,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
 
        /* Update statistics */
        server->stat.clients--;
-       if (server->server_type == SILC_ROUTER)
+       if (server->stat.cell_clients)
          server->stat.cell_clients--;
        SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
        SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -280,7 +280,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
 
        /* Update statistics */
        server->stat.clients--;
-       if (server->server_type == SILC_ROUTER)
+       if (server->stat.cell_clients)
          server->stat.cell_clients--;
        SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
        SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
index b5d038771e695ddac2e6304fb7200fae90d7e919..6bf956d6aa8406034bbb095aa1dd7ea0d99172e5 100644 (file)
@@ -709,7 +709,59 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SERVER_ID
 
 
-   11   <deprecated command>
+   11   SILC_COMMAND_STATS
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used to fetch various statistical information
+        from the server indicated by <Server ID>, which is the ID of
+        server where sender is connected to.  Server receiving this
+        command MAY also send this further to its router for fetching
+        other cell and network wide statistics to accompany the reply.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>          (2) <Server ID>
+                        (3) [<statistics structure>]
+
+        This command replies with the Server ID of the server and 
+        optional statistics structure which includes 32 bit MSB first
+        ordered integer values to represent various statistical
+        information.  The structure is as follows:
+
+          starttime      - time when server was started
+          uptime         - uptime of the server
+          my clients     - number of locally connected clients
+          my channels    - number of locally created channels
+          my server ops  - number of local server operators
+          my router ops  - number of local router operators
+          cell clients   - number of clients in local cell
+          cell channels  - number of channels in local cell
+          cell servers   - number of servers in local cell
+          clients        - number of client in SILC network
+          channels       - number of channels in SILC network
+          servers        - number of servers in SILC network
+          routers        - number of routers in SILC network
+          server ops     - number of server operators in SILC network
+          router ops     - number of router operators in SILC network
+
+        If some value is unknown it is set to zero (0) value.  The
+        "starttime" is the start time of the server, and is seconds
+        since Epoch (POSIX.1).  The "uptime" is time difference of
+        current time and "starttime" in the server, and is seconds
+        in value.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SERVER_ID
 
 
    12   SILC_COMMAND_PING
index 9c8a5cc6ac89d1c367592899c7e2ce7020640d5c..91bdc933ff9e280f61b5c0ac9a90d99703a15a70 100644 (file)
@@ -1647,12 +1647,12 @@ o Padding (variable length) - The padding that MUST be
   other parts of the packet.
 
 o MAC (variable length) - The MAC computed from the
-  Message Length, Message Data, Padding Length and Padding
-  fields.  This protects the integrity of the plaintext
-  channel message.  The receiver can verify from the MAC
-  whether the message decrypted correctly.  Also, if more than
-  one private key has been set for the channel, the receiver
-  can verify which of the keys decrypted the message 
+  Message Length, Message Data, Padding Length, Padding and
+  Initial Vector fields.  This protects the integrity of the
+  plaintext channel message.  The receiver can verify from
+  the MAC whether the message decrypted correctly.  Also, if
+  more than one private key has been set for the channel, the
+  receiver can verify which of the keys decrypted the message 
   correctly.  Note that, this field is encrypted and MUST
   be added to the padding calculation.
 
index 797b464e8deaba7ce547ae69c48c4285238bd04c..80182f5a9240f65a60a1c492956027929af6ef24 100644 (file)
@@ -306,7 +306,7 @@ void silc_client_notify_by_server(SilcClient client,
 
     /* Some client implementations actually quit network by first doing
        LEAVE and then immediately SIGNOFF.  We'll check for this by doing 
-       check for the client after 5 - 14 seconds.  If it is not valid after
+       check for the client after 5 - 34 seconds.  If it is not valid after
        that we'll remove the client from cache. */
     if (!silc_hash_table_count(client_entry->channels)) {
       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
@@ -314,7 +314,7 @@ void silc_client_notify_by_server(SilcClient client,
       res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
       silc_schedule_task_add(client->schedule, 0,
                             silc_client_notify_check_client, conn,
-                            (5 + (silc_rng_get_rn16(client->rng) % 9)),
+                            (5 + (silc_rng_get_rn16(client->rng) % 29)),
                             0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     }
 
index 289b19178b1de78a61f9cc85862c026fe6c6b2d1..616b2d86d950cc0b57617c1c5910c7ead070d2d7 100644 (file)
@@ -615,19 +615,53 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
 SILC_CLIENT_CMD_REPLY_FUNC(list)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   unsigned char *tmp, *name, *topic;
-  SilcUInt32 usercount = 0;
+  SilcUInt32 usercount = 0, len;
+  SilcChannelID *channel_id = NULL;
+  SilcChannelEntry channel_entry;
 
   COMMAND_CHECK_STATUS_LIST;
 
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+  if (!channel_id) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+  if (!name) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
   if (tmp)
     SILC_GET32_MSB(usercount, tmp);
 
+  /* Check whether the channel exists, and add it to cache if it doesn't. */
+  channel_entry = silc_client_get_channel_by_id(cmd->client, conn, 
+                                               channel_id);
+  if (!channel_entry) {
+    /* Add new channel entry */
+    channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
+                                           channel_id);
+    if (!channel_entry) {
+      COMMAND_REPLY_ERROR;
+      goto out;
+    }
+    channel_id = NULL;
+  }
+
   /* Notify application */
-  COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
+  COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
 
   /* Pending callbacks are not executed if this was an list entry */
   if (cmd->status != SILC_STATUS_OK &&
@@ -637,6 +671,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(list)
   }
 
  out:
+  silc_free(channel_id);
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
   silc_client_command_reply_free(cmd);
 }
index 2a853548826575e08387eabd0d4c843de3ae7320..2bd7eb6fce3351cb8fbee08cc26a0856ba4d7619 100644 (file)
@@ -299,7 +299,10 @@ bool silc_channel_message_payload_decrypt(unsigned char *data,
 
     /* Check the MAC of the message */
     SILC_LOG_DEBUG(("Checking channel message MACs"));
-    silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
+    silc_hmac_init(hmac);
+    silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
+    silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
+    silc_hmac_final(hmac, mac2, &mac_len);
     if (memcmp(mac, mac2, mac_len)) {
       SILC_LOG_DEBUG(("Channel message MACs does not match"));
       silc_free(dst);
@@ -395,7 +398,10 @@ bool silc_channel_message_payload_encrypt(unsigned char *data,
   SilcBufferStruct buf;
 
   /* Compute the MAC of the channel message data */
-  silc_hmac_make(hmac, data, data_len, mac, &mac_len);
+  silc_hmac_init(hmac);
+  silc_hmac_update(hmac, data, data_len);
+  silc_hmac_update(hmac, iv, iv_len);
+  silc_hmac_final(hmac, mac, &mac_len);
 
   /* Put rest of the data to the payload */
   silc_buffer_set(&buf, data, true_len);
index 4e84bd5b8c158d372419f72575ac4991b75030df..d1888553cc9c4d594ccf9f97237a2c2011a2abb8 100644 (file)
@@ -134,6 +134,7 @@ typedef unsigned char SilcCommand;
 #define SILC_COMMAND_QUIT              8
 #define SILC_COMMAND_KILL              9
 #define SILC_COMMAND_INFO              10
+#define SILC_COMMAND_STATS             11
 #define SILC_COMMAND_PING              12
 #define SILC_COMMAND_OPER              13
 #define SILC_COMMAND_JOIN              14
index 4694104599e0ad2afe2586cf8cceb6c72bd3d190..756d505d52f78f536c822ee02494d2839aa5c159 100644 (file)
@@ -81,6 +81,7 @@ void silc_ske_free(SilcSKE ske)
       silc_ske_payload_ke_free(ske->ke1_payload);
     if (ske->ke2_payload)
       silc_ske_payload_ke_free(ske->ke2_payload);
+    silc_free(ske->remote_version);
 
     /* Free rest */
     if (ske->prop) {
@@ -1216,6 +1217,8 @@ silc_ske_select_security_properties(SilcSKE ske,
     }
   }
 
+  ske->remote_version = silc_memdup(rp->version, rp->version_len);
+
   /* Flags are returned unchanged. */
   payload->flags = rp->flags;
 
@@ -2006,7 +2009,7 @@ bool silc_ske_parse_version(SilcSKE ske,
                            char **software_version_string,
                            char **vendor_version)
 {
-  return silc_parse_version_string(ske->start_payload->version,
+  return silc_parse_version_string(ske->remote_version,
                                   protocol_version, 
                                   protocol_version_string, 
                                   software_version,
index 7d0aab9e82543def58db09c3ab366d3774654ca0..4db724bf630713908e9dc721a434a24d263afb2f 100644 (file)
@@ -335,6 +335,7 @@ struct SilcSKEStruct {
   SilcSKEStartPayload *start_payload;
   SilcSKEKEPayload *ke1_payload;
   SilcSKEKEPayload *ke2_payload;
+  unsigned char *remote_version;
 
   /* Temporary copy of the KE Start Payload used in the
      HASH computation. */