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)));
356 /* If the client is not marked as local then move it to local list
357 since the server is local. */
358 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
359 SILC_LOG_DEBUG(("Moving client to local list"));
360 silc_idcache_add(server->local_list->clients, client_cache->name,
361 client_cache->id, client_cache->context,
362 client_cache->expire);
363 silc_idcache_del_by_context(server->global_list->clients, client);
366 silc_idcache_list_free(list);
370 if (!silc_idcache_list_next(list, &id_cache))
375 silc_idcache_list_free(list);
377 if (!silc_idcache_get_all(server->global_list->servers, &list))
380 if (silc_idcache_list_first(list, &id_cache)) {
382 server_entry = (SilcServerEntry)id_cache->context;
383 if (server_entry != from &&
384 SILC_ID_COMPARE(server_entry->id, client->id,
385 client->id->ip.data_len)) {
386 SILC_LOG_DEBUG(("Found (global) %s",
387 silc_id_render(server_entry->id, SILC_ID_SERVER)));
389 /* If the client is marked as local then move it to global list
390 since the server is global. */
391 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
392 SILC_LOG_DEBUG(("Moving client to global list"));
393 silc_idcache_add(server->global_list->clients, client_cache->name,
394 client_cache->id, client_cache->context,
395 client_cache->expire);
396 silc_idcache_del_by_context(server->local_list->clients, client);
399 silc_idcache_list_free(list);
403 if (!silc_idcache_list_next(list, &id_cache))
408 silc_idcache_list_free(list);
413 /* Updates the clients that are originated from the `from' to be originated
414 from the `to'. If the `resolve_real_server' is TRUE then this will
415 attempt to figure out which clients really are originated from the
416 `from' and which are originated from a server that we have connection
417 to, when we've acting as backup router. If it is FALSE the `to' will
418 be the new source. This function also removes the clients that are
419 *really* originated from `from' if `remove_from' is TRUE. These are
420 clients that the `from' owns, and not just clients that are behind
423 void silc_server_update_clients_by_server(SilcServer server,
424 SilcServerEntry from,
426 bool resolve_real_server,
429 SilcIDCacheList list = NULL;
430 SilcIDCacheEntry id_cache = NULL;
431 SilcClientEntry client = NULL;
434 SILC_LOG_DEBUG(("Start"));
436 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
438 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
443 if (silc_idcache_get_all(server->global_list->clients, &list)) {
444 if (silc_idcache_list_first(list, &id_cache)) {
446 client = (SilcClientEntry)id_cache->context;
449 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
450 if (!silc_idcache_list_next(list, &id_cache))
456 SILC_LOG_DEBUG(("Client (global) %s",
457 silc_id_render(client->id, SILC_ID_CLIENT)));
459 SILC_LOG_DEBUG(("Client->router (global) %s",
460 silc_id_render(client->router->id, SILC_ID_SERVER)));
462 if (client->router == from) {
463 /* Skip clients that are *really* owned by the `from' */
464 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
465 client->id->ip.data_len)) {
466 SILC_LOG_DEBUG(("Found really owned client, skip it"));
467 if (!silc_idcache_list_next(list, &id_cache))
473 if (resolve_real_server) {
475 silc_server_update_clients_by_real_server(server, from, client,
484 if (!silc_idcache_list_next(list, &id_cache))
488 silc_idcache_list_free(list);
492 if (silc_idcache_get_all(server->local_list->clients, &list)) {
493 if (silc_idcache_list_first(list, &id_cache)) {
495 client = (SilcClientEntry)id_cache->context;
497 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
498 if (!silc_idcache_list_next(list, &id_cache))
504 SILC_LOG_DEBUG(("Client (local) %s",
505 silc_id_render(client->id, SILC_ID_CLIENT)));
507 SILC_LOG_DEBUG(("Client->router (local) %s",
508 silc_id_render(client->router->id, SILC_ID_SERVER)));
510 if (client->router == from) {
511 /* Skip clients that are *really* owned by the `from' */
512 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
513 client->id->ip.data_len)) {
514 SILC_LOG_DEBUG(("Found really owned client, skip it"));
515 if (!silc_idcache_list_next(list, &id_cache))
521 if (resolve_real_server) {
523 silc_server_update_clients_by_real_server(server, from, client,
526 client->router = from; /* on local list put old from */
532 if (!silc_idcache_list_next(list, &id_cache))
536 silc_idcache_list_free(list);
540 /* Now remove the clients that are still marked as orignated from the
541 `from'. These are the clients that really was owned by the `from' and
542 not just exist behind the `from'. */
543 silc_server_remove_clients_by_server(server, from, TRUE);
546 /* Updates servers that are from `from' to be originated from `to'. This
547 will also update the server's connection to `to's connection. */
549 void silc_server_update_servers_by_server(SilcServer server,
550 SilcServerEntry from,
553 SilcIDCacheList list = NULL;
554 SilcIDCacheEntry id_cache = NULL;
555 SilcServerEntry server_entry = NULL;
557 SILC_LOG_DEBUG(("Start"));
559 if (silc_idcache_get_all(server->local_list->servers, &list)) {
560 if (silc_idcache_list_first(list, &id_cache)) {
562 server_entry = (SilcServerEntry)id_cache->context;
563 if (server_entry->router == from) {
564 server_entry->router = to;
565 server_entry->connection = to->connection;
567 if (!silc_idcache_list_next(list, &id_cache))
571 silc_idcache_list_free(list);
574 if (silc_idcache_get_all(server->global_list->servers, &list)) {
575 if (silc_idcache_list_first(list, &id_cache)) {
577 server_entry = (SilcServerEntry)id_cache->context;
578 if (server_entry->router == from) {
579 server_entry->router = to;
580 server_entry->connection = to->connection;
582 if (!silc_idcache_list_next(list, &id_cache))
586 silc_idcache_list_free(list);
590 /* Checks whether given channel has global users. If it does this returns
591 TRUE and FALSE if there is only locally connected clients on the channel. */
593 bool silc_server_channel_has_global(SilcChannelEntry channel)
595 SilcChannelClientEntry chl;
596 SilcHashTableList htl;
598 silc_hash_table_list(channel->user_list, &htl);
599 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
600 if (chl->client->router)
607 /* Checks whether given channel has locally connected users. If it does this
608 returns TRUE and FALSE if there is not one locally connected client. */
610 bool silc_server_channel_has_local(SilcChannelEntry channel)
612 SilcChannelClientEntry chl;
613 SilcHashTableList htl;
615 silc_hash_table_list(channel->user_list, &htl);
616 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
617 if (!chl->client->router)
624 /* Returns TRUE if the given client is on the channel. FALSE if not.
625 This works because we assure that the user list on the channel is
626 always in up to date thus we can only check the channel list from
627 `client' which is faster than checking the user list from `channel'. */
629 bool silc_server_client_on_channel(SilcClientEntry client,
630 SilcChannelEntry channel)
632 if (!client || !channel)
635 if (silc_hash_table_find(client->channels, channel, NULL, NULL))