5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
23 #include "silcserver.h"
24 #include "server_internal.h"
26 /* XXX locking missing from routines! */
28 /************************ Static utility functions **************************/
30 /* Foreach callbcak to free all users from the channel when deleting a
33 static void silc_server_del_channel_foreach(void *key, void *context,
36 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
38 SILC_LOG_DEBUG(("Removing client %s from channel %s",
39 chl->client->nickname ? chl->client->nickname :
40 (unsigned char *)"", chl->channel->channel_name));
42 /* Remove the context from the client's channel hash table as that
43 table and channel's user_list hash table share this same context. */
44 silc_hash_table_del(chl->client->channels, chl->channel);
49 /****************************** Server entry ********************************/
51 void silc_server_destructor_server(SilcIDCache cache,
52 const SilcIDCacheEntry entry,
53 void *destructor_context,
59 /* Adds new server entry to server */
61 SilcServerEntry silc_server_add_server(SilcServer server,
62 const char *server_name,
63 SilcServerType server_type,
65 SilcPacketStream origin)
67 SilcServerEntry entry;
68 char *server_namec = NULL;
73 entry = silc_calloc(1, sizeof(*entry));
77 SILC_LOG_DEBUG(("Adding server entry %p %s", entry,
78 silc_id_render(id, SILC_ID_SERVER)));
80 /* Normalize name. This is cached, original is in server context. */
82 server_namec = silc_identifier_check(server_name, strlen(server_name),
83 SILC_STRING_UTF8, 256, NULL);
89 entry->server_name = strdup(server_name);
90 if (!server->server_name) {
91 silc_free(server_namec);
97 entry->server_type = server_type;
99 entry->stream = origin;
102 if (!silc_idcache_add(server->servers, server_namec, &entry->id,
104 silc_free(server_namec);
105 silc_free(entry->server_name);
110 /* Take reference of the packet stream */
111 silc_packet_stream_ref(origin);
116 /* Delete server entry */
118 SilcBool silc_server_del_server(SilcServer server, SilcServerEntry entry)
120 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
121 entry->server_name : "??", &entry->id ?
122 silc_id_render(&entry->id, SILC_ID_SERVER) : "??"));
125 if (!silc_idcache_del_by_context(server->servers, entry, NULL)) {
126 SILC_LOG_ERROR(("Unknown server %s, could not delete from cache",
127 &entry->id ? silc_id_render(&entry->id, SILC_ID_SERVER) :
135 /* Find server by Server ID */
138 silc_server_find_server_by_id(SilcServer server,
141 SilcIDCacheEntry *ret_entry)
143 SilcIDCacheEntry id_cache = NULL;
144 SilcServerEntry entry;
149 SILC_LOG_DEBUG(("Find Server ID (%s)",
150 silc_id_render(id, SILC_ID_SERVER)));
152 if (!silc_idcache_find_by_id_one(server->servers, (void *)id,
156 entry = id_cache->context;
158 if (entry && registered && !(entry->data.registered))
162 *ret_entry = id_cache;
164 SILC_LOG_DEBUG(("Found"));
169 /* Find server by name. The 'name' must be normalized already. */
172 silc_server_find_server_by_name(SilcServer server, char *name,
174 SilcIDCacheEntry *ret_entry)
176 SilcIDCacheEntry id_cache = NULL;
177 SilcServerEntry entry;
179 SILC_LOG_DEBUG(("Find server by name `%s'", name));
181 if (!silc_idcache_find_by_name_one(server->servers, name, &id_cache))
184 entry = id_cache->context;
186 if (entry && registered && !(entry->data.registered))
190 *ret_entry = id_cache;
192 SILC_LOG_DEBUG(("Found"));
197 /* Find server by connection parameters, hostname and port */
200 silc_server_find_server_by_conn(SilcServer server, char *hostname,
201 int port, SilcBool registered,
202 SilcIDCacheEntry *ret_entry)
204 SilcIDCacheEntry id_cache;
205 SilcServerEntry entry;
211 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
213 if (!silc_idcache_get_all(server->servers, &list))
216 while ((id_cache = silc_list_get(list)) != SILC_LIST_END) {
217 entry = id_cache->context;
218 stream = silc_packet_stream_get_stream(entry->stream);
220 if (entry && registered && !(entry->data.registered))
223 if (silc_socket_stream_get_info(stream, NULL, &h, NULL, &p)) {
224 if (silc_utf8_strcasecmp(hostname, h) && p == port)
232 *ret_entry = id_cache;
234 SILC_LOG_DEBUG(("Found"));
239 /* Replaces old Server ID with new one */
242 silc_server_replace_server_id(SilcServer server, SilcServerID *old_id,
243 SilcServerID *new_id)
245 SilcIDCacheEntry id_cache = NULL;
247 if (!old_id || !new_id)
250 SILC_LOG_DEBUG(("Replacing Server ID %s",
251 silc_id_render(old_id, SILC_ID_SERVER)));
252 SILC_LOG_DEBUG(("New Server ID %s",
253 silc_id_render(new_id, SILC_ID_SERVER)));
255 if (!silc_idcache_find_by_id_one(server->servers, old_id, &id_cache))
257 if (!silc_idcache_update(server->servers, id_cache, old_id, new_id,
259 SILC_LOG_ERROR(("Error updating Server ID"));
263 SILC_LOG_DEBUG(("Replaced"));
265 return id_cache->context;
269 /****************************** Client entry ********************************/
271 void silc_server_destructor_client(SilcIDCache cache,
272 const SilcIDCacheEntry entry,
273 void *destructor_context,
279 /* Adds new client to server */
281 SilcClientEntry silc_server_add_client(SilcServer server,
282 const char *nickname,
283 const char *username,
284 const char *userinfo,
287 SilcPacketStream origin)
289 SilcClientEntry client;
290 char *nicknamec = NULL;
294 if (!id || !origin || !nickname || !username)
297 client = silc_calloc(1, sizeof(*client));
301 SILC_LOG_DEBUG(("Adding client entry %p", client));
303 /* Normalize name. This is cached, original is in client context. */
304 nicknamec = silc_identifier_check(nickname, strlen(nickname),
305 SILC_STRING_UTF8, 128, NULL);
310 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
313 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
316 !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256))
319 client->nickname = strdup(nickname);
320 if (!client->nickname)
323 client->username = strdup(username);
324 if (!client->username)
327 client->userinfo = userinfo ? strdup(userinfo) : NULL;
328 if (!client->userinfo)
333 client->stream = origin;
335 client->channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL,
336 NULL, NULL, NULL, NULL, TRUE);
337 if (!client->channels)
340 if (!silc_idcache_add(server->clients, nicknamec, (void *)&client->id,
344 /* Take reference of the packet stream */
345 silc_packet_stream_ref(origin);
350 if (client->channels)
351 silc_hash_table_free(client->channels);
352 silc_free(client->nickname);
353 silc_free(client->username);
354 silc_free(client->userinfo);
356 silc_free(nicknamec);
360 /* Delete client entry */
362 SilcBool silc_server_del_client(SilcServer server, SilcClientEntry entry)
364 SILC_LOG_DEBUG(("Deleting client %s id %s", entry->nickname ?
365 entry->nickname : (unsigned char *)"??", &entry->id ?
366 silc_id_render(&entry->id, SILC_ID_CLIENT) : "??"));
369 if (!silc_idcache_del_by_context(server->clients, entry, NULL)) {
370 SILC_LOG_ERROR(("Unknown client %s, could not delete from cache",
371 &entry->id ? silc_id_render(&entry->id, SILC_ID_CLIENT) :
379 /* Finds all clients matching the nickanem `nickname'. Returns list of
380 SilcIDCacheEntry entries. The `nickname' must be normalized. */
382 SilcBool silc_server_find_clients(SilcServer server, char *nickname,
385 SilcClientID client_id;
386 unsigned char hash[16];
388 SILC_LOG_DEBUG(("Find clients named %s", nickname));
390 /* Find using Client ID hash, as Client ID is based on the nickname,
391 we can find clients quickly using the hash of the nickname. */
392 memset(&client_id, 0, sizeof(client_id));
393 silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
394 memcpy(client_id.hash, hash, CLIENTID_HASH_LEN);
396 if (!silc_idcache_find_by_id(server->clients, &client_id, list))
399 SILC_LOG_DEBUG(("Found %d clients", silc_list_count(*list)));
404 /* Finds client by Client ID */
406 SilcClientEntry silc_server_find_client_by_id(SilcServer server,
409 SilcIDCacheEntry *ret_entry)
411 SilcIDCacheEntry id_cache = NULL;
412 SilcClientEntry client;
417 SILC_LOG_DEBUG(("Client ID (%s)", silc_id_render(id, SILC_ID_CLIENT)));
419 if (!silc_idcache_find_by_id_one(server->clients, (void *)id, &id_cache))
422 client = id_cache->context;
424 if (client && registered && !(client->data.registered))
428 *ret_entry = id_cache;
430 SILC_LOG_DEBUG(("Found"));
435 /* Replaces old Client ID with new one */
438 silc_server_replace_client_id(SilcServer server, SilcClientID *old_id,
439 SilcClientID *new_id, const char *nickname)
441 SilcIDCacheEntry id_cache = NULL;
442 SilcClientEntry entry;
443 char *name, *nicknamec = NULL;
445 if (!old_id || !new_id)
448 SILC_LOG_DEBUG(("Replacing Client ID %s",
449 silc_id_render(old_id, SILC_ID_CLIENT)));
450 SILC_LOG_DEBUG(("New Client ID %s",
451 silc_id_render(new_id, SILC_ID_CLIENT)));
453 /* Normalize name. This is cached, original is in client context. */
455 nicknamec = silc_identifier_check(nickname, strlen(nickname),
456 SILC_STRING_UTF8, 128, NULL);
461 if (!silc_idcache_find_by_id_one(server->clients, old_id, &id_cache))
463 entry = id_cache->context;
464 name = id_cache->name;
465 if (!silc_idcache_update(server->clients, id_cache, old_id, new_id,
467 SILC_LOG_ERROR(("Error updating Client ID"));
473 /* Check if anyone is watching old nickname */
474 if (server->server_type == SILC_ROUTER)
475 silc_server_check_watcher_list(server, entry, nickname,
476 SILC_NOTIFY_TYPE_NICK_CHANGE);
478 silc_free(entry->nickname);
479 entry->nickname = nickname ? strdup(nickname) : NULL;
481 /* Check if anyone is watching new nickname */
482 if (server->server_type == SILC_ROUTER)
483 silc_server_check_watcher_list(server, entry, nickname,
484 SILC_NOTIFY_TYPE_NICK_CHANGE);
486 SILC_LOG_DEBUG(("Replaced"));
492 /****************************** Channel entry *******************************/
494 void silc_server_destructor_channel(SilcIDCache cache,
495 const SilcIDCacheEntry entry,
496 void *destructor_context,
502 /* Add new channel */
504 SilcChannelEntry silc_server_add_channel(SilcServer server,
505 const char *channel_name,
508 SilcPacketStream origin,
509 SilcCipher channel_key,
512 SilcChannelEntry channel;
513 char *channel_namec = NULL;
515 if (!id || !channel_key || !hmac)
518 channel = silc_calloc(1, sizeof(*channel));
522 SILC_LOG_DEBUG(("Adding new channel %s %p", channel_name, channel));
524 /* Normalize name. This is cached, original is in client context. */
526 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
527 SILC_STRING_UTF8, 256, NULL);
528 if (!channel_namec) {
534 channel->channel_name = channel_name ? strdup(channel_name) : NULL;
537 silc_free(channel_namec);
541 channel->mode = mode;
543 channel->channel_key = channel_key;
544 channel->hmac = hmac;
545 channel->router = origin;
547 channel->user_list = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
548 NULL, NULL, NULL, TRUE);
549 if (!channel->user_list) {
550 silc_cipher_free(channel->channel_key);
551 silc_hmac_free(channel->hmac);
552 silc_free(channel->channel_name);
554 silc_free(channel_namec);
558 if (!silc_idcache_add(server->channels, channel_namec,
559 (void *)&channel->id, (void *)channel)) {
560 silc_cipher_free(channel->channel_key);
561 silc_hmac_free(channel->hmac);
562 silc_free(channel->channel_name);
563 silc_hash_table_free(channel->user_list);
565 silc_free(channel_namec);
569 /* Take reference of the packet stream */
570 silc_packet_stream_ref(origin);
575 /* Free channel entry. This free's everything. */
577 SilcBool silc_server_del_channel(SilcServer server, SilcChannelEntry entry)
579 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
581 /* Remove from cache */
582 if (!silc_idcache_del_by_context(server->channels, entry, NULL)) {
583 SILC_LOG_DEBUG(("Unknown channel %s, did not delete",
584 entry->channel_name));
591 /* Finds channel by channel name. Channel names are unique and they
592 are not case-sensitive. The 'name' must be normalized already. */
594 SilcChannelEntry silc_server_find_channel_by_name(SilcServer server,
596 SilcIDCacheEntry *ret_entry)
598 SilcIDCacheEntry id_cache = NULL;
600 SILC_LOG_DEBUG(("Channel by name %s", name));
602 if (!silc_idcache_find_by_name_one(server->channels, (char *)name,
607 *ret_entry = id_cache;
609 SILC_LOG_DEBUG(("Found"));
611 return id_cache->context;
614 /* Finds channel by Channel ID. */
616 SilcChannelEntry silc_server_find_channel_by_id(SilcServer server,
618 SilcIDCacheEntry *ret_entry)
620 SilcIDCacheEntry id_cache = NULL;
625 SILC_LOG_DEBUG(("Channel ID (%s)", silc_id_render(id, SILC_ID_CHANNEL)));
627 if (!silc_idcache_find_by_id_one(server->channels, (void *)id, &id_cache))
631 *ret_entry = id_cache;
633 SILC_LOG_DEBUG(("Found"));
635 return id_cache->context;
638 /* Replaces old Channel ID with new one. This is done when router forces
639 normal server to change Channel ID. */
641 SilcChannelEntry silc_server_replace_channel_id(SilcServer server,
642 SilcChannelID *old_id,
643 SilcChannelID *new_id)
645 SilcIDCacheEntry id_cache = NULL;
647 if (!old_id || !new_id)
650 SILC_LOG_DEBUG(("Replacing Channel ID %s",
651 silc_id_render(old_id, SILC_ID_CHANNEL)));
652 SILC_LOG_DEBUG(("New Channel ID %s",
653 silc_id_render(new_id, SILC_ID_CHANNEL)));
655 if (!silc_idcache_find_by_id_one(server->channels, old_id, &id_cache))
657 if (!silc_idcache_update(server->channels, id_cache, old_id, new_id,
659 SILC_LOG_ERROR(("Error updating Channel ID"));
663 SILC_LOG_DEBUG(("Replaced"));
665 return id_cache->context;
668 /* Returns channels from the ID list. If the `channel_id' is NULL then
669 all channels are returned. Returns list of SilcIDCacheEntry entries. */
671 SilcBool silc_server_get_channels(SilcServer server,
672 SilcChannelID *channel_id,
675 SILC_LOG_DEBUG(("Start"));
678 if (!silc_idcache_get_all(server->channels, list))
681 if (!silc_idcache_find_by_id(server->channels, channel_id, list))