5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
24 /* Removes the client from channels and possibly removes the channels
25 as well. After removing those channels that exist, their channel
26 keys are regnerated. This is called only by the function
27 silc_server_remove_clients_by_server. */
29 static void silc_server_remove_clients_channels(SilcServer server,
30 SilcSocketConnection sock,
31 SilcClientEntry client,
32 SilcHashTable channels)
34 SilcChannelEntry channel;
35 SilcChannelClientEntry chl;
36 SilcHashTableList htl;
39 SILC_LOG_DEBUG(("Start"));
41 if (!client || !client->id)
44 clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
46 /* Remove the client from all channels. The client is removed from
47 the channels' user list. */
48 silc_hash_table_list(client->channels, &htl);
49 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
50 channel = chl->channel;
52 /* Remove channel from client's channel list */
53 silc_hash_table_del(client->channels, channel);
55 /* Remove channel if there is no users anymore */
56 if (server->server_type == SILC_ROUTER &&
57 silc_hash_table_count(channel->user_list) < 2) {
59 if (silc_hash_table_find(channels, channel, NULL, NULL))
60 silc_hash_table_del(channels, channel);
63 silc_schedule_task_del_by_context(server->schedule, channel->rekey);
65 if (silc_idlist_del_channel(server->local_list, channel))
66 server->stat.my_channels--;
67 else if (silc_idlist_del_channel(server->global_list, channel))
68 server->stat.my_channels--;
72 /* Remove client from channel's client list */
73 silc_hash_table_del(channel->user_list, chl->client);
75 /* If there is no global users on the channel anymore mark the channel
76 as local channel. Do not check if the removed client is local client. */
77 if (server->server_type != SILC_ROUTER && channel->global_users &&
78 chl->client->router && !silc_server_channel_has_global(channel))
79 channel->global_users = FALSE;
82 server->stat.my_chanclients--;
84 /* If there is not at least one local user on the channel then we don't
85 need the channel entry anymore, we can remove it safely. */
86 if (server->server_type != SILC_ROUTER &&
87 !silc_server_channel_has_local(channel)) {
89 if (silc_hash_table_find(channels, channel, NULL, NULL))
90 silc_hash_table_del(channels, channel);
93 silc_schedule_task_del_by_context(server->schedule, channel->rekey);
95 if (channel->founder_key) {
96 /* The founder auth data exists, do not remove the channel entry */
97 SilcChannelClientEntry chl2;
98 SilcHashTableList htl2;
102 silc_hash_table_list(channel->user_list, &htl2);
103 while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
104 silc_hash_table_del(chl2->client->channels, channel);
105 silc_hash_table_del(channel->user_list, chl2->client);
111 /* Remove the channel entry */
112 if (silc_idlist_del_channel(server->local_list, channel))
113 server->stat.my_channels--;
114 else if (silc_idlist_del_channel(server->global_list, channel))
115 server->stat.my_channels--;
119 /* Add the channel to the the channels list to regenerate the
121 if (!silc_hash_table_find(channels, channel, NULL, NULL))
122 silc_hash_table_add(channels, channel, channel);
125 silc_buffer_free(clidp);
128 /* This function is used to remove all client entries by the server `entry'.
129 This is called when the connection is lost to the server. In this case
130 we must invalidate all the client entries owned by the server `entry'.
131 If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
132 distributed to our local clients. */
134 bool silc_server_remove_clients_by_server(SilcServer server,
135 SilcServerEntry entry,
138 SilcIDCacheList list = NULL;
139 SilcIDCacheEntry id_cache = NULL;
140 SilcClientEntry client = NULL;
142 SilcClientEntry *clients = NULL;
143 uint32 clients_c = 0;
144 unsigned char **argv = NULL;
145 uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
146 SilcHashTableList htl;
147 SilcChannelEntry channel;
148 SilcHashTable channels;
151 SILC_LOG_DEBUG(("Start"));
153 /* Allocate the hash table that holds the channels that require
154 channel key re-generation after we've removed this server's clients
155 from the channels. */
156 channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
159 if (server_signoff) {
160 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
161 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
162 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
163 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
164 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
165 memcpy(argv[argc], idp->data, idp->len);
166 argv_lens[argc] = idp->len;
167 argv_types[argc] = argc + 1;
169 silc_buffer_free(idp);
172 if (silc_idcache_get_all(server->local_list->clients, &list)) {
174 if (silc_idcache_list_first(list, &id_cache)) {
176 client = (SilcClientEntry)id_cache->context;
177 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
178 if (!silc_idcache_list_next(list, &id_cache))
184 if (client->router != entry) {
185 if (server_signoff && client->connection) {
186 clients = silc_realloc(clients,
187 sizeof(*clients) * (clients_c + 1));
188 clients[clients_c] = client;
192 if (!silc_idcache_list_next(list, &id_cache))
198 if (server_signoff) {
199 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
200 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
201 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
203 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
205 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
206 memcpy(argv[argc], idp->data, idp->len);
207 argv_lens[argc] = idp->len;
208 argv_types[argc] = argc + 1;
210 silc_buffer_free(idp);
213 /* Remove the client entry */
214 silc_server_remove_clients_channels(server, NULL, client, channels);
215 silc_idlist_del_client(server->local_list, client);
217 if (!silc_idcache_list_next(list, &id_cache))
221 silc_idcache_list_free(list);
224 if (silc_idcache_get_all(server->global_list->clients, &list)) {
226 if (silc_idcache_list_first(list, &id_cache)) {
228 client = (SilcClientEntry)id_cache->context;
229 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
230 if (!silc_idcache_list_next(list, &id_cache))
236 if (client->router != entry) {
237 if (server_signoff && client->connection) {
238 clients = silc_realloc(clients,
239 sizeof(*clients) * (clients_c + 1));
240 clients[clients_c] = client;
244 if (!silc_idcache_list_next(list, &id_cache))
250 if (server_signoff) {
251 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
252 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
253 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
255 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
257 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
258 memcpy(argv[argc], idp->data, idp->len);
259 argv_lens[argc] = idp->len;
260 argv_types[argc] = argc + 1;
262 silc_buffer_free(idp);
265 /* Remove the client entry */
266 silc_server_remove_clients_channels(server, NULL, client, channels);
267 silc_idlist_del_client(server->global_list, client);
269 if (!silc_idcache_list_next(list, &id_cache))
273 silc_idcache_list_free(list);
276 /* Send the SERVER_SIGNOFF notify */
277 if (server_signoff) {
280 /* Send SERVER_SIGNOFF notify to our primary router */
281 if (!server->standalone && server->router &&
282 server->router != entry) {
283 args = silc_argument_payload_encode(1, argv, argv_lens,
285 silc_server_send_notify_args(server,
286 server->router->connection,
287 server->server_type == SILC_SERVER ?
289 SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
291 silc_buffer_free(args);
294 args = silc_argument_payload_encode(argc, argv, argv_lens,
296 /* Send to local clients */
297 for (i = 0; i < clients_c; i++) {
298 silc_server_send_notify_args(server, clients[i]->connection,
299 FALSE, SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
304 silc_buffer_free(args);
305 for (i = 0; i < argc; i++)
308 silc_free(argv_lens);
309 silc_free(argv_types);
312 /* We must now re-generate the channel key for all channels that had
313 this server's client(s) on the channel. As they left the channel we
314 must re-generate the channel key. */
315 silc_hash_table_list(channels, &htl);
316 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
317 if (!silc_server_create_channel_key(server, channel, 0))
320 /* Do not send the channel key if private channel key mode is set */
321 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
324 silc_server_send_channel_key(server, NULL, channel,
325 server->server_type == SILC_ROUTER ?
326 FALSE : !server->standalone);
328 silc_hash_table_free(channels);
333 static SilcServerEntry
334 silc_server_update_clients_by_real_server(SilcServer server,
335 SilcServerEntry from,
336 SilcClientEntry client,
338 SilcIDCacheEntry client_cache)
340 SilcServerEntry server_entry;
341 SilcIDCacheEntry id_cache = NULL;
342 SilcIDCacheList list;
344 if (!silc_idcache_get_all(server->local_list->servers, &list))
347 if (silc_idcache_list_first(list, &id_cache)) {
349 server_entry = (SilcServerEntry)id_cache->context;
350 if (server_entry != from &&
351 SILC_ID_COMPARE(server_entry->id, client->id,
352 client->id->ip.data_len)) {
353 SILC_LOG_DEBUG(("Found (local) %s",
354 silc_id_render(server_entry->id, SILC_ID_SERVER)));
357 if (!server_entry->data.send_key && server_entry->router) {
358 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
359 /* If the client is not marked as local then move it to local list
360 since the server is local. */
362 SILC_LOG_DEBUG(("Moving client to local list"));
363 silc_idcache_add(server->local_list->clients, client_cache->name,
364 client_cache->id, client_cache->context,
365 client_cache->expire);
366 silc_idcache_del_by_context(server->global_list->clients, client);
368 server_entry = server_entry->router;
371 /* If the client is not marked as local then move it to local list
372 since the server is local. */
373 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
374 SILC_LOG_DEBUG(("Moving client to local list"));
375 silc_idcache_add(server->local_list->clients, client_cache->name,
376 client_cache->id, client_cache->context,
377 client_cache->expire);
378 silc_idcache_del_by_context(server->global_list->clients, client);
384 silc_idcache_list_free(list);
388 if (!silc_idcache_list_next(list, &id_cache))
393 silc_idcache_list_free(list);
395 if (!silc_idcache_get_all(server->global_list->servers, &list))
398 if (silc_idcache_list_first(list, &id_cache)) {
400 server_entry = (SilcServerEntry)id_cache->context;
401 if (server_entry != from &&
402 SILC_ID_COMPARE(server_entry->id, client->id,
403 client->id->ip.data_len)) {
404 SILC_LOG_DEBUG(("Found (global) %s",
405 silc_id_render(server_entry->id, SILC_ID_SERVER)));
408 if (!server_entry->data.send_key && server_entry->router) {
409 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
410 /* If the client is marked as local then move it to global list
411 since the server is global. */
413 SILC_LOG_DEBUG(("Moving client to global list"));
414 silc_idcache_add(server->global_list->clients, client_cache->name,
415 client_cache->id, client_cache->context,
416 client_cache->expire);
417 silc_idcache_del_by_context(server->local_list->clients, client);
419 server_entry = server_entry->router;
422 /* If the client is marked as local then move it to global list
423 since the server is global. */
424 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
425 SILC_LOG_DEBUG(("Moving client to global list"));
426 silc_idcache_add(server->global_list->clients, client_cache->name,
427 client_cache->id, client_cache->context,
428 client_cache->expire);
429 silc_idcache_del_by_context(server->local_list->clients, client);
435 silc_idcache_list_free(list);
439 if (!silc_idcache_list_next(list, &id_cache))
444 silc_idcache_list_free(list);
449 /* Updates the clients that are originated from the `from' to be originated
450 from the `to'. If the `resolve_real_server' is TRUE then this will
451 attempt to figure out which clients really are originated from the
452 `from' and which are originated from a server that we have connection
453 to, when we've acting as backup router. If it is FALSE the `to' will
454 be the new source. This function also removes the clients that are
455 *really* originated from `from' if `remove_from' is TRUE. These are
456 clients that the `from' owns, and not just clients that are behind
459 void silc_server_update_clients_by_server(SilcServer server,
460 SilcServerEntry from,
462 bool resolve_real_server,
465 SilcIDCacheList list = NULL;
466 SilcIDCacheEntry id_cache = NULL;
467 SilcClientEntry client = NULL;
470 SILC_LOG_DEBUG(("Start"));
472 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
474 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
479 if (silc_idcache_get_all(server->global_list->clients, &list)) {
480 if (silc_idcache_list_first(list, &id_cache)) {
482 client = (SilcClientEntry)id_cache->context;
485 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
486 if (!silc_idcache_list_next(list, &id_cache))
492 SILC_LOG_DEBUG(("Client (global) %s",
493 silc_id_render(client->id, SILC_ID_CLIENT)));
495 SILC_LOG_DEBUG(("Client->router (global) %s",
496 silc_id_render(client->router->id, SILC_ID_SERVER)));
498 if (client->router == from) {
499 /* Skip clients that are *really* owned by the `from' */
500 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
501 client->id->ip.data_len)) {
502 SILC_LOG_DEBUG(("Found really owned client, skip it"));
503 if (!silc_idcache_list_next(list, &id_cache))
509 if (resolve_real_server) {
511 silc_server_update_clients_by_real_server(server, from, client,
520 if (!silc_idcache_list_next(list, &id_cache))
524 silc_idcache_list_free(list);
528 if (silc_idcache_get_all(server->local_list->clients, &list)) {
529 if (silc_idcache_list_first(list, &id_cache)) {
531 client = (SilcClientEntry)id_cache->context;
533 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
534 if (!silc_idcache_list_next(list, &id_cache))
540 SILC_LOG_DEBUG(("Client (local) %s",
541 silc_id_render(client->id, SILC_ID_CLIENT)));
543 SILC_LOG_DEBUG(("Client->router (local) %s",
544 silc_id_render(client->router->id, SILC_ID_SERVER)));
546 if (client->router == from) {
547 /* Skip clients that are *really* owned by the `from' */
548 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
549 client->id->ip.data_len)) {
550 SILC_LOG_DEBUG(("Found really owned client, skip it"));
551 if (!silc_idcache_list_next(list, &id_cache))
557 if (resolve_real_server) {
559 silc_server_update_clients_by_real_server(server, from, client,
562 client->router = from; /* on local list put old from */
568 if (!silc_idcache_list_next(list, &id_cache))
572 silc_idcache_list_free(list);
576 /* Now remove the clients that are still marked as orignated from the
577 `from'. These are the clients that really was owned by the `from' and
578 not just exist behind the `from'. */
579 silc_server_remove_clients_by_server(server, from, TRUE);
582 /* Updates servers that are from `from' to be originated from `to'. This
583 will also update the server's connection to `to's connection. */
585 void silc_server_update_servers_by_server(SilcServer server,
586 SilcServerEntry from,
589 SilcIDCacheList list = NULL;
590 SilcIDCacheEntry id_cache = NULL;
591 SilcServerEntry server_entry = NULL;
593 SILC_LOG_DEBUG(("Start"));
595 if (silc_idcache_get_all(server->local_list->servers, &list)) {
596 if (silc_idcache_list_first(list, &id_cache)) {
598 server_entry = (SilcServerEntry)id_cache->context;
599 if (server_entry->router == from) {
600 server_entry->router = to;
601 server_entry->connection = to->connection;
603 if (!silc_idcache_list_next(list, &id_cache))
607 silc_idcache_list_free(list);
610 if (silc_idcache_get_all(server->global_list->servers, &list)) {
611 if (silc_idcache_list_first(list, &id_cache)) {
613 server_entry = (SilcServerEntry)id_cache->context;
614 if (server_entry->router == from) {
615 server_entry->router = to;
616 server_entry->connection = to->connection;
618 if (!silc_idcache_list_next(list, &id_cache))
622 silc_idcache_list_free(list);
626 /* Checks whether given channel has global users. If it does this returns
627 TRUE and FALSE if there is only locally connected clients on the channel. */
629 bool silc_server_channel_has_global(SilcChannelEntry channel)
631 SilcChannelClientEntry chl;
632 SilcHashTableList htl;
634 silc_hash_table_list(channel->user_list, &htl);
635 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
636 if (chl->client->router)
643 /* Checks whether given channel has locally connected users. If it does this
644 returns TRUE and FALSE if there is not one locally connected client. */
646 bool silc_server_channel_has_local(SilcChannelEntry channel)
648 SilcChannelClientEntry chl;
649 SilcHashTableList htl;
651 silc_hash_table_list(channel->user_list, &htl);
652 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
653 if (!chl->client->router)
660 /* Returns TRUE if the given client is on the channel. FALSE if not.
661 This works because we assure that the user list on the channel is
662 always in up to date thus we can only check the channel list from
663 `client' which is faster than checking the user list from `channel'. */
665 bool silc_server_client_on_channel(SilcClientEntry client,
666 SilcChannelEntry channel)
668 if (!client || !channel)
671 if (silc_hash_table_find(client->channels, channel, NULL, NULL))