updates.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 13 Mar 2001 21:33:21 +0000 (21:33 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 13 Mar 2001 21:33:21 +0000 (21:33 +0000)
12 files changed:
CHANGES
apps/silcd/command.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/server.c
apps/silcd/server.h
doc/draft-riikonen-silc-spec-01.nroff
lib/silcclient/client.c
lib/silcclient/client_prvmsg.c
lib/silcclient/command_reply.c
lib/silccore/idcache.c
lib/silccore/idcache.h

diff --git a/CHANGES b/CHANGES
index 7a1abd34ac735552904f294a85b696bde3b186bd..b0cd20936ed1797ee15050626de9bbfa060343fa 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,27 @@
+Tue Mar 13 22:17:34 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added new argument to the WHOWAS command reply, the real name.
+         It is an optional argument.  Updated the protocol specs.
+
+       * Added SilcIDCacheDestructor callback that is registered when
+         the SilcIDCache is allocated.  The callback is called when
+         an cache entry in the ID Cache expires, or is purged from the
+         cache.  Added into lib/silccore/idcache.[ch].
+
+         Added silc_idlist_client_destructor to the silcd/idlist.[ch]
+         to destruct the client entries when the cache entry expires.
+         Other ID Cache's in server and in the client library ignores
+         the destructor.
+
+       * If the ID Cache entry's `expire' field is zero then the entry
+         never expires.  Added boolean `expire' argument to the
+         silc_idcache_add function in the lib/silccore/idcache.[ch].
+         If it is TRUE the default expiry value is used.
+
+       * Added silc_server_free_client_data_timeout that is registered
+         when client disconnects.  By default for 5 minutes we preserve
+         the client entry for history - for WHOWAS command.
+
 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
index 0202f59752c5146c675cf50f360584188d24b42b..985b8d4996eb875038bb34ba27ce49b396b788a2 100644 (file)
@@ -903,8 +903,25 @@ SILC_SERVER_CMD_FUNC(whois)
     silc_server_command_free(cmd);
 }
 
+/* Server side of command WHOWAS. */
+
 SILC_SERVER_CMD_FUNC(whowas)
 {
+#if 0
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  int ret = 0;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
+
+  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+    ret = silc_server_command_whois_from_client(cmd);
+  else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
+          (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
+    ret = silc_server_command_whois_from_server(cmd);
+
+  if (!ret)
+    silc_server_command_free(cmd);
+#endif
 }
 
 /******************************************************************************
@@ -1394,7 +1411,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Update client cache */
   silc_idcache_add(server->local_list->clients, client->nickname, 
-                  SILC_ID_CLIENT, client->id, (void *)client, TRUE);
+                  SILC_ID_CLIENT, client->id, (void *)client, TRUE, FALSE);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
index 5bb09466cde28b3c8c0624b484a15a94504ee804..86b603179b036ce579ec3329c0d1f5b8dff85fff 100644 (file)
@@ -96,7 +96,7 @@ silc_idlist_add_server(SilcIDList id_list,
   server->connection = connection;
 
   if (!silc_idcache_add(id_list->servers, server->server_name, SILC_ID_SERVER,
-                       (void *)server->id, (void *)server, TRUE)) {
+                       (void *)server->id, (void *)server, TRUE, FALSE)) {
     silc_free(server);
     return NULL;
   }
@@ -282,7 +282,7 @@ silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
                 client_list);
 
   if (!silc_idcache_add(id_list->clients, nickname, SILC_ID_CLIENT,
-                       (void *)client->id, (void *)client, TRUE)) {
+                       (void *)client->id, (void *)client, TRUE, FALSE)) {
     silc_free(client);
     return NULL;
   }
@@ -548,6 +548,30 @@ silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
   return client;
 }
 
+/* Client cache entry destructor that is called when the cache is purged. */
+
+void silc_idlist_client_destructor(SilcIDCache cache,
+                                  SilcIDCacheEntry entry)
+{
+  SilcClientEntry client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  client = (SilcClientEntry)entry->context;
+  if (client) {
+    if (client->nickname)
+      silc_free(client->nickname);
+    if (client->username)
+      silc_free(client->username);
+    if (client->userinfo)
+      silc_free(client->userinfo);
+    if (client->id)
+      silc_free(client->id);
+
+    memset(client, 'F', sizeof(*client));
+    silc_free(client);
+  }
+}
 
 /******************************************************************************
 
@@ -583,7 +607,7 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
 
   if (!silc_idcache_add(id_list->channels, channel->channel_name, 
                        SILC_ID_CHANNEL, (void *)channel->id, 
-                       (void *)channel, TRUE)) {
+                       (void *)channel, TRUE, FALSE)) {
     silc_free(channel);
     return NULL;
   }
index d018bd10b6d29c5b52013b140f0614244a5cdc54..e05bcbdab834b225b1148c9c6be526d6c5708856 100644 (file)
@@ -247,18 +247,9 @@ typedef struct SilcChannelClientEntryStruct {
        cell this client is coming from. This is used to route messages to 
        this client.
 
-   SilcCipher session_key
+   SilcList channels
 
-       The actual session key established by key exchange protcol between
-       connecting parties. This is used for both encryption and decryption.
-
-   SilcPKCS pkcs
-
-       PKCS of the client. This maybe NULL.
-
-   SilcHmac hmac
-
-       MAC key used to compute MAC's for packets. 
+       List of channels this client has joined.
 
    void *connection
 
@@ -502,6 +493,8 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
 SilcClientEntry
 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
                              SilcClientID *new_id);
+void silc_idlist_client_destructor(SilcIDCache cache,
+                                  SilcIDCacheEntry entry);
 SilcChannelEntry
 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
                        SilcChannelID *id, SilcServerEntry router,
index d680e964bc5bcb206b17012c1498fbc7e8507aae..849fc10bbeaeb085cb4f008d4467ce1ff9b0aedc 100644 (file)
@@ -221,16 +221,18 @@ int silc_server_init(SilcServer server)
   }
 
   /* Initialize ID caches */
-  server->local_list->clients = silc_idcache_alloc(0);
-  server->local_list->servers = silc_idcache_alloc(0);
-  server->local_list->channels = silc_idcache_alloc(0);
+  server->local_list->clients = 
+    silc_idcache_alloc(0, silc_idlist_client_destructor);
+  server->local_list->servers = silc_idcache_alloc(0, NULL);
+  server->local_list->channels = silc_idcache_alloc(0, NULL);
 
   /* These are allocated for normal server as well as these hold some 
      global information that the server has fetched from its router. For 
      router these are used as they are supposed to be used on router. */
-  server->global_list->clients = silc_idcache_alloc(0);
-  server->global_list->servers = silc_idcache_alloc(0);
-  server->global_list->channels = silc_idcache_alloc(0);
+  server->global_list->clients = 
+    silc_idcache_alloc(0, silc_idlist_client_destructor);
+  server->global_list->servers = silc_idcache_alloc(0, NULL);
+  server->global_list->channels = silc_idcache_alloc(0, NULL);
 
   /* Allocate the entire socket list that is used in server. Eventually 
      all connections will have entry in this table (it is a table of 
@@ -1951,27 +1953,49 @@ 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;
+
+  silc_idlist_del_data(i->client);
+  silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
+  silc_free(i);
+}
+
 /* Frees client data and notifies about client's signoff. */
 
 void silc_server_free_client_data(SilcServer server, 
                                  SilcSocketConnection sock,
-                                 SilcClientEntry user_data, char *signoff)
+                                 SilcClientEntry client, char *signoff)
 {
+  FreeClientInternal i = silc_calloc(1, sizeof(*i));
+
   /* Send REMOVE_ID packet to routers. */
   if (!server->standalone && server->router)
     silc_server_send_notify_signoff(server, server->router->connection,
                                    server->server_type == SILC_SERVER ?
-                                   FALSE : TRUE, user_data->id, 
+                                   FALSE : TRUE, client->id, 
                                    SILC_ID_CLIENT_LEN, signoff);
 
   /* Remove client from all channels */
-  silc_server_remove_from_channels(server, sock, user_data, signoff);
+  silc_server_remove_from_channels(server, sock, client, signoff);
 
-  /* XXX must take some info to history before freeing */
+  /* We will not delete the client entry right away. We will take it
+     into history (for WHOWAS command) for 5 minutes */
+  i->server = server;
+  i->client = client;
+  silc_task_register(server->timeout_queue, 0, 
+                    silc_server_free_client_data_timeout,
+                    (void *)i, 300, 0,
+                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  client->data.registered = FALSE;
 
   /* Free the client entry and everything in it */
-  silc_idlist_del_data(user_data);
-  silc_idlist_del_client(server->local_list, user_data);
   server->stat.my_clients--;
   server->stat.clients--;
   if (server->server_type == SILC_ROUTER)
index ce1194cb025f17540a4245fd962e9fdd284a30bc..296c35cc4605029c1afea237fc57c45049d8fec6 100644 (file)
@@ -96,7 +96,7 @@ void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock);
 void silc_server_free_client_data(SilcServer server, 
                                  SilcSocketConnection sock,
-                                 SilcClientEntry user_data, char *signoff);
+                                 SilcClientEntry client, char *signoff);
 void silc_server_free_sock_user_data(SilcServer server, 
                                     SilcSocketConnection sock);
 int silc_server_channel_has_global(SilcChannelEntry channel);
index e1ad3e515c203cc855ebb6e7db3634378a3a3076..b587e55dd02c83b8cc13414ac00294dbe0bc494c 100644 (file)
@@ -1963,9 +1963,9 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  3
+        Max Arguments:  4
             Arguments:  (1) <Status Payload>  (2) <nickname>[@<server>]
-                        (3) <username@host>
+                        (3) <username@host>   (4) [<real name>]
 
         This command may reply with several command reply messages to form
         a list of results.  In this case the status payload will include
index 1e9d13e00420f51833ab1bd384bcda6f7514fadd..ed9bc13a9b200fd09be5387dcd4afa53ac0312a3 100644 (file)
@@ -140,9 +140,9 @@ SilcClientConnection silc_client_add_connection(SilcClient client,
   conn = silc_calloc(1, sizeof(*conn));
 
   /* Initialize ID caches */
-  conn->client_cache = silc_idcache_alloc(0);
-  conn->channel_cache = silc_idcache_alloc(0);
-  conn->server_cache = silc_idcache_alloc(0);
+  conn->client_cache = silc_idcache_alloc(0, NULL);
+  conn->channel_cache = silc_idcache_alloc(0, NULL);
+  conn->server_cache = silc_idcache_alloc(0, NULL);
   conn->client = client;
   conn->remote_host = strdup(hostname);
   conn->remote_port = port;
@@ -1129,7 +1129,7 @@ void silc_client_receive_new_id(SilcClient client,
   
   /* Put it to the ID cache */
   silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
-                  conn->local_id, (void *)conn->local_entry, TRUE);
+                  conn->local_id, (void *)conn->local_entry, TRUE, FALSE);
 
   /* Notify application of successful connection. We do it here now that
      we've received the Client ID and are allowed to send traffic. */
@@ -1162,7 +1162,7 @@ SilcChannelEntry silc_client_new_channel_id(SilcClient client,
 
   /* Put it to the ID cache */
   silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
-                  (void *)channel->id, (void *)channel, TRUE);
+                  (void *)channel->id, (void *)channel, TRUE, FALSE);
 
   return channel;
 }
index 4752b2f380bc4beacc56ebe178c78d5601ea5ef6..3fe00aaf30aa5653dbd9ac2b794ee1fe176bfa9c 100644 (file)
@@ -178,7 +178,7 @@ void silc_client_private_message(SilcClient client,
       /* Save the client to cache */
       silc_idcache_add(conn->client_cache, remote_client->nickname,
                       SILC_ID_CLIENT, remote_client->id, remote_client, 
-                      TRUE);
+                      TRUE, TRUE);
     } else {
       remote_client = (SilcClientEntry)id_cache->context;
     }
index f05b9eca85f7826e9858a47663c367cdc7b6aa5e..c4861a8a95bbd7c7b9a8c42cba59de66ebc1b025 100644 (file)
@@ -251,7 +251,8 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
     
     /* Add client to cache */
     silc_idcache_add(conn->client_cache, client_entry->nickname,
-                    SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
+                    SILC_ID_CLIENT, client_id, (void *)client_entry, 
+                    TRUE, FALSE);
   } else {
     client_entry = (SilcClientEntry)id_cache->context;
     if (client_entry->nickname)
@@ -379,7 +380,8 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
     
     /* Add client to cache */
     silc_idcache_add(conn->client_cache, client_entry->nickname,
-                    SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
+                    SILC_ID_CLIENT, client_id, (void *)client_entry, 
+                    TRUE, FALSE);
   } else {
     client_entry = (SilcClientEntry)id_cache->context;
     if (client_entry->nickname)
@@ -862,7 +864,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
       client_entry = silc_calloc(1, sizeof(*client_entry));
       client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
       silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT, 
-                      client_entry->id, (void *)client_entry, FALSE);
+                      client_entry->id, (void *)client_entry, FALSE, FALSE);
     } else {
       /* Yes, we have it already */
       client_entry = (SilcClientEntry)id_cache->context;
index b35d23bf0d03ec798c5911db681833ec4f4ecd20..6c836514941aeac007b2efe154c57babeb862083 100644 (file)
@@ -61,12 +61,20 @@ static void silc_idcache_list_add(SilcIDCacheList list,
        is to provide faster access to the cache when searching by data.
        This is updated by silc_idcache_add and sorting functions.
 
+   SilcIDCacheDestructor destructor
+
+       Destructor callback that is called when an cache entry expires or is
+       purged from the ID cache. The application must not free cache entry
+       because the library will do it automatically. The appliation, however,
+       is responsible of freeing any data in the entry.
+
 */
 struct SilcIDCacheStruct {
   SilcIDCacheEntry cache;
   unsigned int cache_count;
   int sorted;
   int fast_access[256];
+  SilcIDCacheDestructor destructor;
 };
 
 /* 
@@ -94,7 +102,8 @@ struct SilcIDCacheListStruct {
 /* Allocates new ID cache object. The initial amount of allocated entries
    can be sent as argument. If `count' is 0 the system uses default values. */
 
-SilcIDCache silc_idcache_alloc(unsigned int count)
+SilcIDCache silc_idcache_alloc(unsigned int count,
+                              SilcIDCacheDestructor destructor)
 {
   SilcIDCache cache;
 
@@ -104,6 +113,7 @@ SilcIDCache silc_idcache_alloc(unsigned int count)
   cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
   cache->cache_count = count ? count : 5;
   memset(cache->fast_access, -1, sizeof(cache->fast_access));
+  cache->destructor = destructor;
 
   return cache;
 }
@@ -381,8 +391,8 @@ int silc_idcache_find_by_context(SilcIDCache cache, void *context,
    however, it is not mandatory. */
 
 int silc_idcache_add(SilcIDCache cache, unsigned char *data, 
-                    SilcIdType id_type,
-                    void *id, void *context, int sort)
+                    SilcIdType id_type, void *id, void *context, int sort,
+                    int expire)
 {
   int i;
   unsigned int count;
@@ -412,7 +422,7 @@ int silc_idcache_add(SilcIDCache cache, unsigned char *data,
       c[i].data = data;
       c[i].type = id_type;
       c[i].id = id;
-      c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
+      c[i].expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
       c[i].context = context;
       break;
     }
@@ -427,7 +437,7 @@ int silc_idcache_add(SilcIDCache cache, unsigned char *data,
     c[count].data = data;
     c[count].type = id_type;
     c[count].id = id;
-    c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
+    c[count].expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
     c[count].context = context;
     count += 5;
   }
@@ -511,8 +521,12 @@ int silc_idcache_purge(SilcIDCache cache)
   c = cache->cache;
 
   for (i = 0; i < cache->cache_count; i++) {
-    if (c[i].data && 
-       (c[i].expire == 0 || c[i].expire < curtime)) {
+    if (c[i].data && c[i].expire < curtime) {
+
+      /* Call the destructor */
+      if (cache->destructor)
+       cache->destructor(cache, &c[i]);
+
       c[i].id = NULL;
       c[i].data = NULL;
       c[i].type = 0;
@@ -524,6 +538,27 @@ int silc_idcache_purge(SilcIDCache cache)
   return TRUE;
 }
 
+/* Purges the specific entry by context. */
+
+int silc_idcache_purge_by_context(SilcIDCache cache, void *context)
+{
+  SilcIDCacheEntry entry;
+
+  if (!silc_idcache_find_by_context(cache, context, &entry))
+    return FALSE;
+
+  /* Call the destructor */
+  if (cache->destructor)
+    cache->destructor(cache, entry);
+  
+  entry->id = NULL;
+  entry->data = NULL;
+  entry->type = 0;
+  entry->expire = 0;
+  entry->context = NULL;
+  return TRUE;
+}
+
 /* Allocates ID cache list. */
 
 static SilcIDCacheList silc_idcache_list_alloc()
index 9421caf0a1d0d7c692c585de6c8def099de64380..492ecfb7cd041ea75950d7b3fe07f29729c621f3 100644 (file)
@@ -46,8 +46,8 @@
 
       Time when this cache entry expires.  This is normal time() value
       plus the validity.  Cache entry has expired if current time is
-      more than value in this field, or if this field has been set to
-      zero (0) value.
+      more than value in this field.  If this value is zero (0) the
+      entry never expires.
 
    void *context
 
@@ -68,12 +68,20 @@ typedef struct SilcIDCacheStruct *SilcIDCache;
 /* Forward declaration for ID Cache List */
 typedef struct SilcIDCacheListStruct *SilcIDCacheList;
 
+/* Destructor callback that is called when an cache entry expires or is
+   purged from the ID cache. The application must not free cache entry
+   because the library will do it automatically. The appliation, however,
+   is responsible of freeing any data in the entry. */
+typedef void (*SilcIDCacheDestructor)(SilcIDCache cache,
+                                     SilcIDCacheEntry entry);
+
 #define SILC_ID_CACHE_ANY ((void *)1)
 
 #define SILC_ID_CACHE_EXPIRE 3600
 
 /* Prototypes */
-SilcIDCache silc_idcache_alloc(unsigned int count);
+SilcIDCache silc_idcache_alloc(unsigned int count,
+                              SilcIDCacheDestructor destructor);
 void silc_idcache_free(SilcIDCache cache);
 void silc_idcache_sort_by_data(SilcIDCache cache);
 int silc_idcache_find_by_data(SilcIDCache cache, unsigned char *data, 
@@ -89,13 +97,14 @@ int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type,
 int silc_idcache_find_by_context(SilcIDCache cache, void *context, 
                                 SilcIDCacheEntry *ret);
 int silc_idcache_add(SilcIDCache cache, unsigned char *data, 
-                    SilcIdType id_type,
-                    void *id, void *context, int sort);
+                    SilcIdType id_type, void *id, void *context, int sort,
+                    int expire);
 int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
 int silc_idcache_del_by_data(SilcIDCache cache, unsigned char *data);
 int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id);
 int silc_idcache_del_all(SilcIDCache cache);
 int silc_idcache_purge(SilcIDCache cache);
+int silc_idcache_purge_by_context(SilcIDCache cache, void *context);
 int silc_idcache_list_count(SilcIDCacheList list);
 int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret);
 int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret);