+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
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
}
/******************************************************************************
/* 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);
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;
}
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;
}
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);
+ }
+}
/******************************************************************************
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;
}
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
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,
}
/* 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
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)
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);
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
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;
/* 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. */
/* 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;
}
/* 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;
}
/* 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)
/* 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)
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;
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;
};
/*
/* 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;
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;
}
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;
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;
}
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;
}
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;
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()
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
/* 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,
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);