5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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 /************************ Static utility functions **************************/
28 /* Foreach callbcak to free all users from the channel when deleting a
31 static void silc_server_del_channel_foreach(void *key, void *context,
34 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
36 SILC_LOG_DEBUG(("Removing client %s from channel %s",
37 chl->client->nickname ? chl->client->nickname :
38 (unsigned char *)"", chl->channel->channel_name));
40 /* Remove the context from the client's channel hash table as that
41 table and channel's user_list hash table share this same context. */
42 silc_hash_table_del(chl->client->channels, chl->channel);
47 /****************************** Server entry ********************************/
49 void silc_server_destructor_server(SilcIDCache cache,
50 const SilcIDCacheEntry entry,
51 void *destructor_context,
57 /* Adds new server entry to server */
59 SilcServerEntry silc_server_add_server(SilcServer server,
60 const char *server_name,
61 SilcServerType server_type,
63 SilcPacketStream origin)
65 SilcServerEntry entry;
66 char *server_namec = NULL;
71 entry = silc_calloc(1, sizeof(*entry));
75 SILC_LOG_DEBUG(("Adding server entry %p %s", entry,
76 silc_id_render(id, SILC_ID_SERVER)));
78 /* Normalize name. This is cached, original is in server context. */
80 server_namec = silc_identifier_check(server_name, strlen(server_name),
81 SILC_STRING_UTF8, 256, NULL);
87 entry->server_name = strdup(server_name);
88 if (!server->server_name) {
89 silc_free(server_namec);
95 entry->server_type = server_type;
97 entry->stream = origin;
100 if (!silc_idcache_add(server->servers, server_namec, &entry->id,
102 silc_free(server_namec);
103 silc_free(entry->server_name);
108 /* Take reference of the packet stream */
109 silc_packet_stream_ref(origin);
114 /* Delete server entry */
116 SilcBool silc_server_del_server(SilcServer server, SilcServerEntry entry)
118 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
119 entry->server_name : "??", &entry->id ?
120 silc_id_render(&entry->id, SILC_ID_SERVER) : "??"));
123 if (!silc_idcache_del_by_context(server->servers, entry, NULL)) {
124 SILC_LOG_ERROR(("Unknown server %s, could not delete from cache",
125 &entry->id ? silc_id_render(&entry->id, SILC_ID_SERVER) :
133 /* Find server by Server ID */
136 silc_server_find_server_by_id(SilcServer server,
139 SilcIDCacheEntry *ret_entry)
141 SilcIDCacheEntry id_cache = NULL;
142 SilcServerEntry entry;
147 SILC_LOG_DEBUG(("Find Server ID (%s)",
148 silc_id_render(id, SILC_ID_SERVER)));
150 if (!silc_idcache_find_by_id_one(server->servers, (void *)id,
154 entry = id_cache->context;
156 if (entry && registered && !(entry->data.registered))
160 *ret_entry = id_cache;
162 SILC_LOG_DEBUG(("Found"));
167 /* Find server by name. The 'name' must be normalized already. */
170 silc_server_find_server_by_name(SilcServer server, char *name,
172 SilcIDCacheEntry *ret_entry)
174 SilcIDCacheEntry id_cache = NULL;
175 SilcServerEntry entry;
177 SILC_LOG_DEBUG(("Find server by name `%s'", name));
179 if (!silc_idcache_find_by_name_one(server->servers, name, &id_cache))
182 entry = id_cache->context;
184 if (entry && registered && !(entry->data.registered))
188 *ret_entry = id_cache;
190 SILC_LOG_DEBUG(("Found"));
195 /* Find server by connection parameters, hostname and port */
198 silc_server_find_server_by_conn(SilcServer server, char *hostname,
199 int port, SilcBool registered,
200 SilcIDCacheEntry *ret_entry)
202 SilcIDCacheEntry id_cache;
203 SilcServerEntry entry;
209 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
211 if (!silc_idcache_get_all(server->servers, &list))
214 while ((id_cache = silc_list_get(list)) != SILC_LIST_END) {
215 entry = id_cache->context;
216 stream = silc_packet_stream_get_stream(entry->stream);
218 if (entry && registered && !(entry->data.registered))
221 if (silc_socket_stream_get_info(stream, NULL, &h, NULL, &p)) {
222 if (silc_utf8_strcasecmp(hostname, h) && p == port)
230 *ret_entry = id_cache;
232 SILC_LOG_DEBUG(("Found"));
237 /* Replaces old Server ID with new one */
240 silc_server_replace_server_id(SilcServer server, SilcServerID *old_id,
241 SilcServerID *new_id)
243 SilcIDCacheEntry id_cache = NULL;
244 SilcServerEntry entry;
246 if (!old_id || !new_id)
249 SILC_LOG_DEBUG(("Replacing Server ID %s",
250 silc_id_render(old_id, SILC_ID_SERVER)));
251 SILC_LOG_DEBUG(("New Server ID %s",
252 silc_id_render(new_id, SILC_ID_SERVER)));
254 if (!silc_idcache_find_by_id_one(server->servers, (void *)old_id,
258 entry = id_cache->context;
261 if (!silc_idcache_update(server->servers, id_cache, old_id, &entry->id,
263 SILC_LOG_ERROR(("Error updating Server ID"));
267 SILC_LOG_DEBUG(("Replaced"));
273 /****************************** Client entry ********************************/
275 void silc_server_destructor_client(SilcIDCache cache,
276 const SilcIDCacheEntry entry,
277 void *destructor_context,
283 /* Adds new client to server */
285 SilcClientEntry silc_server_add_client(SilcServer server,
286 const char *nickname,
287 const char *username,
288 const char *userinfo,
291 SilcPacketStream origin)
293 SilcClientEntry client;
294 char *nicknamec = NULL;
298 if (!id || !origin || !nickname || !username)
301 client = silc_calloc(1, sizeof(*client));
305 SILC_LOG_DEBUG(("Adding client entry %p", client));
307 /* Normalize name. This is cached, original is in client context. */
308 nicknamec = silc_identifier_check(nickname, strlen(nickname),
309 SILC_STRING_UTF8, 128, NULL);
314 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
317 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
320 !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256))
323 client->nickname = strdup(nickname);
324 if (!client->nickname)
327 client->username = strdup(username);
328 if (!client->username)
331 client->userinfo = userinfo ? strdup(userinfo) : NULL;
332 if (!client->userinfo)
337 client->stream = origin;
339 client->channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL,
340 NULL, NULL, NULL, NULL, TRUE);
341 if (!client->channels)
344 if (!silc_idcache_add(server->clients, nicknamec, (void *)&client->id,
348 /* Take reference of the packet stream */
349 silc_packet_stream_ref(origin);
354 if (client->channels)
355 silc_hash_table_free(client->channels);
356 silc_free(client->nickname);
357 silc_free(client->username);
358 silc_free(client->userinfo);
360 silc_free(nicknamec);
364 /* Delete client entry */
366 SilcBool silc_server_del_client(SilcServer server, SilcClientEntry entry)
368 SILC_LOG_DEBUG(("Deleting client %s id %s", entry->nickname ?
369 entry->nickname : (unsigned char *)"??", &entry->id ?
370 silc_id_render(&entry->id, SILC_ID_CLIENT) : "??"));
373 if (!silc_idcache_del_by_context(server->clients, entry, NULL)) {
374 SILC_LOG_ERROR(("Unknown client %s, could not delete from cache",
375 &entry->id ? silc_id_render(&entry->id, SILC_ID_CLIENT) :
383 /* Finds all clients matching the nickanem `nickname'. Returns list of
384 SilcIDCacheEntry entries. The `nickname' must be normalized. */
386 SilcBool silc_server_find_clients(SilcServer server, char *nickname,
389 SilcClientID client_id;
390 unsigned char hash[16];
392 SILC_LOG_DEBUG(("Find clients named %s", nickname));
394 /* Find using Client ID hash, as Client ID is based on the nickname,
395 we can find clients quickly using the hash of the nickname. */
396 memset(&client_id, 0, sizeof(client_id));
397 silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
398 memcpy(client_id.hash, hash, CLIENTID_HASH_LEN);
400 if (!silc_idcache_find_by_id(server->clients, &client_id, list))
403 SILC_LOG_DEBUG(("Found %d clients", silc_list_count(*list)));
408 /* Finds client by Client ID */
410 SilcClientEntry silc_server_find_client_by_id(SilcServer server,
413 SilcIDCacheEntry *ret_entry)
415 SilcIDCacheEntry id_cache = NULL;
416 SilcClientEntry client;
421 SILC_LOG_DEBUG(("Client ID (%s)", silc_id_render(id, SILC_ID_CLIENT)));
423 if (!silc_idcache_find_by_id_one(server->clients, (void *)id, &id_cache))
426 client = id_cache->context;
428 if (client && registered && !(client->data.registered))
432 *ret_entry = id_cache;
434 SILC_LOG_DEBUG(("Found"));
439 /* Replaces old Client ID with new one */
442 silc_server_replace_client_id(SilcServer server, SilcClientID *old_id,
443 SilcClientID *new_id, const char *nickname)
445 SilcIDCacheEntry id_cache = NULL;
446 SilcClientEntry entry;
447 char *name, *nicknamec = NULL;
449 if (!old_id || !new_id)
452 SILC_LOG_DEBUG(("Replacing Client ID %s",
453 silc_id_render(old_id, SILC_ID_SERVER)));
454 SILC_LOG_DEBUG(("New Client ID %s",
455 silc_id_render(new_id, SILC_ID_SERVER)));
457 /* Normalize name. This is cached, original is in client context. */
459 nicknamec = silc_identifier_check(nickname, strlen(nickname),
460 SILC_STRING_UTF8, 128, NULL);
465 if (!silc_idcache_find_by_id_one(server->clients, (void *)old_id,
469 entry = id_cache->context;
472 name = id_cache->name;
473 if (!silc_idcache_update(server->clients, id_cache, old_id, &entry->id,
475 SILC_LOG_ERROR(("Error updating Client ID"));
481 /* Check if anyone is watching old 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_free(entry->nickname);
487 entry->nickname = nickname ? strdup(nickname) : NULL;
489 /* Check if anyone is watching new nickname */
490 if (server->server_type == SILC_ROUTER)
491 silc_server_check_watcher_list(server, entry, nickname,
492 SILC_NOTIFY_TYPE_NICK_CHANGE);
494 SILC_LOG_DEBUG(("Replaced"));
500 /****************************** Channel entry *******************************/
502 void silc_server_destructor_channel(SilcIDCache cache,
503 const SilcIDCacheEntry entry,
504 void *destructor_context,
510 /* Add new channel */
512 SilcChannelEntry silc_server_add_channel(SilcServer server,
513 const char *channel_name,
516 SilcPacketStream origin,
517 SilcCipher channel_key,
520 SilcChannelEntry channel;
521 char *channel_namec = NULL;
523 if (!id || !channel_key || !hmac)
526 channel = silc_calloc(1, sizeof(*channel));
530 SILC_LOG_DEBUG(("Adding new channel %s %p", channel_name, channel));
532 /* Normalize name. This is cached, original is in client context. */
534 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
535 SILC_STRING_UTF8, 256, NULL);
536 if (!channel_namec) {
542 channel->channel_name = channel_name ? strdup(channel_name) : NULL;
545 silc_free(channel_namec);
549 channel->mode = mode;
551 channel->channel_key = channel_key;
552 channel->hmac = hmac;
553 channel->router = origin;
555 channel->user_list = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
556 NULL, NULL, NULL, TRUE);
557 if (!channel->user_list) {
558 silc_cipher_free(channel->channel_key);
559 silc_hmac_free(channel->hmac);
560 silc_free(channel->channel_name);
562 silc_free(channel_namec);
566 if (!silc_idcache_add(server->channels, channel_namec,
567 (void *)&channel->id, (void *)channel)) {
568 silc_cipher_free(channel->channel_key);
569 silc_hmac_free(channel->hmac);
570 silc_free(channel->channel_name);
571 silc_hash_table_free(channel->user_list);
573 silc_free(channel_namec);
577 /* Take reference of the packet stream */
578 silc_packet_stream_ref(origin);
583 /* Free channel entry. This free's everything. */
585 SilcBool silc_server_del_channel(SilcServer server, SilcChannelEntry entry)
587 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
589 /* Remove from cache */
590 if (!silc_idcache_del_by_context(server->channels, entry, NULL)) {
591 SILC_LOG_DEBUG(("Unknown channel %s, did not delete",
592 entry->channel_name));
599 /* Finds channel by channel name. Channel names are unique and they
600 are not case-sensitive. The 'name' must be normalized already. */
602 SilcChannelEntry silc_server_find_channel_by_name(SilcServer server,
604 SilcIDCacheEntry *ret_entry)
606 SilcIDCacheEntry id_cache = NULL;
608 SILC_LOG_DEBUG(("Channel by name %s", name));
610 if (!silc_idcache_find_by_name_one(server->channels, (char *)name,
615 *ret_entry = id_cache;
617 SILC_LOG_DEBUG(("Found"));
619 return id_cache->context;
622 /* Finds channel by Channel ID. */
624 SilcChannelEntry silc_server_find_channel_by_id(SilcServer server,
626 SilcIDCacheEntry *ret_entry)
628 SilcIDCacheEntry id_cache = NULL;
633 SILC_LOG_DEBUG(("Channel ID (%s)", silc_id_render(id, SILC_ID_CHANNEL)));
635 if (!silc_idcache_find_by_id_one(server->channels, (void *)id, &id_cache))
639 *ret_entry = id_cache;
641 SILC_LOG_DEBUG(("Found"));
643 return id_cache->context;
646 /* Replaces old Channel ID with new one. This is done when router forces
647 normal server to change Channel ID. */
649 SilcChannelEntry silc_server_replace_channel_id(SilcServer server,
650 SilcChannelID *old_id,
651 SilcChannelID *new_id)
653 SilcIDCacheEntry id_cache = NULL;
654 SilcChannelEntry entry;
656 if (!old_id || !new_id)
659 SILC_LOG_DEBUG(("Replacing Channel ID %s",
660 silc_id_render(old_id, SILC_ID_CHANNEL)));
661 SILC_LOG_DEBUG(("New Channel ID %s",
662 silc_id_render(new_id, SILC_ID_CHANNEL)));
664 if (!silc_idcache_find_by_id_one(server->channels, (void *)old_id,
668 entry = id_cache->context;
671 if (!silc_idcache_update(server->channels, id_cache, old_id, &entry->id,
673 SILC_LOG_ERROR(("Error updating Channel ID"));
677 SILC_LOG_DEBUG(("Replaced"));
682 /* Returns channels from the ID list. If the `channel_id' is NULL then
683 all channels are returned. Returns list of SilcIDCacheEntry entries. */
685 SilcBool silc_server_get_channels(SilcServer server,
686 SilcChannelID *channel_id,
689 SILC_LOG_DEBUG(("Start"));
692 if (!silc_idcache_get_all(server->channels, list))
695 if (!silc_idcache_find_by_id(server->channels, channel_id, list))