X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_entry.c;h=c950bfb283ee032029b1663d0419d383a783b986;hp=488acfd3b804e5cb016073fe35b47e37b6fadfd8;hb=1598b3a51b51a434037461ccd35487bc0df3137c;hpb=665ee4a1f1571804376f9be28363ad5d9e91ff7f diff --git a/lib/silcclient/client_entry.c b/lib/silcclient/client_entry.c index 488acfd3..c950bfb2 100644 --- a/lib/silcclient/client_entry.c +++ b/lib/silcclient/client_entry.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2007 Pekka Riikonen + Copyright (C) 2001 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -791,7 +791,8 @@ SilcClientEntry silc_client_add_client(SilcClient client, return NULL; silc_rwlock_alloc(&client_entry->internal.lock); - silc_atomic_init8(&client_entry->internal.refcnt, 0); + silc_atomic_init32(&client_entry->internal.refcnt, 0); + silc_atomic_init32(&client_entry->internal.deleted, 1); client_entry->id = *id; client_entry->mode = mode; client_entry->realname = userinfo ? strdup(userinfo) : NULL; @@ -800,10 +801,10 @@ SilcClientEntry silc_client_add_client(SilcClient client, client_entry->server, sizeof(client_entry->server)); if (nickname && client->internal->params->full_nicknames) silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), - nickname); + "%s", nickname); else if (nickname) silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), - parsed); + "%s", parsed); silc_parse_userfqdn(username, client_entry->username, sizeof(client_entry->username), @@ -814,6 +815,9 @@ SilcClientEntry silc_client_add_client(SilcClient client, NULL, NULL, NULL, TRUE); if (!client_entry->channels) { silc_free(client_entry->realname); + silc_atomic_uninit32(&client_entry->internal.deleted); + silc_atomic_uninit32(&client_entry->internal.refcnt); + silc_rwlock_free(client_entry->internal.lock); silc_free(client_entry); return NULL; } @@ -823,8 +827,11 @@ SilcClientEntry silc_client_add_client(SilcClient client, nick = silc_identifier_check(parsed, strlen(parsed), SILC_STRING_UTF8, 128, NULL); if (!nick) { - silc_free(client_entry->realname); silc_hash_table_free(client_entry->channels); + silc_free(client_entry->realname); + silc_atomic_uninit32(&client_entry->internal.deleted); + silc_atomic_uninit32(&client_entry->internal.refcnt); + silc_rwlock_free(client_entry->internal.lock); silc_free(client_entry); return NULL; } @@ -836,8 +843,11 @@ SilcClientEntry silc_client_add_client(SilcClient client, if (!silc_idcache_add(conn->internal->client_cache, nick, &client_entry->id, client_entry)) { silc_free(nick); - silc_free(client_entry->realname); silc_hash_table_free(client_entry->channels); + silc_free(client_entry->realname); + silc_atomic_uninit32(&client_entry->internal.deleted); + silc_atomic_uninit32(&client_entry->internal.refcnt); + silc_rwlock_free(client_entry->internal.lock); silc_free(client_entry); silc_mutex_unlock(conn->internal->lock); return NULL; @@ -890,10 +900,10 @@ void silc_client_update_client(SilcClient client, client_entry->server, sizeof(client_entry->server)); if (client->internal->params->full_nicknames) silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), - nickname); + "%s", nickname); else silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), - parsed); + "%s", parsed); /* Normalize nickname */ nick = silc_identifier_check(parsed, strlen(parsed), @@ -995,7 +1005,8 @@ void silc_client_del_client_entry(SilcClient client, silc_client_ftp_session_free_client(client, client_entry); if (client_entry->internal.ke) silc_client_abort_key_agreement(client, conn, client_entry); - silc_atomic_uninit8(&client_entry->internal.refcnt); + silc_atomic_uninit32(&client_entry->internal.deleted); + silc_atomic_uninit32(&client_entry->internal.refcnt); silc_rwlock_free(client_entry->internal.lock); silc_free(client_entry); } @@ -1005,30 +1016,18 @@ void silc_client_del_client_entry(SilcClient client, SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { - SilcBool ret; - if (!client_entry) return FALSE; - if (silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) > 0) - return FALSE; - - SILC_LOG_DEBUG(("Deleting client %p", client_entry)); - - silc_mutex_lock(conn->internal->lock); - ret = silc_idcache_del_by_context(conn->internal->client_cache, - client_entry, NULL); - silc_mutex_unlock(conn->internal->lock); - - if (ret) { - /* Remove from channels */ - silc_client_remove_from_channels(client, conn, client_entry); + SILC_LOG_DEBUG(("Marking client entry %p deleted", client_entry)); - /* Free the client entry data */ - silc_client_del_client_entry(client, conn, client_entry); + if (silc_atomic_sub_int32(&client_entry->internal.deleted, 1) != 0) { + SILC_LOG_DEBUG(("Client entry %p already marked deleted", client_entry)); + return FALSE; } - return ret; + silc_client_unref_client(client, conn, client_entry); + return TRUE; } /* Internal routine used to find client by ID and if not found this creates @@ -1072,10 +1071,10 @@ SilcClientEntry silc_client_ref_client(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { - silc_atomic_add_int8(&client_entry->internal.refcnt, 1); + silc_atomic_add_int32(&client_entry->internal.refcnt, 1); SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry, - silc_atomic_get_int8(&client_entry->internal.refcnt) - 1, - silc_atomic_get_int8(&client_entry->internal.refcnt))); + silc_atomic_get_int32(&client_entry->internal.refcnt) - 1, + silc_atomic_get_int32(&client_entry->internal.refcnt))); return client_entry; } @@ -1084,11 +1083,32 @@ SilcClientEntry silc_client_ref_client(SilcClient client, void silc_client_unref_client(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { - if (client_entry) { - SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry, - silc_atomic_get_int8(&client_entry->internal.refcnt), - silc_atomic_get_int8(&client_entry->internal.refcnt) - 1)); - silc_client_del_client(client, conn, client_entry); + SilcBool ret; + + if (!client_entry) + return; + + SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry, + silc_atomic_get_int32(&client_entry->internal.refcnt), + silc_atomic_get_int32(&client_entry->internal.refcnt) - 1)); + + if (silc_atomic_sub_int32(&client_entry->internal.refcnt, 1) > 0) + return; + + SILC_LOG_DEBUG(("Deleting client %p (%d)", client_entry, + silc_atomic_get_int32(&client_entry->internal.deleted))); + + silc_mutex_lock(conn->internal->lock); + ret = silc_idcache_del_by_context(conn->internal->client_cache, + client_entry, NULL); + silc_mutex_unlock(conn->internal->lock); + + if (ret) { + /* Remove from channels */ + silc_client_remove_from_channels(client, conn, client_entry); + + /* Free the client entry data */ + silc_client_del_client_entry(client, conn, client_entry); } } @@ -1186,7 +1206,7 @@ SilcClientEntry silc_client_nickname_format(SilcClient client, return NULL; silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), - cp); + "%s", cp); silc_free(cp); } @@ -1626,7 +1646,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, return NULL; silc_rwlock_alloc(&channel->internal.lock); - silc_atomic_init16(&channel->internal.refcnt, 0); + silc_atomic_init32(&channel->internal.refcnt, 0); + silc_atomic_init32(&channel->internal.deleted, 1); channel->id = *channel_id; channel->mode = mode; @@ -1639,7 +1660,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, if (!channel->channel_name) { silc_rwlock_free(channel->internal.lock); - silc_atomic_uninit16(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.deleted); silc_free(channel); return NULL; } @@ -1648,7 +1670,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, NULL, NULL, NULL, TRUE); if (!channel->user_list) { silc_rwlock_free(channel->internal.lock); - silc_atomic_uninit16(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.deleted); silc_free(channel->channel_name); silc_free(channel); return NULL; @@ -1659,7 +1682,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, SILC_STRING_UTF8, 256, NULL); if (!channel_namec) { silc_rwlock_free(channel->internal.lock); - silc_atomic_uninit16(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.deleted); silc_free(channel->channel_name); silc_hash_table_free(channel->user_list); silc_free(channel); @@ -1672,7 +1696,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, if (!silc_idcache_add(conn->internal->channel_cache, channel_namec, &channel->id, channel)) { silc_rwlock_free(channel->internal.lock); - silc_atomic_uninit16(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.refcnt); + silc_atomic_uninit32(&channel->internal.deleted); silc_free(channel_namec); silc_free(channel->channel_name); silc_hash_table_free(channel->user_list); @@ -1694,67 +1719,18 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel) { - SilcIDCacheEntry id_cache; - SilcBool ret = TRUE; - SilcCipher key; - SilcHmac hmac; - char *namec; - if (!channel) return FALSE; - if (silc_atomic_sub_int16(&channel->internal.refcnt, 1) > 0) - return FALSE; - - SILC_LOG_DEBUG(("Deleting channel %p", channel)); - - silc_mutex_lock(conn->internal->lock); - if (silc_idcache_find_by_context(conn->internal->channel_cache, channel, - &id_cache)) { - namec = id_cache->name; - ret = silc_idcache_del_by_context(conn->internal->channel_cache, - channel, NULL); - silc_free(namec); - } - silc_mutex_unlock(conn->internal->lock); + SILC_LOG_DEBUG(("Marking channel entry %p deleted", channel)); - if (!ret) + if (silc_atomic_sub_int32(&channel->internal.deleted, 1) != 0) { + SILC_LOG_DEBUG(("Channel entry %p already marked deleted", channel)); return FALSE; - - silc_client_empty_channel(client, conn, channel); - silc_hash_table_free(channel->user_list); - silc_free(channel->channel_name); - silc_free(channel->topic); - if (channel->founder_key) - silc_pkcs_public_key_free(channel->founder_key); - if (channel->internal.send_key) - silc_cipher_free(channel->internal.send_key); - if (channel->internal.receive_key) - silc_cipher_free(channel->internal.receive_key); - if (channel->internal.hmac) - silc_hmac_free(channel->internal.hmac); - if (channel->internal.old_channel_keys) { - silc_dlist_start(channel->internal.old_channel_keys); - while ((key = silc_dlist_get(channel->internal.old_channel_keys))) - silc_cipher_free(key); - silc_dlist_uninit(channel->internal.old_channel_keys); - } - if (channel->internal.old_hmacs) { - silc_dlist_start(channel->internal.old_hmacs); - while ((hmac = silc_dlist_get(channel->internal.old_hmacs))) - silc_hmac_free(hmac); - silc_dlist_uninit(channel->internal.old_hmacs); } - if (channel->channel_pubkeys) - silc_argument_list_free(channel->channel_pubkeys, - SILC_ARGUMENT_PUBLIC_KEY); - silc_client_del_channel_private_keys(client, conn, channel); - silc_atomic_uninit16(&channel->internal.refcnt); - silc_rwlock_free(channel->internal.lock); - silc_schedule_task_del_by_context(conn->client->schedule, channel); - silc_free(channel); - return ret; + silc_client_unref_channel(client, conn, channel); + return TRUE; } /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE @@ -1806,10 +1782,10 @@ SilcChannelEntry silc_client_ref_channel(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel_entry) { - silc_atomic_add_int16(&channel_entry->internal.refcnt, 1); + silc_atomic_add_int32(&channel_entry->internal.refcnt, 1); SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry, - silc_atomic_get_int16(&channel_entry->internal.refcnt) - 1, - silc_atomic_get_int16(&channel_entry->internal.refcnt))); + silc_atomic_get_int32(&channel_entry->internal.refcnt) - 1, + silc_atomic_get_int32(&channel_entry->internal.refcnt))); return channel_entry; } @@ -1818,13 +1794,71 @@ SilcChannelEntry silc_client_ref_channel(SilcClient client, void silc_client_unref_channel(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel_entry) { - if (channel_entry) { - SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry, - silc_atomic_get_int16(&channel_entry->internal.refcnt), - silc_atomic_get_int16(&channel_entry->internal.refcnt) - - 1)); - silc_client_del_channel(client, conn, channel_entry); + SilcIDCacheEntry id_cache; + SilcBool ret = TRUE; + SilcCipher key; + SilcHmac hmac; + char *namec; + + if (!channel_entry) + return; + + SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry, + silc_atomic_get_int32(&channel_entry->internal.refcnt), + silc_atomic_get_int32(&channel_entry->internal.refcnt) + - 1)); + + if (silc_atomic_sub_int32(&channel_entry->internal.refcnt, 1) > 0) + return; + + SILC_LOG_DEBUG(("Deleting channel %p", channel_entry)); + + silc_mutex_lock(conn->internal->lock); + if (silc_idcache_find_by_context(conn->internal->channel_cache, channel_entry, + &id_cache)) { + namec = id_cache->name; + ret = silc_idcache_del_by_context(conn->internal->channel_cache, + channel_entry, NULL); + silc_free(namec); + } + silc_mutex_unlock(conn->internal->lock); + + if (!ret) + return; + + silc_client_empty_channel(client, conn, channel_entry); + silc_client_del_channel_private_keys(client, conn, channel_entry); + silc_hash_table_free(channel_entry->user_list); + silc_free(channel_entry->channel_name); + silc_free(channel_entry->topic); + if (channel_entry->founder_key) + silc_pkcs_public_key_free(channel_entry->founder_key); + if (channel_entry->internal.send_key) + silc_cipher_free(channel_entry->internal.send_key); + if (channel_entry->internal.receive_key) + silc_cipher_free(channel_entry->internal.receive_key); + if (channel_entry->internal.hmac) + silc_hmac_free(channel_entry->internal.hmac); + if (channel_entry->internal.old_channel_keys) { + silc_dlist_start(channel_entry->internal.old_channel_keys); + while ((key = silc_dlist_get(channel_entry->internal.old_channel_keys))) + silc_cipher_free(key); + silc_dlist_uninit(channel_entry->internal.old_channel_keys); + } + if (channel_entry->internal.old_hmacs) { + silc_dlist_start(channel_entry->internal.old_hmacs); + while ((hmac = silc_dlist_get(channel_entry->internal.old_hmacs))) + silc_hmac_free(hmac); + silc_dlist_uninit(channel_entry->internal.old_hmacs); } + if (channel_entry->channel_pubkeys) + silc_argument_list_free(channel_entry->channel_pubkeys, + SILC_ARGUMENT_PUBLIC_KEY); + silc_atomic_uninit32(&channel_entry->internal.deleted); + silc_atomic_uninit32(&channel_entry->internal.refcnt); + silc_rwlock_free(channel_entry->internal.lock); + silc_schedule_task_del_by_context(conn->client->schedule, channel_entry); + silc_free(channel_entry); } /* Free channel entry list */ @@ -2059,7 +2093,8 @@ SilcServerEntry silc_client_add_server(SilcClient client, return NULL; silc_rwlock_alloc(&server_entry->internal.lock); - silc_atomic_init8(&server_entry->internal.refcnt, 0); + silc_atomic_init32(&server_entry->internal.refcnt, 0); + silc_atomic_init32(&server_entry->internal.deleted, 1); server_entry->id = *server_id; if (server_name) server_entry->server_name = strdup(server_name); @@ -2073,6 +2108,9 @@ SilcServerEntry silc_client_add_server(SilcClient client, if (!server_namec) { silc_free(server_entry->server_name); silc_free(server_entry->server_info); + silc_atomic_uninit32(&server_entry->internal.deleted); + silc_atomic_uninit32(&server_entry->internal.refcnt); + silc_rwlock_free(server_entry->internal.lock); silc_free(server_entry); return NULL; } @@ -2086,6 +2124,9 @@ SilcServerEntry silc_client_add_server(SilcClient client, silc_free(server_namec); silc_free(server_entry->server_name); silc_free(server_entry->server_info); + silc_atomic_uninit32(&server_entry->internal.deleted); + silc_atomic_uninit32(&server_entry->internal.refcnt); + silc_rwlock_free(server_entry->internal.lock); silc_free(server_entry); silc_mutex_unlock(conn->internal->lock); return NULL; @@ -2104,37 +2145,14 @@ SilcServerEntry silc_client_add_server(SilcClient client, SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn, SilcServerEntry server) { - SilcIDCacheEntry id_cache; - SilcBool ret = TRUE; - char *namec; - if (!server) return FALSE; - if (silc_atomic_sub_int8(&server->internal.refcnt, 1) > 0) + if (silc_atomic_sub_int32(&server->internal.deleted, 1) != 0) return FALSE; - SILC_LOG_DEBUG(("Deleting server %p", server)); - - silc_mutex_lock(conn->internal->lock); - if (silc_idcache_find_by_context(conn->internal->server_cache, server, - &id_cache)) { - namec = id_cache->name; - ret = silc_idcache_del_by_context(conn->internal->server_cache, - server, NULL); - silc_free(namec); - } - silc_mutex_unlock(conn->internal->lock); - - silc_free(server->server_name); - silc_free(server->server_info); - if (server->public_key) - silc_pkcs_public_key_free(server->public_key); - silc_atomic_uninit8(&server->internal.refcnt); - silc_rwlock_free(server->internal.lock); - silc_free(server); - - return ret; + silc_client_unref_server(client, conn, server); + return TRUE; } /* Updates the `server_entry' with the new information sent as argument. */ @@ -2198,10 +2216,10 @@ SilcServerEntry silc_client_ref_server(SilcClient client, SilcClientConnection conn, SilcServerEntry server_entry) { - silc_atomic_add_int8(&server_entry->internal.refcnt, 1); + silc_atomic_add_int32(&server_entry->internal.refcnt, 1); SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry, - silc_atomic_get_int8(&server_entry->internal.refcnt) - 1, - silc_atomic_get_int8(&server_entry->internal.refcnt))); + silc_atomic_get_int32(&server_entry->internal.refcnt) - 1, + silc_atomic_get_int32(&server_entry->internal.refcnt))); return server_entry; } @@ -2210,13 +2228,36 @@ SilcServerEntry silc_client_ref_server(SilcClient client, void silc_client_unref_server(SilcClient client, SilcClientConnection conn, SilcServerEntry server_entry) { - if (server_entry) { - SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry, - silc_atomic_get_int8(&server_entry->internal.refcnt), - silc_atomic_get_int8(&server_entry->internal.refcnt) - - 1)); - silc_client_del_server(client, conn, server_entry); + SilcBool ret; + SilcIDCacheEntry id_cache; + char *namec; + + if (!server_entry) + return; + + if (silc_atomic_sub_int32(&server_entry->internal.refcnt, 1) > 0) + return; + + SILC_LOG_DEBUG(("Deleting server %p", server_entry)); + + silc_mutex_lock(conn->internal->lock); + if (silc_idcache_find_by_context(conn->internal->server_cache, server_entry, + &id_cache)) { + namec = id_cache->name; + ret = silc_idcache_del_by_context(conn->internal->server_cache, + server_entry, NULL); + silc_free(namec); } + silc_mutex_unlock(conn->internal->lock); + + silc_free(server_entry->server_name); + silc_free(server_entry->server_info); + if (server_entry->public_key) + silc_pkcs_public_key_free(server_entry->public_key); + silc_atomic_uninit32(&server_entry->internal.deleted); + silc_atomic_uninit32(&server_entry->internal.refcnt); + silc_rwlock_free(server_entry->internal.lock); + silc_free(server_entry); } /* Free server entry list */