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--;
68 silc_idlist_del_channel(server->global_list, channel);
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--;
115 silc_idlist_del_channel(server->global_list, channel);
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)));
356 if (!server_entry->data.send_key && server_entry->router) {
357 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
358 /* If the client is not marked as local then move it to local list
359 since the server is local. */
361 SILC_LOG_DEBUG(("Moving client to local list"));
362 silc_idcache_add(server->local_list->clients, client_cache->name,
363 client_cache->id, client_cache->context,
364 client_cache->expire);
365 silc_idcache_del_by_context(server->global_list->clients, client);
367 server_entry = server_entry->router;
369 /* If the client is not marked as local then move it to local list
370 since the server is local. */
371 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
372 SILC_LOG_DEBUG(("Moving client to local list"));
373 silc_idcache_add(server->local_list->clients, client_cache->name,
374 client_cache->id, client_cache->context,
375 client_cache->expire);
376 silc_idcache_del_by_context(server->global_list->clients, client);
380 silc_idcache_list_free(list);
384 if (!silc_idcache_list_next(list, &id_cache))
389 silc_idcache_list_free(list);
391 if (!silc_idcache_get_all(server->global_list->servers, &list))
394 if (silc_idcache_list_first(list, &id_cache)) {
396 server_entry = (SilcServerEntry)id_cache->context;
397 if (server_entry != from &&
398 SILC_ID_COMPARE(server_entry->id, client->id,
399 client->id->ip.data_len)) {
400 SILC_LOG_DEBUG(("Found (global) %s",
401 silc_id_render(server_entry->id, SILC_ID_SERVER)));
403 if (!server_entry->data.send_key && server_entry->router) {
404 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
405 /* If the client is marked as local then move it to global list
406 since the server is global. */
408 SILC_LOG_DEBUG(("Moving client to global list"));
409 silc_idcache_add(server->global_list->clients, client_cache->name,
410 client_cache->id, client_cache->context,
411 client_cache->expire);
412 silc_idcache_del_by_context(server->local_list->clients, client);
414 server_entry = server_entry->router;
416 /* If the client is marked as local then move it to global list
417 since the server is global. */
418 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
419 SILC_LOG_DEBUG(("Moving client to global list"));
420 silc_idcache_add(server->global_list->clients, client_cache->name,
421 client_cache->id, client_cache->context,
422 client_cache->expire);
423 silc_idcache_del_by_context(server->local_list->clients, client);
427 silc_idcache_list_free(list);
431 if (!silc_idcache_list_next(list, &id_cache))
436 silc_idcache_list_free(list);
441 /* Updates the clients that are originated from the `from' to be originated
442 from the `to'. If the `resolve_real_server' is TRUE then this will
443 attempt to figure out which clients really are originated from the
444 `from' and which are originated from a server that we have connection
445 to, when we've acting as backup router. If it is FALSE the `to' will
446 be the new source. This function also removes the clients that are
447 *really* originated from `from' if `remove_from' is TRUE. These are
448 clients that the `from' owns, and not just clients that are behind
451 void silc_server_update_clients_by_server(SilcServer server,
452 SilcServerEntry from,
454 bool resolve_real_server,
457 SilcIDCacheList list = NULL;
458 SilcIDCacheEntry id_cache = NULL;
459 SilcClientEntry client = NULL;
462 SILC_LOG_DEBUG(("Start"));
464 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
466 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
471 if (silc_idcache_get_all(server->global_list->clients, &list)) {
472 if (silc_idcache_list_first(list, &id_cache)) {
474 client = (SilcClientEntry)id_cache->context;
477 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
478 if (!silc_idcache_list_next(list, &id_cache))
484 SILC_LOG_DEBUG(("Client (global) %s",
485 silc_id_render(client->id, SILC_ID_CLIENT)));
487 SILC_LOG_DEBUG(("Client->router (global) %s",
488 silc_id_render(client->router->id, SILC_ID_SERVER)));
490 if (client->router == from) {
491 /* Skip clients that are *really* owned by the `from' */
492 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
493 client->id->ip.data_len)) {
494 SILC_LOG_DEBUG(("Found really owned client, skip it"));
495 if (!silc_idcache_list_next(list, &id_cache))
501 if (resolve_real_server) {
503 silc_server_update_clients_by_real_server(server, from, client,
512 if (!silc_idcache_list_next(list, &id_cache))
516 silc_idcache_list_free(list);
520 if (silc_idcache_get_all(server->local_list->clients, &list)) {
521 if (silc_idcache_list_first(list, &id_cache)) {
523 client = (SilcClientEntry)id_cache->context;
525 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
526 if (!silc_idcache_list_next(list, &id_cache))
532 SILC_LOG_DEBUG(("Client (local) %s",
533 silc_id_render(client->id, SILC_ID_CLIENT)));
535 SILC_LOG_DEBUG(("Client->router (local) %s",
536 silc_id_render(client->router->id, SILC_ID_SERVER)));
538 if (client->router == from) {
539 /* Skip clients that are *really* owned by the `from' */
540 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
541 client->id->ip.data_len)) {
542 SILC_LOG_DEBUG(("Found really owned client, skip it"));
543 if (!silc_idcache_list_next(list, &id_cache))
549 if (resolve_real_server) {
551 silc_server_update_clients_by_real_server(server, from, client,
554 client->router = from; /* on local list put old from */
560 if (!silc_idcache_list_next(list, &id_cache))
564 silc_idcache_list_free(list);
568 /* Now remove the clients that are still marked as orignated from the
569 `from'. These are the clients that really was owned by the `from' and
570 not just exist behind the `from'. */
571 silc_server_remove_clients_by_server(server, from, TRUE);
574 /* Updates servers that are from `from' to be originated from `to'. This
575 will also update the server's connection to `to's connection. */
577 void silc_server_update_servers_by_server(SilcServer server,
578 SilcServerEntry from,
581 SilcIDCacheList list = NULL;
582 SilcIDCacheEntry id_cache = NULL;
583 SilcServerEntry server_entry = NULL;
585 SILC_LOG_DEBUG(("Start"));
587 if (silc_idcache_get_all(server->local_list->servers, &list)) {
588 if (silc_idcache_list_first(list, &id_cache)) {
590 server_entry = (SilcServerEntry)id_cache->context;
591 if (server_entry->router == from) {
592 server_entry->router = to;
593 server_entry->connection = to->connection;
595 if (!silc_idcache_list_next(list, &id_cache))
599 silc_idcache_list_free(list);
602 if (silc_idcache_get_all(server->global_list->servers, &list)) {
603 if (silc_idcache_list_first(list, &id_cache)) {
605 server_entry = (SilcServerEntry)id_cache->context;
606 if (server_entry->router == from) {
607 server_entry->router = to;
608 server_entry->connection = to->connection;
610 if (!silc_idcache_list_next(list, &id_cache))
614 silc_idcache_list_free(list);
618 /* Checks whether given channel has global users. If it does this returns
619 TRUE and FALSE if there is only locally connected clients on the channel. */
621 bool silc_server_channel_has_global(SilcChannelEntry channel)
623 SilcChannelClientEntry chl;
624 SilcHashTableList htl;
626 silc_hash_table_list(channel->user_list, &htl);
627 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
628 if (chl->client->router)
635 /* Checks whether given channel has locally connected users. If it does this
636 returns TRUE and FALSE if there is not one locally connected client. */
638 bool silc_server_channel_has_local(SilcChannelEntry channel)
640 SilcChannelClientEntry chl;
641 SilcHashTableList htl;
643 silc_hash_table_list(channel->user_list, &htl);
644 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
645 if (!chl->client->router)
652 /* Returns TRUE if the given client is on the channel. FALSE if not.
653 This works because we assure that the user list on the channel is
654 always in up to date thus we can only check the channel list from
655 `client' which is faster than checking the user list from `channel'. */
657 bool silc_server_client_on_channel(SilcClientEntry client,
658 SilcChannelEntry channel)
660 if (!client || !channel)
663 if (silc_hash_table_find(client->channels, channel, NULL, NULL))