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;
100 channel->disabled = TRUE;
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) {
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) {
278 SilcBuffer args, not;
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 /* Send to local clients */
295 args = silc_argument_payload_encode(argc, argv, argv_lens,
297 not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
299 silc_server_packet_send_clients(server, clients, clients_c,
300 SILC_PACKET_NOTIFY, 0, FALSE,
301 not->data, not->len, FALSE);
304 silc_buffer_free(args);
305 silc_buffer_free(not);
306 for (i = 0; i < argc; i++)
309 silc_free(argv_lens);
310 silc_free(argv_types);
313 /* We must now re-generate the channel key for all channels that had
314 this server's client(s) on the channel. As they left the channel we
315 must re-generate the channel key. */
316 silc_hash_table_list(channels, &htl);
317 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
318 if (!silc_server_create_channel_key(server, channel, 0))
321 /* Do not send the channel key if private channel key mode is set */
322 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
325 silc_server_send_channel_key(server, NULL, channel,
326 server->server_type == SILC_ROUTER ?
327 FALSE : !server->standalone);
329 silc_hash_table_free(channels);
334 static SilcServerEntry
335 silc_server_update_clients_by_real_server(SilcServer server,
336 SilcServerEntry from,
337 SilcClientEntry client,
339 SilcIDCacheEntry client_cache)
341 SilcServerEntry server_entry;
342 SilcIDCacheEntry id_cache = NULL;
343 SilcIDCacheList list;
345 if (!silc_idcache_get_all(server->local_list->servers, &list))
348 if (silc_idcache_list_first(list, &id_cache)) {
350 server_entry = (SilcServerEntry)id_cache->context;
351 if (server_entry != from &&
352 SILC_ID_COMPARE(server_entry->id, client->id,
353 client->id->ip.data_len)) {
354 SILC_LOG_DEBUG(("Found (local) %s",
355 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;
370 /* If the client is not marked as local then move it to local list
371 since the server is local. */
372 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
373 SILC_LOG_DEBUG(("Moving client to local list"));
374 silc_idcache_add(server->local_list->clients, client_cache->name,
375 client_cache->id, client_cache->context,
376 client_cache->expire);
377 silc_idcache_del_by_context(server->global_list->clients, client);
381 silc_idcache_list_free(list);
385 if (!silc_idcache_list_next(list, &id_cache))
390 silc_idcache_list_free(list);
392 if (!silc_idcache_get_all(server->global_list->servers, &list))
395 if (silc_idcache_list_first(list, &id_cache)) {
397 server_entry = (SilcServerEntry)id_cache->context;
398 if (server_entry != from &&
399 SILC_ID_COMPARE(server_entry->id, client->id,
400 client->id->ip.data_len)) {
401 SILC_LOG_DEBUG(("Found (global) %s",
402 silc_id_render(server_entry->id, SILC_ID_SERVER)));
404 if (!server_entry->data.send_key && server_entry->router) {
405 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
406 /* If the client is marked as local then move it to global list
407 since the server is global. */
409 SILC_LOG_DEBUG(("Moving client to global list"));
410 silc_idcache_add(server->global_list->clients, client_cache->name,
411 client_cache->id, client_cache->context,
412 client_cache->expire);
413 silc_idcache_del_by_context(server->local_list->clients, client);
415 server_entry = server_entry->router;
417 /* If the client is marked as local then move it to global list
418 since the server is global. */
419 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
420 SILC_LOG_DEBUG(("Moving client to global list"));
421 silc_idcache_add(server->global_list->clients, client_cache->name,
422 client_cache->id, client_cache->context,
423 client_cache->expire);
424 silc_idcache_del_by_context(server->local_list->clients, client);
428 silc_idcache_list_free(list);
432 if (!silc_idcache_list_next(list, &id_cache))
437 silc_idcache_list_free(list);
442 /* Updates the clients that are originated from the `from' to be originated
443 from the `to'. If the `resolve_real_server' is TRUE then this will
444 attempt to figure out which clients really are originated from the
445 `from' and which are originated from a server that we have connection
446 to, when we've acting as backup router. If it is FALSE the `to' will
447 be the new source. This function also removes the clients that are
448 *really* originated from `from' if `remove_from' is TRUE. These are
449 clients that the `from' owns, and not just clients that are behind
452 void silc_server_update_clients_by_server(SilcServer server,
453 SilcServerEntry from,
455 bool resolve_real_server,
458 SilcIDCacheList list = NULL;
459 SilcIDCacheEntry id_cache = NULL;
460 SilcClientEntry client = NULL;
463 SILC_LOG_DEBUG(("Start"));
465 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
467 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
472 if (silc_idcache_get_all(server->global_list->clients, &list)) {
473 if (silc_idcache_list_first(list, &id_cache)) {
475 client = (SilcClientEntry)id_cache->context;
478 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
479 if (!silc_idcache_list_next(list, &id_cache))
485 SILC_LOG_DEBUG(("Client (global) %s",
486 silc_id_render(client->id, SILC_ID_CLIENT)));
488 SILC_LOG_DEBUG(("Client->router (global) %s",
489 silc_id_render(client->router->id, SILC_ID_SERVER)));
491 if (client->router == from) {
492 /* Skip clients that are *really* owned by the `from' */
493 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
494 client->id->ip.data_len)) {
495 SILC_LOG_DEBUG(("Found really owned client, skip it"));
496 if (!silc_idcache_list_next(list, &id_cache))
502 if (resolve_real_server) {
504 silc_server_update_clients_by_real_server(server, from, client,
513 if (!silc_idcache_list_next(list, &id_cache))
517 silc_idcache_list_free(list);
521 if (silc_idcache_get_all(server->local_list->clients, &list)) {
522 if (silc_idcache_list_first(list, &id_cache)) {
524 client = (SilcClientEntry)id_cache->context;
526 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
527 if (!silc_idcache_list_next(list, &id_cache))
533 SILC_LOG_DEBUG(("Client (local) %s",
534 silc_id_render(client->id, SILC_ID_CLIENT)));
536 SILC_LOG_DEBUG(("Client->router (local) %s",
537 silc_id_render(client->router->id, SILC_ID_SERVER)));
539 if (client->router == from) {
540 /* Skip clients that are *really* owned by the `from' */
541 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
542 client->id->ip.data_len)) {
543 SILC_LOG_DEBUG(("Found really owned client, skip it"));
544 if (!silc_idcache_list_next(list, &id_cache))
550 if (resolve_real_server) {
552 silc_server_update_clients_by_real_server(server, from, client,
555 client->router = from; /* on local list put old from */
561 if (!silc_idcache_list_next(list, &id_cache))
565 silc_idcache_list_free(list);
569 /* Now remove the clients that are still marked as orignated from the
570 `from'. These are the clients that really was owned by the `from' and
571 not just exist behind the `from'. */
572 silc_server_remove_clients_by_server(server, from, TRUE);
575 /* Updates servers that are from `from' to be originated from `to'. This
576 will also update the server's connection to `to's connection. */
578 void silc_server_update_servers_by_server(SilcServer server,
579 SilcServerEntry from,
582 SilcIDCacheList list = NULL;
583 SilcIDCacheEntry id_cache = NULL;
584 SilcServerEntry server_entry = NULL;
586 SILC_LOG_DEBUG(("Start"));
588 if (silc_idcache_get_all(server->local_list->servers, &list)) {
589 if (silc_idcache_list_first(list, &id_cache)) {
591 server_entry = (SilcServerEntry)id_cache->context;
592 if (server_entry->router == from) {
593 server_entry->router = to;
594 server_entry->connection = to->connection;
596 if (!silc_idcache_list_next(list, &id_cache))
600 silc_idcache_list_free(list);
603 if (silc_idcache_get_all(server->global_list->servers, &list)) {
604 if (silc_idcache_list_first(list, &id_cache)) {
606 server_entry = (SilcServerEntry)id_cache->context;
607 if (server_entry->router == from) {
608 server_entry->router = to;
609 server_entry->connection = to->connection;
611 if (!silc_idcache_list_next(list, &id_cache))
615 silc_idcache_list_free(list);
619 /* Checks whether given channel has global users. If it does this returns
620 TRUE and FALSE if there is only locally connected clients on the channel. */
622 bool silc_server_channel_has_global(SilcChannelEntry channel)
624 SilcChannelClientEntry chl;
625 SilcHashTableList htl;
627 silc_hash_table_list(channel->user_list, &htl);
628 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
629 if (chl->client->router)
636 /* Checks whether given channel has locally connected users. If it does this
637 returns TRUE and FALSE if there is not one locally connected client. */
639 bool silc_server_channel_has_local(SilcChannelEntry channel)
641 SilcChannelClientEntry chl;
642 SilcHashTableList htl;
644 silc_hash_table_list(channel->user_list, &htl);
645 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
646 if (!chl->client->router)
653 /* Returns TRUE if the given client is on the channel. FALSE if not.
654 This works because we assure that the user list on the channel is
655 always in up to date thus we can only check the channel list from
656 `client' which is faster than checking the user list from `channel'. */
658 bool silc_server_client_on_channel(SilcClientEntry client,
659 SilcChannelEntry channel)
661 if (!client || !channel)
664 if (silc_hash_table_find(client->channels, channel, NULL, NULL))