The SILC Project

source navigation ]
identifier search ]
freetext search ]
file search ]

silc/silcd/server_util.c

  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