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);
108 silc_hash_table_list_reset(&htl2);
112 /* Remove the channel entry */
113 if (silc_idlist_del_channel(server->local_list, channel))
114 server->stat.my_channels--;
116 silc_idlist_del_channel(server->global_list, channel);
120 /* Add the channel to the the channels list to regenerate the
122 if (!silc_hash_table_find(channels, channel, NULL, NULL))
123 silc_hash_table_add(channels, channel, channel);
125 silc_hash_table_list_reset(&htl);
127 silc_buffer_free(clidp);
130 /* This function is used to remove all client entries by the server `entry'.
131 This is called when the connection is lost to the server. In this case
132 we must invalidate all the client entries owned by the server `entry'.
133 If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
134 distributed to our local clients. */
136 bool silc_server_remove_clients_by_server(SilcServer server,
137 SilcServerEntry entry,
140 SilcIDCacheList list = NULL;
141 SilcIDCacheEntry id_cache = NULL;
142 SilcClientEntry client = NULL;
144 SilcClientEntry *clients = NULL;
145 uint32 clients_c = 0;
146 unsigned char **argv = NULL;
147 uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
148 SilcHashTableList htl;
149 SilcChannelEntry channel;
150 SilcHashTable channels;
153 SILC_LOG_DEBUG(("Start"));
155 /* Allocate the hash table that holds the channels that require
156 channel key re-generation after we've removed this server's clients
157 from the channels. */
158 channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
161 if (server_signoff) {
162 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
163 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
164 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
165 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
166 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
167 memcpy(argv[argc], idp->data, idp->len);
168 argv_lens[argc] = idp->len;
169 argv_types[argc] = argc + 1;
171 silc_buffer_free(idp);
174 if (silc_idcache_get_all(server->local_list->clients, &list)) {
176 if (silc_idcache_list_first(list, &id_cache)) {
178 client = (SilcClientEntry)id_cache->context;
179 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
180 if (!silc_idcache_list_next(list, &id_cache))
186 if (client->router != entry) {
187 if (server_signoff) {
188 clients = silc_realloc(clients,
189 sizeof(*clients) * (clients_c + 1));
190 clients[clients_c] = client;
194 if (!silc_idcache_list_next(list, &id_cache))
200 if (server_signoff) {
201 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
202 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
203 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
205 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
207 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
208 memcpy(argv[argc], idp->data, idp->len);
209 argv_lens[argc] = idp->len;
210 argv_types[argc] = argc + 1;
212 silc_buffer_free(idp);
215 /* Update statistics */
216 server->stat.clients--;
217 if (server->server_type == SILC_ROUTER)
218 server->stat.cell_clients--;
219 SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
220 SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
222 /* Remove the client entry */
223 silc_server_remove_clients_channels(server, NULL, client, channels);
224 if (!server_signoff) {
225 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
226 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
228 silc_idlist_del_client(server->local_list, client);
231 if (!silc_idcache_list_next(list, &id_cache))
235 silc_idcache_list_free(list);
238 if (silc_idcache_get_all(server->global_list->clients, &list)) {
240 if (silc_idcache_list_first(list, &id_cache)) {
242 client = (SilcClientEntry)id_cache->context;
243 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
244 if (!silc_idcache_list_next(list, &id_cache))
250 if (client->router != entry) {
251 if (server_signoff && client->connection) {
252 clients = silc_realloc(clients,
253 sizeof(*clients) * (clients_c + 1));
254 clients[clients_c] = client;
258 if (!silc_idcache_list_next(list, &id_cache))
264 if (server_signoff) {
265 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
266 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
267 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
269 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
271 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
272 memcpy(argv[argc], idp->data, idp->len);
273 argv_lens[argc] = idp->len;
274 argv_types[argc] = argc + 1;
276 silc_buffer_free(idp);
279 /* Update statistics */
280 server->stat.clients--;
281 if (server->server_type == SILC_ROUTER)
282 server->stat.cell_clients--;
283 SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
284 SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
286 /* Remove the client entry */
287 silc_server_remove_clients_channels(server, NULL, client, channels);
288 if (!server_signoff) {
289 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
290 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
292 silc_idlist_del_client(server->global_list, client);
295 if (!silc_idcache_list_next(list, &id_cache))
299 silc_idcache_list_free(list);
302 /* Send the SERVER_SIGNOFF notify */
303 if (server_signoff) {
304 SilcBuffer args, not;
306 /* Send SERVER_SIGNOFF notify to our primary router */
307 if (!server->standalone && server->router &&
308 server->router != entry) {
309 args = silc_argument_payload_encode(1, argv, argv_lens,
311 silc_server_send_notify_args(server,
312 server->router->connection,
313 server->server_type == SILC_SERVER ?
315 SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
317 silc_buffer_free(args);
320 /* Send to local clients. We also send the list of client ID's that
321 is to be removed for those servers that would like to use that list. */
322 args = silc_argument_payload_encode(argc, argv, argv_lens,
324 not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
326 silc_server_packet_send_clients(server, clients, clients_c,
327 SILC_PACKET_NOTIFY, 0, FALSE,
328 not->data, not->len, FALSE);
331 silc_buffer_free(args);
332 silc_buffer_free(not);
333 for (i = 0; i < argc; i++)
336 silc_free(argv_lens);
337 silc_free(argv_types);
340 /* We must now re-generate the channel key for all channels that had
341 this server's client(s) on the channel. As they left the channel we
342 must re-generate the channel key. */
343 silc_hash_table_list(channels, &htl);
344 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
345 if (!silc_server_create_channel_key(server, channel, 0)) {
346 silc_hash_table_list_reset(&htl);
347 silc_hash_table_free(channels);
351 /* Do not send the channel key if private channel key mode is set */
352 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
355 silc_server_send_channel_key(server, NULL, channel,
356 server->server_type == SILC_ROUTER ?
357 FALSE : !server->standalone);
359 silc_hash_table_list_reset(&htl);
360 silc_hash_table_free(channels);
365 static SilcServerEntry
366 silc_server_update_clients_by_real_server(SilcServer server,
367 SilcServerEntry from,
368 SilcClientEntry client,
370 SilcIDCacheEntry client_cache)
372 SilcServerEntry server_entry;
373 SilcIDCacheEntry id_cache = NULL;
374 SilcIDCacheList list;
376 if (!silc_idcache_get_all(server->local_list->servers, &list))
379 if (silc_idcache_list_first(list, &id_cache)) {
381 server_entry = (SilcServerEntry)id_cache->context;
382 if (server_entry != from &&
383 SILC_ID_COMPARE(server_entry->id, client->id,
384 client->id->ip.data_len)) {
385 SILC_LOG_DEBUG(("Found (local) %s",
386 silc_id_render(server_entry->id, SILC_ID_SERVER)));
388 if (!server_entry->data.send_key && server_entry->router) {
389 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
390 /* If the client is not marked as local then move it to local list
391 since the server is local. */
393 SILC_LOG_DEBUG(("Moving client to local list"));
394 silc_idcache_add(server->local_list->clients, client_cache->name,
395 client_cache->id, client_cache->context,
396 client_cache->expire, NULL);
397 silc_idcache_del_by_context(server->global_list->clients, client);
399 server_entry = server_entry->router;
401 /* If the client is not marked as local then move it to local list
402 since the server is local. */
403 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
404 SILC_LOG_DEBUG(("Moving client to local list"));
405 silc_idcache_add(server->local_list->clients, client_cache->name,
406 client_cache->id, client_cache->context,
407 client_cache->expire, NULL);
408 silc_idcache_del_by_context(server->global_list->clients, client);
412 silc_idcache_list_free(list);
416 if (!silc_idcache_list_next(list, &id_cache))
421 silc_idcache_list_free(list);
423 if (!silc_idcache_get_all(server->global_list->servers, &list))
426 if (silc_idcache_list_first(list, &id_cache)) {
428 server_entry = (SilcServerEntry)id_cache->context;
429 if (server_entry != from &&
430 SILC_ID_COMPARE(server_entry->id, client->id,
431 client->id->ip.data_len)) {
432 SILC_LOG_DEBUG(("Found (global) %s",
433 silc_id_render(server_entry->id, SILC_ID_SERVER)));
435 if (!server_entry->data.send_key && server_entry->router) {
436 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
437 /* If the client is marked as local then move it to global list
438 since the server is global. */
440 SILC_LOG_DEBUG(("Moving client to global list"));
441 silc_idcache_add(server->global_list->clients, client_cache->name,
442 client_cache->id, client_cache->context,
443 client_cache->expire, NULL);
444 silc_idcache_del_by_context(server->local_list->clients, client);
446 server_entry = server_entry->router;
448 /* If the client is marked as local then move it to global list
449 since the server is global. */
450 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
451 SILC_LOG_DEBUG(("Moving client to global list"));
452 silc_idcache_add(server->global_list->clients, client_cache->name,
453 client_cache->id, client_cache->context,
454 client_cache->expire, NULL);
455 silc_idcache_del_by_context(server->local_list->clients, client);
459 silc_idcache_list_free(list);
463 if (!silc_idcache_list_next(list, &id_cache))
468 silc_idcache_list_free(list);
473 /* Updates the clients that are originated from the `from' to be originated
474 from the `to'. If the `resolve_real_server' is TRUE then this will
475 attempt to figure out which clients really are originated from the
476 `from' and which are originated from a server that we have connection
477 to, when we've acting as backup router. If it is FALSE the `to' will
478 be the new source. This function also removes the clients that are
479 *really* originated from `from' if `remove_from' is TRUE. These are
480 clients that the `from' owns, and not just clients that are behind
483 void silc_server_update_clients_by_server(SilcServer server,
484 SilcServerEntry from,
486 bool resolve_real_server,
489 SilcIDCacheList list = NULL;
490 SilcIDCacheEntry id_cache = NULL;
491 SilcClientEntry client = NULL;
494 SILC_LOG_DEBUG(("Start"));
496 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
498 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
503 if (silc_idcache_get_all(server->global_list->clients, &list)) {
504 if (silc_idcache_list_first(list, &id_cache)) {
506 client = (SilcClientEntry)id_cache->context;
507 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
508 if (!silc_idcache_list_next(list, &id_cache))
514 SILC_LOG_DEBUG(("Client (global) %s",
515 silc_id_render(client->id, SILC_ID_CLIENT)));
517 SILC_LOG_DEBUG(("Client->router (global) %s",
518 silc_id_render(client->router->id, SILC_ID_SERVER)));
520 if (client->router == from) {
521 /* Skip clients that are *really* owned by the `from' */
522 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
523 client->id->ip.data_len)) {
524 SILC_LOG_DEBUG(("Found really owned client, skip it"));
525 if (!silc_idcache_list_next(list, &id_cache))
531 if (resolve_real_server) {
533 silc_server_update_clients_by_real_server(server, from, client,
542 if (!silc_idcache_list_next(list, &id_cache))
546 silc_idcache_list_free(list);
550 if (silc_idcache_get_all(server->local_list->clients, &list)) {
551 if (silc_idcache_list_first(list, &id_cache)) {
553 client = (SilcClientEntry)id_cache->context;
554 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
555 if (!silc_idcache_list_next(list, &id_cache))
561 SILC_LOG_DEBUG(("Client (local) %s",
562 silc_id_render(client->id, SILC_ID_CLIENT)));
564 SILC_LOG_DEBUG(("Client->router (local) %s",
565 silc_id_render(client->router->id, SILC_ID_SERVER)));
567 if (client->router == from) {
568 /* Skip clients that are *really* owned by the `from' */
569 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
570 client->id->ip.data_len)) {
571 SILC_LOG_DEBUG(("Found really owned client, skip it"));
572 if (!silc_idcache_list_next(list, &id_cache))
578 if (resolve_real_server) {
580 silc_server_update_clients_by_real_server(server, from, client,
583 client->router = from; /* on local list put old from */
589 if (!silc_idcache_list_next(list, &id_cache))
593 silc_idcache_list_free(list);
597 /* Now remove the clients that are still marked as orignated from the
598 `from'. These are the clients that really was owned by the `from' and
599 not just exist behind the `from'. */
600 silc_server_remove_clients_by_server(server, from, TRUE);
603 /* Updates servers that are from `from' to be originated from `to'. This
604 will also update the server's connection to `to's connection. */
606 void silc_server_update_servers_by_server(SilcServer server,
607 SilcServerEntry from,
610 SilcIDCacheList list = NULL;
611 SilcIDCacheEntry id_cache = NULL;
612 SilcServerEntry server_entry = NULL;
614 SILC_LOG_DEBUG(("Start"));
616 if (silc_idcache_get_all(server->local_list->servers, &list)) {
617 if (silc_idcache_list_first(list, &id_cache)) {
619 server_entry = (SilcServerEntry)id_cache->context;
620 if (server_entry->router == from) {
621 server_entry->router = to;
622 server_entry->connection = to->connection;
624 if (!silc_idcache_list_next(list, &id_cache))
628 silc_idcache_list_free(list);
631 if (silc_idcache_get_all(server->global_list->servers, &list)) {
632 if (silc_idcache_list_first(list, &id_cache)) {
634 server_entry = (SilcServerEntry)id_cache->context;
635 if (server_entry->router == from) {
636 server_entry->router = to;
637 server_entry->connection = to->connection;
639 if (!silc_idcache_list_next(list, &id_cache))
643 silc_idcache_list_free(list);
647 /* Removes channels that are from `from. */
649 void silc_server_remove_channels_by_server(SilcServer server,
650 SilcServerEntry from)
652 SilcIDCacheList list = NULL;
653 SilcIDCacheEntry id_cache = NULL;
654 SilcChannelEntry channel = NULL;
656 SILC_LOG_DEBUG(("Start"));
658 if (silc_idcache_get_all(server->global_list->channels, &list)) {
659 if (silc_idcache_list_first(list, &id_cache)) {
661 channel = (SilcChannelEntry)id_cache->context;
662 if (channel->router == from)
663 silc_idlist_del_channel(server->global_list, channel);
664 if (!silc_idcache_list_next(list, &id_cache))
668 silc_idcache_list_free(list);
672 /* Updates channels that are from `from' to be originated from `to'. */
674 void silc_server_update_channels_by_server(SilcServer server,
675 SilcServerEntry from,
678 SilcIDCacheList list = NULL;
679 SilcIDCacheEntry id_cache = NULL;
680 SilcChannelEntry channel = NULL;
682 SILC_LOG_DEBUG(("Start"));
684 if (silc_idcache_get_all(server->global_list->channels, &list)) {
685 if (silc_idcache_list_first(list, &id_cache)) {
687 channel = (SilcChannelEntry)id_cache->context;
688 if (channel->router == from)
689 channel->router = to;
690 if (!silc_idcache_list_next(list, &id_cache))
694 silc_idcache_list_free(list);
698 /* Checks whether given channel has global users. If it does this returns
699 TRUE and FALSE if there is only locally connected clients on the channel. */
701 bool silc_server_channel_has_global(SilcChannelEntry channel)
703 SilcChannelClientEntry chl;
704 SilcHashTableList htl;
706 silc_hash_table_list(channel->user_list, &htl);
707 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
708 if (chl->client->router) {
709 silc_hash_table_list_reset(&htl);
713 silc_hash_table_list_reset(&htl);
718 /* Checks whether given channel has locally connected users. If it does this
719 returns TRUE and FALSE if there is not one locally connected client. */
721 bool silc_server_channel_has_local(SilcChannelEntry channel)
723 SilcChannelClientEntry chl;
724 SilcHashTableList htl;
726 silc_hash_table_list(channel->user_list, &htl);
727 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
728 if (!chl->client->router) {
729 silc_hash_table_list_reset(&htl);
733 silc_hash_table_list_reset(&htl);
738 /* Returns TRUE if the given client is on the channel. FALSE if not.
739 This works because we assure that the user list on the channel is
740 always in up to date thus we can only check the channel list from
741 `client' which is faster than checking the user list from `channel'. */
743 bool silc_server_client_on_channel(SilcClientEntry client,
744 SilcChannelEntry channel)
746 if (!client || !channel)
749 return silc_hash_table_find(client->channels, channel, NULL, NULL);
752 /* Checks string for bad characters and returns TRUE if they are found. */
754 bool silc_server_name_bad_chars(const char *name, uint32 name_len)
758 for (i = 0; i < name_len; i++) {
759 if (!isascii(name[i]))
761 if (name[i] <= 32) return TRUE;
762 if (name[i] == ' ') return TRUE;
763 if (name[i] == '*') return TRUE;
764 if (name[i] == '?') return TRUE;
765 if (name[i] == ',') return TRUE;
771 /* Modifies the `name' if it includes bad characters and returns new
772 allocated name that does not include bad characters. */
774 char *silc_server_name_modify_bad(const char *name, uint32 name_len)
777 char *newname = strdup(name);
779 for (i = 0; i < name_len; i++) {
780 if (!isascii(newname[i])) newname[i] = '_';
781 if (newname[i] <= 32) newname[i] = '_';
782 if (newname[i] == ' ') newname[i] = '_';
783 if (newname[i] == '*') newname[i] = '_';
784 if (newname[i] == '?') newname[i] = '_';
785 if (newname[i] == ',') newname[i] = '_';
791 /* Find number of sockets by IP address indicated by `ip'. Returns 0 if
792 socket connections with the IP address does not exist. */
794 uint32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip)
798 for (i = 0, count = 0; i < server->config->param.connections_max; i++) {
799 if (server->sockets[i] && !strcmp(server->sockets[i]->ip, ip))