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 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
216 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
217 server->stat.clients--;
218 if (server->server_type == SILC_ROUTER)
219 server->stat.cell_clients--;
221 if (!silc_idcache_list_next(list, &id_cache))
225 silc_idcache_list_free(list);
228 if (silc_idcache_get_all(server->global_list->clients, &list)) {
230 if (silc_idcache_list_first(list, &id_cache)) {
232 client = (SilcClientEntry)id_cache->context;
233 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
234 if (!silc_idcache_list_next(list, &id_cache))
240 if (client->router != entry) {
241 if (server_signoff && client->connection) {
242 clients = silc_realloc(clients,
243 sizeof(*clients) * (clients_c + 1));
244 clients[clients_c] = client;
248 if (!silc_idcache_list_next(list, &id_cache))
254 if (server_signoff) {
255 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
256 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
257 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
259 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
261 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
262 memcpy(argv[argc], idp->data, idp->len);
263 argv_lens[argc] = idp->len;
264 argv_types[argc] = argc + 1;
266 silc_buffer_free(idp);
269 /* Remove the client entry */
270 silc_server_remove_clients_channels(server, NULL, client, channels);
271 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
272 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
273 server->stat.clients--;
274 if (server->server_type == SILC_ROUTER)
275 server->stat.cell_clients--;
277 if (!silc_idcache_list_next(list, &id_cache))
281 silc_idcache_list_free(list);
284 /* Send the SERVER_SIGNOFF notify */
285 if (server_signoff) {
286 SilcBuffer args, not;
288 /* Send SERVER_SIGNOFF notify to our primary router */
289 if (!server->standalone && server->router &&
290 server->router != entry) {
291 args = silc_argument_payload_encode(1, argv, argv_lens,
293 silc_server_send_notify_args(server,
294 server->router->connection,
295 server->server_type == SILC_SERVER ?
297 SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
299 silc_buffer_free(args);
302 /* Send to local clients. We also send the list of client ID's that
303 is to be removed for those servers that would like to use that list. */
304 args = silc_argument_payload_encode(argc, argv, argv_lens,
306 not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
308 silc_server_packet_send_clients(server, clients, clients_c,
309 SILC_PACKET_NOTIFY, 0, FALSE,
310 not->data, not->len, FALSE);
313 silc_buffer_free(args);
314 silc_buffer_free(not);
315 for (i = 0; i < argc; i++)
318 silc_free(argv_lens);
319 silc_free(argv_types);
322 /* We must now re-generate the channel key for all channels that had
323 this server's client(s) on the channel. As they left the channel we
324 must re-generate the channel key. */
325 silc_hash_table_list(channels, &htl);
326 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
327 if (!silc_server_create_channel_key(server, channel, 0))
330 /* Do not send the channel key if private channel key mode is set */
331 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
334 silc_server_send_channel_key(server, NULL, channel,
335 server->server_type == SILC_ROUTER ?
336 FALSE : !server->standalone);
338 silc_hash_table_free(channels);
343 static SilcServerEntry
344 silc_server_update_clients_by_real_server(SilcServer server,
345 SilcServerEntry from,
346 SilcClientEntry client,
348 SilcIDCacheEntry client_cache)
350 SilcServerEntry server_entry;
351 SilcIDCacheEntry id_cache = NULL;
352 SilcIDCacheList list;
354 if (!silc_idcache_get_all(server->local_list->servers, &list))
357 if (silc_idcache_list_first(list, &id_cache)) {
359 server_entry = (SilcServerEntry)id_cache->context;
360 if (server_entry != from &&
361 SILC_ID_COMPARE(server_entry->id, client->id,
362 client->id->ip.data_len)) {
363 SILC_LOG_DEBUG(("Found (local) %s",
364 silc_id_render(server_entry->id, SILC_ID_SERVER)));
366 if (!server_entry->data.send_key && server_entry->router) {
367 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
368 /* If the client is not marked as local then move it to local list
369 since the server is local. */
371 SILC_LOG_DEBUG(("Moving client to local list"));
372 silc_idcache_add(server->local_list->clients, client_cache->name,
373 client_cache->id, client_cache->context,
374 client_cache->expire);
375 silc_idcache_del_by_context(server->global_list->clients, client);
377 server_entry = server_entry->router;
379 /* If the client is not marked as local then move it to local list
380 since the server is local. */
381 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
382 SILC_LOG_DEBUG(("Moving client to local list"));
383 silc_idcache_add(server->local_list->clients, client_cache->name,
384 client_cache->id, client_cache->context,
385 client_cache->expire);
386 silc_idcache_del_by_context(server->global_list->clients, client);
390 silc_idcache_list_free(list);
394 if (!silc_idcache_list_next(list, &id_cache))
399 silc_idcache_list_free(list);
401 if (!silc_idcache_get_all(server->global_list->servers, &list))
404 if (silc_idcache_list_first(list, &id_cache)) {
406 server_entry = (SilcServerEntry)id_cache->context;
407 if (server_entry != from &&
408 SILC_ID_COMPARE(server_entry->id, client->id,
409 client->id->ip.data_len)) {
410 SILC_LOG_DEBUG(("Found (global) %s",
411 silc_id_render(server_entry->id, SILC_ID_SERVER)));
413 if (!server_entry->data.send_key && server_entry->router) {
414 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
415 /* If the client is marked as local then move it to global list
416 since the server is global. */
418 SILC_LOG_DEBUG(("Moving client to global list"));
419 silc_idcache_add(server->global_list->clients, client_cache->name,
420 client_cache->id, client_cache->context,
421 client_cache->expire);
422 silc_idcache_del_by_context(server->local_list->clients, client);
424 server_entry = server_entry->router;
426 /* If the client is marked as local then move it to global list
427 since the server is global. */
428 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
429 SILC_LOG_DEBUG(("Moving client to global list"));
430 silc_idcache_add(server->global_list->clients, client_cache->name,
431 client_cache->id, client_cache->context,
432 client_cache->expire);
433 silc_idcache_del_by_context(server->local_list->clients, client);
437 silc_idcache_list_free(list);
441 if (!silc_idcache_list_next(list, &id_cache))
446 silc_idcache_list_free(list);
451 /* Updates the clients that are originated from the `from' to be originated
452 from the `to'. If the `resolve_real_server' is TRUE then this will
453 attempt to figure out which clients really are originated from the
454 `from' and which are originated from a server that we have connection
455 to, when we've acting as backup router. If it is FALSE the `to' will
456 be the new source. This function also removes the clients that are
457 *really* originated from `from' if `remove_from' is TRUE. These are
458 clients that the `from' owns, and not just clients that are behind
461 void silc_server_update_clients_by_server(SilcServer server,
462 SilcServerEntry from,
464 bool resolve_real_server,
467 SilcIDCacheList list = NULL;
468 SilcIDCacheEntry id_cache = NULL;
469 SilcClientEntry client = NULL;
472 SILC_LOG_DEBUG(("Start"));
474 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
476 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
481 if (silc_idcache_get_all(server->global_list->clients, &list)) {
482 if (silc_idcache_list_first(list, &id_cache)) {
484 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;
532 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
533 if (!silc_idcache_list_next(list, &id_cache))
539 SILC_LOG_DEBUG(("Client (local) %s",
540 silc_id_render(client->id, SILC_ID_CLIENT)));
542 SILC_LOG_DEBUG(("Client->router (local) %s",
543 silc_id_render(client->router->id, SILC_ID_SERVER)));
545 if (client->router == from) {
546 /* Skip clients that are *really* owned by the `from' */
547 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
548 client->id->ip.data_len)) {
549 SILC_LOG_DEBUG(("Found really owned client, skip it"));
550 if (!silc_idcache_list_next(list, &id_cache))
556 if (resolve_real_server) {
558 silc_server_update_clients_by_real_server(server, from, client,
561 client->router = from; /* on local list put old from */
567 if (!silc_idcache_list_next(list, &id_cache))
571 silc_idcache_list_free(list);
575 /* Now remove the clients that are still marked as orignated from the
576 `from'. These are the clients that really was owned by the `from' and
577 not just exist behind the `from'. */
578 silc_server_remove_clients_by_server(server, from, TRUE);
581 /* Updates servers that are from `from' to be originated from `to'. This
582 will also update the server's connection to `to's connection. */
584 void silc_server_update_servers_by_server(SilcServer server,
585 SilcServerEntry from,
588 SilcIDCacheList list = NULL;
589 SilcIDCacheEntry id_cache = NULL;
590 SilcServerEntry server_entry = NULL;
592 SILC_LOG_DEBUG(("Start"));
594 if (silc_idcache_get_all(server->local_list->servers, &list)) {
595 if (silc_idcache_list_first(list, &id_cache)) {
597 server_entry = (SilcServerEntry)id_cache->context;
598 if (server_entry->router == from) {
599 server_entry->router = to;
600 server_entry->connection = to->connection;
602 if (!silc_idcache_list_next(list, &id_cache))
606 silc_idcache_list_free(list);
609 if (silc_idcache_get_all(server->global_list->servers, &list)) {
610 if (silc_idcache_list_first(list, &id_cache)) {
612 server_entry = (SilcServerEntry)id_cache->context;
613 if (server_entry->router == from) {
614 server_entry->router = to;
615 server_entry->connection = to->connection;
617 if (!silc_idcache_list_next(list, &id_cache))
621 silc_idcache_list_free(list);
625 /* Checks whether given channel has global users. If it does this returns
626 TRUE and FALSE if there is only locally connected clients on the channel. */
628 bool silc_server_channel_has_global(SilcChannelEntry channel)
630 SilcChannelClientEntry chl;
631 SilcHashTableList htl;
633 silc_hash_table_list(channel->user_list, &htl);
634 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
635 if (chl->client->router)
642 /* Checks whether given channel has locally connected users. If it does this
643 returns TRUE and FALSE if there is not one locally connected client. */
645 bool silc_server_channel_has_local(SilcChannelEntry channel)
647 SilcChannelClientEntry chl;
648 SilcHashTableList htl;
650 silc_hash_table_list(channel->user_list, &htl);
651 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
652 if (!chl->client->router)
659 /* Returns TRUE if the given client is on the channel. FALSE if not.
660 This works because we assure that the user list on the channel is
661 always in up to date thus we can only check the channel list from
662 `client' which is faster than checking the user list from `channel'. */
664 bool silc_server_client_on_channel(SilcClientEntry client,
665 SilcChannelEntry channel)
667 if (!client || !channel)
670 if (silc_hash_table_find(client->channels, channel, NULL, NULL))