1 /*
2
3 server_util.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 1997 - 2005 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id: server_util.c,v 1.77 2005/04/23 13:32:25 priikone Exp $ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
24 extern char *server_version;
25
26 /* Removes the client from channels and possibly removes the channels
27 as well. After removing those channels that exist, their channel
28 keys are regnerated. This is called only by the function
29 silc_server_remove_clients_by_server. */
30
31 static void
32 silc_server_remove_clients_channels(SilcServer server,
33 SilcServerEntry server_entry,
34 SilcHashTable clients,
35 SilcClientEntry client,
36 SilcHashTable channels)
37 {
38 SilcChannelEntry channel;
39 SilcChannelClientEntry chl, chl2;
40 SilcHashTableList htl, htl2;
41
42 if (!client)
43 return;
44
45 SILC_LOG_DEBUG(("Remove client %s from all channels",
46 client->nickname ? client->nickname :
47 (unsigned char *)""));
48
49 if (silc_hash_table_find(clients, client, NULL, NULL))
50 silc_hash_table_del(clients, client);
51
52 /* Remove the client from all channels. The client is removed from
53 the channels' user list. */
54 silc_hash_table_list(client->channels, &htl);
55 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
56 channel = chl->channel;
57
58 /* Remove channel if this is last client leaving the channel, unless
59 the channel is permanent. */
60 if (server->server_type != SILC_SERVER &&
61 silc_hash_table_count(channel->user_list) < 2) {
62 if (silc_hash_table_find(channels, channel, NULL, NULL))
63 silc_hash_table_del(channels, channel);
64 silc_schedule_task_del_by_context(server->schedule, channel->rekey);
65 silc_server_channel_delete(server, channel);
66 continue;
67 }
68
69 silc_hash_table_del(client->channels, channel);
70 silc_hash_table_del(channel->user_list, chl->client);
71 channel->user_count--;
72
73 /* If there is no global users on the channel anymore mark the channel
74 as local channel. Do not check if the removed client is local client. */
75 if (server->server_type != SILC_ROUTER && channel->global_users &&
76 chl->client->router && !silc_server_channel_has_global(channel))
77 channel->global_users = FALSE;
78
79 silc_free(chl);
80
81 /* Update statistics */
82 if (SILC_IS_LOCAL(client))
83 server->stat.my_chanclients--;
84 if (server->server_type == SILC_ROUTER) {
85 server->stat.cell_chanclients--;
86 server->stat.chanclients--;
87 }
88
89 /* If there is not at least one local user on the channel then we don't
90 need the channel entry anymore, we can remove it safely, unless the
91 channel is permanent channel */
92 if (server->server_type == SILC_SERVER &&
93 !silc_server_channel_has_local(channel)) {
94 if (silc_hash_table_find(channels, channel, NULL, NULL))
95 silc_hash_table_del(channels, channel);
96 silc_schedule_task_del_by_context(server->schedule, channel->rekey);
97 silc_server_channel_delete(server, channel);
98 continue;
99 }
100
101 /* Mark other local clients to the table of clients whom will receive
102 the SERVER_SIGNOFF notify. */
103 silc_hash_table_list(channel->user_list, &htl2);
104 while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
105 SilcClientEntry c = chl2->client;
106 if (!c)
107 continue;
108
109 /* Add client to table, if it's not from the signoff server */
110 if (c->router != server_entry &&
111 !silc_hash_table_find(clients, c, NULL, NULL))
112 silc_hash_table_add(clients, c, c);
113 }
114 silc_hash_table_list_reset(&htl2);
115
116 /* Add the channel to the the channels list to regenerate the
117 channel key */
118 if (!silc_hash_table_find(channels, channel, NULL, NULL))
119 silc_hash_table_add(channels, channel, channel);
120 }
121 silc_hash_table_list_reset(&htl);
122 assert(!silc_hash_table_count(client->channels));
123 }
124
125 /* This function removes all client entries that are originated from
126 `router' and are owned by `entry'. `router' and `entry' can be same
127 too. If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
128 distributed to our local clients. */
129
130 bool silc_server_remove_clients_by_server(SilcServer server,
131 SilcServerEntry router,
132 SilcServerEntry entry,
133 bool server_signoff)
134 {
135 SilcIDCacheList list = NULL;
136 SilcIDCacheEntry id_cache = NULL;
137 SilcClientEntry client = NULL;
138 SilcBuffer idp;
139 unsigned char **argv = NULL;
140 SilcUInt32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
141 SilcHashTableList htl;
142 SilcChannelEntry channel;
143 SilcHashTable channels, clients;
144 int i;
145
146 if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
147 return FALSE;
148
149 SILC_LOG_DEBUG(("Removing clients by %s",
150 entry->server_name ? entry->server_name : "server"));
151
152 if (!router)
153 router = entry;
154
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,
159 NULL, NULL, TRUE);
160 clients = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
161 NULL, NULL, TRUE);
162
163 if (server_signoff) {
164 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
165 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
166 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
167 argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
168 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
169 memcpy(argv[argc], idp->data, idp->len);
170 argv_lens[argc] = idp->len;
171 argv_types[argc] = argc + 1;
172 argc++;
173 silc_buffer_free(idp);
174 }
175
176 if (silc_idcache_get_all(server->local_list->clients, &list)) {
177 if (silc_idcache_list_first(list, &id_cache)) {
178 while (id_cache) {
179 client = (SilcClientEntry)id_cache->context;
180
181 /* If client is not registered, is not originated from `router'
182 and is not owned by `entry', skip it. */
183 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
184 client->router != router ||
185 (router != entry && !SILC_ID_COMPARE(client->id, entry->id,
186 client->id->ip.data_len))) {
187 if (!silc_idcache_list_next(list, &id_cache))
188 break;
189 else
190 continue;
191 }
192
193 if (server_signoff) {
194 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
195 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
196 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
197 (argc + 1));
198 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
199 (argc + 1));
200 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
201 memcpy(argv[argc], idp->data, idp->len);
202 argv_lens[argc] = idp->len;
203 argv_types[argc] = argc + 1;
204 argc++;
205 silc_buffer_free(idp);
206 }
207
208 /* Update statistics */
209 server->stat.clients--;
210 if (server->stat.cell_clients)
211 server->stat.cell_clients--;
212 SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
213 SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
214
215 if (client->data.public_key)
216 silc_hash_table_del_by_context(server->pk_hash,
217 client->data.public_key,
218 client);
219 silc_server_remove_clients_channels(server, entry, clients,
220 client, channels);
221 silc_server_del_from_watcher_list(server, client);
222
223 /* Remove the client entry */
224 if (!server_signoff) {
225 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
226 client->mode = 0;
227 client->router = NULL;
228 client->connection = NULL;
229 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
230 } else {
231 silc_idlist_del_data(client);
232 silc_idlist_del_client(server->local_list, client);
233 }
234
235 if (!silc_idcache_list_next(list, &id_cache))
236 break;
237 }
238 }
239 silc_idcache_list_free(list);
240 }
241
242 if (silc_idcache_get_all(server->global_list->clients, &list)) {
243
244 if (silc_idcache_list_first(list, &id_cache)) {
245 while (id_cache) {
246 client = (SilcClientEntry)id_cache->context;
247
248 /* If client is not registered, is not originated from `router'
249 and is not owned by `entry', skip it. */
250 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
251 client->router != router ||
252 (router != entry && !SILC_ID_COMPARE(client->id, entry->id,
253 client->id->ip.data_len))) {
254 if (!silc_idcache_list_next(list, &id_cache))
255 break;
256 else
257 continue;
258 }
259
260 if (server_signoff) {
261 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
262 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
263 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
264 (argc + 1));
265 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
266 (argc + 1));
267 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
268 memcpy(argv[argc], idp->data, idp->len);
269 argv_lens[argc] = idp->len;
270 argv_types[argc] = argc + 1;
271 argc++;
272 silc_buffer_free(idp);
273 }
274
275 /* Update statistics */
276 server->stat.clients--;
277 if (server->stat.cell_clients)
278 server->stat.cell_clients--;
279 SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
280 SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
281
282 if (client->data.public_key)
283 silc_hash_table_del_by_context(server->pk_hash,
284 client->data.public_key,
285 client);
286 silc_server_remove_clients_channels(server, entry, clients,
287 client, channels);
288 silc_server_del_from_watcher_list(server, client);
289
290 /* Remove the client entry */
291 if (!server_signoff) {
292 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
293 client->mode = 0;
294 client->router = NULL;
295 client->connection = NULL;
296 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
297 } else {
298 silc_idlist_del_data(client);
299 silc_idlist_del_client(server->global_list, client);
300 }
301
302 if (!silc_idcache_list_next(list, &id_cache))
303 break;
304 }
305 }
306 silc_idcache_list_free(list);
307 }
308
309 /* Return now if we are shutting down */
310 if (server->server_shutdown) {
311 silc_hash_table_free(channels);
312
313 if (server_signoff) {
314 for (i = 0; i < argc; i++)
315 silc_free(argv[i]);
316 silc_free(argv);
317 silc_free(argv_lens);
318 silc_free(argv_types);
319 silc_hash_table_free(clients);
320 }
321 return TRUE;
322 }
323
324 /* Send the SERVER_SIGNOFF notify */
325 if (server_signoff) {
326 SilcBuffer args, not;
327
328 SILC_LOG_DEBUG(("Sending SERVER_SIGNOFF for %s with %d clients",
329 silc_id_render(entry->id, SILC_ID_SERVER), argc - 1));
330
331 /* Send SERVER_SIGNOFF notify to our primary router */
332 if (server->router != entry) {
333 args = silc_argument_payload_encode(1, argv, argv_lens,
334 argv_types);
335 silc_server_send_notify_args(server, SILC_PRIMARY_ROUTE(server),
336 SILC_BROADCAST(server),
337 SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
338 argc, args);
339 silc_buffer_free(args);
340 }
341
342 /* Send to local clients. We also send the list of client ID's that
343 is to be removed for those servers that would like to use that list. */
344 args = silc_argument_payload_encode(argc, argv, argv_lens,
345 argv_types);
346 not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
347 argc, args);
348 silc_server_packet_send_clients(server, clients,
349 SILC_PACKET_NOTIFY, 0, FALSE,
350 not->data, not->len, FALSE);
351
352 /* Send notify also to local backup routers */
353 silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0,
354 not->data, not->len, FALSE, TRUE);
355
356 silc_buffer_free(args);
357 silc_buffer_free(not);
358 for (i = 0; i < argc; i++)
359 silc_free(argv[i]);
360 silc_free(argv);
361 silc_free(argv_lens);
362 silc_free(argv_types);
363 silc_hash_table_free(clients);
364 }
365
366 /* We must now re-generate the channel key for all channels that had
367 this server's client(s) on the channel. As they left the channel we
368 must re-generate the channel key. */
369 silc_hash_table_list(channels, &htl);
370 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
371 if (!silc_server_create_channel_key(server, channel, 0)) {
372 silc_hash_table_list_reset(&htl);
373 silc_hash_table_free(channels);
374 return FALSE;
375 }
376
377 /* Do not send the channel key if private channel key mode is set */
378 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY || !channel->channel_key)
379 continue;
380
381 silc_server_send_channel_key(server, NULL, channel,
382 server->server_type == SILC_ROUTER ?
383 FALSE : !server->standalone);
384 }
385 silc_hash_table_list_reset(&htl);
386 silc_hash_table_free(channels);
387
388 return TRUE;
389 }
390
391 static SilcServerEntry
392 silc_server_update_clients_by_real_server(SilcServer server,
393 SilcServerEntry from,
394 SilcServerEntry to,
395 SilcClientEntry client,
396 bool local,
397 SilcIDCacheEntry client_cache)
398 {
399 SilcServerEntry server_entry;
400 SilcIDCacheEntry id_cache = NULL;
401 SilcIDCacheList list;
402 bool tolocal = (to == server->id_entry);
403
404 SILC_LOG_DEBUG(("Start"));
405
406 if (!silc_idcache_get_all(server->local_list->servers, &list))
407 return NULL;
408
409 if (silc_idcache_list_first(list, &id_cache)) {
410 while (id_cache) {
411 server_entry = (SilcServerEntry)id_cache->context;
412 if (server_entry != from &&
413 (tolocal || server_entry != server->id_entry) &&
414 SILC_ID_COMPARE(server_entry->id, client->id,
415 client->id->ip.data_len)) {
416 SILC_LOG_DEBUG(("Found (local) %s",
417 silc_id_render(server_entry->id, SILC_ID_SERVER)));
418
419 if (!server_entry->data.send_key && server_entry->router) {
420 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
421 /* If the client is not marked as local then move it to local list
422 since the server is local. */
423 if (!local) {
424 SILC_LOG_DEBUG(("Moving client to local list"));
425 silc_idcache_add(server->local_list->clients, client_cache->name,
426 client_cache->id, client_cache->context,
427 client_cache->expire, NULL);
428 silc_idcache_del_by_context(server->global_list->clients, client);
429 }
430 server_entry = server_entry->router;
431 } else {
432 SILC_LOG_DEBUG(("Server locally connected"));
433 /* If the client is not marked as local then move it to local list
434 since the server is local. */
435 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
436 SILC_LOG_DEBUG(("Moving client to local list"));
437 silc_idcache_add(server->local_list->clients, client_cache->name,
438 client_cache->id, client_cache->context,
439 client_cache->expire, NULL);
440 silc_idcache_del_by_context(server->global_list->clients, client);
441
442 } else if (server->server_type == SILC_BACKUP_ROUTER && local) {
443 /* If we are backup router and this client is on local list, we
444 must move it to global list, as it is not currently local to
445 us (we are not primary). */
446 SILC_LOG_DEBUG(("Moving client to global list"));
447 silc_idcache_add(server->global_list->clients, client_cache->name,
448 client_cache->id, client_cache->context,
449 client_cache->expire, NULL);
450 silc_idcache_del_by_context(server->local_list->clients, client);
451 }
452 }
453
454 silc_idcache_list_free(list);
455 return server_entry;
456 }
457
458 if (!silc_idcache_list_next(list, &id_cache))
459 break;
460 }
461 }
462
463 silc_idcache_list_free(list);
464
465 if (!silc_idcache_get_all(server->global_list->servers, &list))
466 return NULL;
467
468 if (silc_idcache_list_first(list, &id_cache)) {
469 while (id_cache) {
470 server_entry = (SilcServerEntry)id_cache->context;
471 if (server_entry != from && server_entry != server->id_entry &&
472 (tolocal || server_entry != server->id_entry) &&
473 SILC_ID_COMPARE(server_entry->id, client->id,
474 client->id->ip.data_len)) {
475 SILC_LOG_DEBUG(("Found (global) %s",
476 silc_id_render(server_entry->id, SILC_ID_SERVER)));
477
478 if (!server_entry->data.send_key && server_entry->router) {
479 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
480 /* If the client is marked as local then move it to global list
481 since the server is global. */
482 if (local) {
483 SILC_LOG_DEBUG(("Moving client to global list"));
484 silc_idcache_add(server->global_list->clients, client_cache->name,
485 client_cache->id, client_cache->context, 0, NULL);
486 silc_idcache_del_by_context(server->local_list->clients, client);
487 }
488 server_entry = server_entry->router;
489 } else {
490 SILC_LOG_DEBUG(("Server locally connected"));
491 /* If the client is marked as local then move it to global list
492 since the server is global. */
493 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
494 SILC_LOG_DEBUG(("Moving client to global list"));
495 silc_idcache_add(server->global_list->clients, client_cache->name,
496 client_cache->id, client_cache->context, 0, NULL);
497 silc_idcache_del_by_context(server->local_list->clients, client);
498 }
499 }
500
501 silc_idcache_list_free(list);
502 return server_entry;
503 }
504
505 if (!silc_idcache_list_next(list, &id_cache))
506 break;
507 }
508 }
509
510 silc_idcache_list_free(list);
511
512 return NULL;
513 }
514
515 /* Updates the clients that are originated from the `from' to be originated
516 from the `to'. If the `resolve_real_server' is TRUE then this will
517 attempt to figure out which clients really are originated from the
518 `from' and which are originated from a server that we have connection
519 to, when we've acting as backup router. If it is FALSE the `to' will
520 be the new source. */
521
522 void silc_server_update_clients_by_server(SilcServer server,
523 SilcServerEntry from,
524 SilcServerEntry to,
525 bool resolve_real_server)
526 {
527 SilcIDCacheList list = NULL;
528 SilcIDCacheEntry id_cache = NULL;
529 SilcClientEntry client = NULL;
530 bool local;
531
532 if (from && from->id) {
533 SILC_LOG_DEBUG(("Changing from server %s",
534 silc_id_render(from->id, SILC_ID_SERVER)));
535 }
536 if (to && to->id) {
537 SILC_LOG_DEBUG(("Changing to server %s",
538 silc_id_render(to->id, SILC_ID_SERVER)));
539 }
540
541 SILC_LOG_DEBUG(("global list"));
542 local = FALSE;
543 if (silc_idcache_get_all(server->global_list->clients, &list)) {
544 if (silc_idcache_list_first(list, &id_cache)) {
545 while (id_cache) {
546 client = (SilcClientEntry)id_cache->context;
547
548 /* If entry is disabled skip it. If entry is local to us, do not
549 switch it to anyone else, it is ours so skip it. */
550 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
551 SILC_IS_LOCAL(client)) {
552 if (!silc_idcache_list_next(list, &id_cache))
553 break;
554 else
555 continue;
556 }
557
558 SILC_LOG_DEBUG(("Client %s",
559 silc_id_render(client->id, SILC_ID_CLIENT)));
560 if (client->router && client->router->id)
561 SILC_LOG_DEBUG(("Client->router %s",
562 silc_id_render(client->router->id, SILC_ID_SERVER)));
563
564 if (from) {
565 if (client->router == from) {
566 if (resolve_real_server) {
567 client->router =
568 silc_server_update_clients_by_real_server(server, from, to,
569 client, local,
570 id_cache);
571 if (!client->router) {
572 if (server->server_type == SILC_ROUTER)
573 client->router = from;
574 else
575 client->router = to;
576 }
577 } else {
578 client->router = to;
579 }
580 }
581 } else {
582 /* All are changed */
583 if (resolve_real_server)
584 /* Call this so that the entry is moved to correct list if
585 needed. No resolving by real server is actually done. */
586 silc_server_update_clients_by_real_server(server, NULL, to,
587 client, local,
588 id_cache);
589
590 client->router = to;
591 }
592
593 if (client->router && client->router->id)
594 SILC_LOG_DEBUG(("Client changed to %s",
595 silc_id_render(client->router->id, SILC_ID_SERVER)));
596
597 if (!silc_idcache_list_next(list, &id_cache))
598 break;
599 }
600 }
601 silc_idcache_list_free(list);
602 }
603
604 SILC_LOG_DEBUG(("local list"));
605 local = TRUE;
606 if (silc_idcache_get_all(server->local_list->clients, &list)) {
607 if (silc_idcache_list_first(list, &id_cache)) {
608 while (id_cache) {
609 client = (SilcClientEntry)id_cache->context;
610
611 /* If entry is disabled skip it. If entry is local to us, do not
612 switch it to anyone else, it is ours so skip it. */
613 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
614 SILC_IS_LOCAL(client)) {
615 if (!silc_idcache_list_next(list, &id_cache))
616 break;
617 else
618 continue;
619 }
620
621 SILC_LOG_DEBUG(("Client %s",
622 silc_id_render(client->id, SILC_ID_CLIENT)));
623 if (client->router && client->router->id)
624 SILC_LOG_DEBUG(("Client->router %s",
625 silc_id_render(client->router->id, SILC_ID_SERVER)));
626
627 if (from) {
628 if (client->router == from) {
629 if (resolve_real_server) {
630 client->router =
631 silc_server_update_clients_by_real_server(server, from, to,
632 client, local,
633 id_cache);
634 if (!client->router)
635 client->router = from;
636 } else {
637 client->router = to;
638 }
639 }
640 } else {
641 /* All are changed */
642 if (resolve_real_server)
643 /* Call this so that the entry is moved to correct list if
644 needed. No resolving by real server is actually done. */
645 silc_server_update_clients_by_real_server(server, NULL, to,
646 client, local,
647 id_cache);
648
649 client->router = to;
650 }
651
652 if (client->router && client->router->id)
653 SILC_LOG_DEBUG(("Client changed to %s",
654 silc_id_render(client->router->id, SILC_ID_SERVER)));
655
656 if (!silc_idcache_list_next(list, &id_cache))
657 break;
658 }
659 }
660 silc_idcache_list_free(list);
661 }
662 }
663
664 /* Updates servers that are from `from' to be originated from `to'. This
665 will also update the server's connection to `to's connection. */
666
667 void silc_server_update_servers_by_server(SilcServer server,
668 SilcServerEntry from,
669 SilcServerEntry to)
670 {
671 SilcIDCacheList list = NULL;
672 SilcIDCacheEntry id_cache = NULL;
673 SilcServerEntry server_entry = NULL;
674
675 SILC_LOG_DEBUG(("Updating servers"));
676
677 if (silc_idcache_get_all(server->local_list->servers, &list)) {
678 if (silc_idcache_list_first(list, &id_cache)) {
679 while (id_cache) {
680 server_entry = (SilcServerEntry)id_cache->context;
681
682 /* If entry is local to us, do not switch it to any anyone else,
683 it is ours. */
684 if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
685 server_entry == from) {
686 if (!silc_idcache_list_next(list, &id_cache))
687 break;
688 else
689 continue;
690 }
691
692 /* If we are standalone router, any server that is not directly
693 connected to cannot exist anymore. If we are not standalone
694 we update it correctly. */
695 if (server->server_type == SILC_ROUTER && server->standalone) {
696 silc_server_backup_del(server, server_entry);
697 silc_server_backup_replaced_del(server, server_entry);
698 silc_idlist_del_data(server_entry);
699 silc_idlist_del_server(server->local_list, server_entry);
700 server->stat.servers--;
701 server->stat.cell_servers--;
702 } else {
703 /* XXX if we are not standalone, do a check from local config
704 whether this server is in our cell, but not connected to
705 us (in which case we must remove it). */
706
707 if (from) {
708 if (server_entry->router == from) {
709 SILC_LOG_DEBUG(("Updating server (local) %s",
710 server_entry->server_name ?
711 server_entry->server_name : ""));
712 server_entry->router = to;
713 server_entry->connection = to->connection;
714 }
715 } else {
716 /* Update all */
717 SILC_LOG_DEBUG(("Updating server (local) %s",
718 server_entry->server_name ?
719 server_entry->server_name : ""));
720 server_entry->router = to;
721 server_entry->connection = to->connection;
722 }
723 }
724
725 if (!silc_idcache_list_next(list, &id_cache))
726 break;
727 }
728 }
729 silc_idcache_list_free(list);
730 }
731
732 if (silc_idcache_get_all(server->global_list->servers, &list)) {
733 if (silc_idcache_list_first(list, &id_cache)) {
734 while (id_cache) {
735 server_entry = (SilcServerEntry)id_cache->context;
736
737 /* If entry is local to us, do not switch it to anyone else,
738 it is ours. */
739 if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
740 server_entry == from) {
741 if (!silc_idcache_list_next(list, &id_cache))
742 break;
743 else
744 continue;
745 }
746
747 /* If we are standalone router, any server that is not directly
748 connected to cannot exist anymore. If we are not standalone
749 we update it correctly. */
750 if (server->server_type == SILC_ROUTER && server->standalone) {
751 silc_server_backup_del(server, server_entry);
752 silc_server_backup_replaced_del(server, server_entry);
753 silc_idlist_del_data(server_entry);
754 silc_idlist_del_server(server->global_list, server_entry);
755 server->stat.servers--;
756 server->stat.cell_servers--;
757 } else {
758 /* XXX if we are not standalone, do a check from local config
759 whether this server is in our cell, but not connected to
760 us (in which case we must remove it). */
761
762 if (from) {
763 if (server_entry->router == from) {
764 SILC_LOG_DEBUG(("Updating server (global) %s",
765 server_entry->server_name ?
766 server_entry->server_name : ""));
767 server_entry->router = to;
768 server_entry->connection = to->connection;
769 }
770 } else {
771 /* Update all */
772 SILC_LOG_DEBUG(("Updating server (global) %s",
773 server_entry->server_name ?
774 server_entry->server_name : ""));
775 server_entry->router = to;
776 server_entry->connection = to->connection;
777 }
778 }
779
780 if (!silc_idcache_list_next(list, &id_cache))
781 break;
782 }
783 }
784 silc_idcache_list_free(list);
785 }
786 }
787
788
789 /* Toggles the enabled/disabled status of local server connections. Packets
790 can be sent to the servers when `toggle_enabled' is TRUE and will be
791 dropped if `toggle_enabled' is FALSE, after this function is called. */
792
793 void silc_server_local_servers_toggle_enabled(SilcServer server,
794 bool toggle_enabled)
795 {
796 SilcIDCacheList list = NULL;
797 SilcIDCacheEntry id_cache = NULL;
798 SilcServerEntry server_entry = NULL;
799
800 if (silc_idcache_get_all(server->local_list->servers, &list)) {
801 if (silc_idcache_list_first(list, &id_cache)) {
802 while (id_cache) {
803 server_entry = (SilcServerEntry)id_cache->context;
804 if (!SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry) {
805 if (!silc_idcache_list_next(list, &id_cache))
806 break;
807 else
808 continue;
809 }
810
811 if (toggle_enabled)
812 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
813 else
814 server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
815
816 if (!silc_idcache_list_next(list, &id_cache))
817 break;
818 }
819 }
820 silc_idcache_list_free(list);
821 }
822
823 if (silc_idcache_get_all(server->global_list->servers, &list)) {
824 if (silc_idcache_list_first(list, &id_cache)) {
825 while (id_cache) {
826 server_entry = (SilcServerEntry)id_cache->context;
827 if (!SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry) {
828 if (!silc_idcache_list_next(list, &id_cache))
829 break;
830 else
831 continue;
832 }
833
834 if (toggle_enabled)
835 server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
836 else
837 server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
838
839 if (!silc_idcache_list_next(list, &id_cache))
840 break;
841 }
842 }
843 silc_idcache_list_free(list);
844 }
845 }
846
847 /* Removes servers that are originated from the `from'. The server
848 entry is deleted in this function. If `remove_clients' is TRUE then
849 all clients originated from the server are removed too, and server
850 signoff is sent. Note that this does not remove the `from'. This
851 also does not remove locally connected servers. */
852
853 void silc_server_remove_servers_by_server(SilcServer server,
854 SilcServerEntry from,
855 bool remove_clients)
856 {
857 SilcIDCacheList list = NULL;
858 SilcIDCacheEntry id_cache = NULL;
859 SilcServerEntry server_entry = NULL;
860
861 SILC_LOG_DEBUG(("Removing servers by %s",
862 from->server_name ? from->server_name : "server"));
863
864 if (silc_idcache_get_all(server->local_list->servers, &list)) {
865 if (silc_idcache_list_first(list, &id_cache)) {
866 while (id_cache) {
867 server_entry = (SilcServerEntry)id_cache->context;
868 if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
869 server_entry->router != from || server_entry == from) {
870 if (!silc_idcache_list_next(list, &id_cache))
871 break;
872 else
873 continue;
874 }
875
876 /* Remove clients owned by this server */
877 if (remove_clients)
878 silc_server_remove_clients_by_server(server, from, server_entry,
879 TRUE);
880
881 /* Remove the server */
882 silc_server_backup_del(server, server_entry);
883 silc_idlist_del_server(server->local_list, server_entry);
884
885 if (!silc_idcache_list_next(list, &id_cache))
886 break;
887 }
888 }
889 silc_idcache_list_free(list);
890 }
891
892 if (silc_idcache_get_all(server->global_list->servers, &list)) {
893 if (silc_idcache_list_first(list, &id_cache)) {
894 while (id_cache) {
895 server_entry = (SilcServerEntry)id_cache->context;
896 if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
897 server_entry->router != from || server_entry == from) {
898 if (!silc_idcache_list_next(list, &id_cache))
899 break;
900 else
901 continue;
902 }
903
904 /* Remove clients owned by this server */
905 if (remove_clients)
906 silc_server_remove_clients_by_server(server, from, server_entry,
907 TRUE);
908
909 /* Remove the server */
910 silc_server_backup_del(server, server_entry);
911 silc_idlist_del_server(server->global_list, server_entry);
912
913 if (!silc_idcache_list_next(list, &id_cache))
914 break;
915 }
916 }
917 silc_idcache_list_free(list);
918 }
919 }
920
921 /* Removes channels that are from `from. */
922
923 void silc_server_remove_channels_by_server(SilcServer server,
924 SilcServerEntry from)
925 {
926 SilcIDCacheList list = NULL;
927 SilcIDCacheEntry id_cache = NULL;
928 SilcChannelEntry channel = NULL;
929
930 SILC_LOG_DEBUG(("Removing channels by server"));
931
932 if (silc_idcache_get_all(server->global_list->channels, &list)) {
933 if (silc_idcache_list_first(list, &id_cache)) {
934 while (id_cache) {
935 channel = (SilcChannelEntry)id_cache->context;
936 if (channel->router == from)
937 silc_idlist_del_channel(server->global_list, channel);
938 if (!silc_idcache_list_next(list, &id_cache))
939 break;
940 }
941 }
942 silc_idcache_list_free(list);
943 }
944 }
945
946 /* Updates channels that are from `from' to be originated from `to'. */
947
948 void silc_server_update_channels_by_server(SilcServer server,
949 SilcServerEntry from,
950 SilcServerEntry to)
951 {
952 SilcIDCacheList list = NULL;
953 SilcIDCacheEntry id_cache = NULL;
954 SilcChannelEntry channel = NULL;
955
956 SILC_LOG_DEBUG(("Updating channels by server"));
957
958 if (silc_idcache_get_all(server->global_list->channels, &list)) {
959 if (silc_idcache_list_first(list, &id_cache)) {
960 while (id_cache) {
961 channel = (SilcChannelEntry)id_cache->context;
962 if (from) {
963 if (channel->router == from)
964 channel->router = to;
965 } else {
966 /* Update all */
967 channel->router = to;
968 }
969 if (!silc_idcache_list_next(list, &id_cache))
970 break;
971 }
972 }
973 silc_idcache_list_free(list);
974 }
975 }
976
977 /* Checks whether given channel has global users. If it does this returns
978 TRUE and FALSE if there is only locally connected clients on the channel. */
979
980 bool silc_server_channel_has_global(SilcChannelEntry channel)
981 {
982 SilcChannelClientEntry chl;
983 SilcHashTableList htl;
984
985 silc_hash_table_list(channel->user_list, &htl);
986 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
987 if (chl->client->router) {
988 silc_hash_table_list_reset(&htl);
989 return TRUE;
990 }
991 }
992 silc_hash_table_list_reset(&htl);
993
994 return FALSE;
995 }
996
997 /* Checks whether given channel has locally connected users. If it does this
998 returns TRUE and FALSE if there is not one locally connected client. */
999
1000 bool silc_server_channel_has_local(SilcChannelEntry channel)
1001 {
1002 SilcChannelClientEntry chl;
1003 SilcHashTableList htl;
1004
1005 silc_hash_table_list(channel->user_list, &htl);
1006 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
1007 if (SILC_IS_LOCAL(chl->client)) {
1008 sil