From 4d58526a59b7310e9e11a2cca02fb955ab1732b4 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 13 Mar 2001 21:33:21 +0000 Subject: [PATCH] updates. --- CHANGES | 24 +++++++++++++ apps/silcd/command.c | 19 ++++++++++- apps/silcd/idlist.c | 30 ++++++++++++++-- apps/silcd/idlist.h | 15 +++----- apps/silcd/server.c | 48 +++++++++++++++++++------- apps/silcd/server.h | 2 +- doc/draft-riikonen-silc-spec-01.nroff | 4 +-- lib/silcclient/client.c | 10 +++--- lib/silcclient/client_prvmsg.c | 2 +- lib/silcclient/command_reply.c | 8 +++-- lib/silccore/idcache.c | 49 +++++++++++++++++++++++---- lib/silccore/idcache.h | 19 ++++++++--- 12 files changed, 179 insertions(+), 51 deletions(-) diff --git a/CHANGES b/CHANGES index 7a1abd34..b0cd2093 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,27 @@ +Tue Mar 13 22:17:34 EET 2001 Pekka Riikonen + + * 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 * Added support to the server to enforce that commands are not diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 0202f597..985b8d49 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -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); diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 5bb09466..86b60317 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -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; } diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index d018bd10..e05bcbda 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -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, diff --git a/apps/silcd/server.c b/apps/silcd/server.c index d680e964..849fc10b 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -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) diff --git a/apps/silcd/server.h b/apps/silcd/server.h index ce1194cb..296c35cc 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -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); diff --git a/doc/draft-riikonen-silc-spec-01.nroff b/doc/draft-riikonen-silc-spec-01.nroff index e1ad3e51..b587e55d 100644 --- a/doc/draft-riikonen-silc-spec-01.nroff +++ b/doc/draft-riikonen-silc-spec-01.nroff @@ -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) (2) [@] - (3) + (3) (4) [] This command may reply with several command reply messages to form a list of results. In this case the status payload will include diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 1e9d13e0..ed9bc13a 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -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; } diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 4752b2f3..3fe00aaf 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -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; } diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index f05b9eca..c4861a8a 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -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; diff --git a/lib/silccore/idcache.c b/lib/silccore/idcache.c index b35d23bf..6c836514 100644 --- a/lib/silccore/idcache.c +++ b/lib/silccore/idcache.c @@ -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() diff --git a/lib/silccore/idcache.h b/lib/silccore/idcache.h index 9421caf0..492ecfb7 100644 --- a/lib/silccore/idcache.h +++ b/lib/silccore/idcache.h @@ -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); -- 2.24.0