updates.
[silc.git] / apps / silcd / server_util.c
1 /*
2
3   server_util.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 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$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
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. */
28
29 static void silc_server_remove_clients_channels(SilcServer server, 
30                                                 SilcSocketConnection sock,
31                                                 SilcClientEntry client,
32                                                 SilcHashTable channels)
33 {
34   SilcChannelEntry channel;
35   SilcChannelClientEntry chl;
36   SilcHashTableList htl;
37   SilcBuffer clidp;
38
39   SILC_LOG_DEBUG(("Start"));
40
41   if (!client || !client->id)
42     return;
43
44   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
45
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;
51
52     /* Remove channel from client's channel list */
53     silc_hash_table_del(client->channels, channel);
54
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) {
58
59       if (silc_hash_table_find(channels, channel, NULL, NULL))
60         silc_hash_table_del(channels, channel);
61
62       if (channel->rekey)
63         silc_schedule_task_del_by_context(server->schedule, channel->rekey);
64
65       if (silc_idlist_del_channel(server->local_list, channel))
66         server->stat.my_channels--;
67       else if (silc_idlist_del_channel(server->global_list, channel))
68         server->stat.my_channels--;
69       continue;
70     }
71
72     /* Remove client from channel's client list */
73     silc_hash_table_del(channel->user_list, chl->client);
74
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;
80
81     silc_free(chl);
82     server->stat.my_chanclients--;
83
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)) {
88
89       if (silc_hash_table_find(channels, channel, NULL, NULL))
90         silc_hash_table_del(channels, channel);
91
92       if (channel->rekey)
93         silc_schedule_task_del_by_context(server->schedule, channel->rekey);
94
95       if (channel->founder_key) {
96         /* The founder auth data exists, do not remove the channel entry */
97         SilcChannelClientEntry chl2;
98         SilcHashTableList htl2;
99
100         channel->id = NULL;
101
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);
106           silc_free(chl2);
107         }
108         continue;
109       }
110
111       /* Remove the channel entry */
112       if (silc_idlist_del_channel(server->local_list, channel))
113         server->stat.my_channels--;
114       else if (silc_idlist_del_channel(server->global_list, channel))
115         server->stat.my_channels--;
116       continue;
117     }
118
119     /* Add the channel to the the channels list to regenerate the 
120        channel key */
121     if (!silc_hash_table_find(channels, channel, NULL, NULL))
122       silc_hash_table_add(channels, channel, channel);
123   }
124
125   silc_buffer_free(clidp);
126 }
127
128 /* This function is used to remove all client entries by the server `entry'.
129    This is called when the connection is lost to the server. In this case
130    we must invalidate all the client entries owned by the server `entry'. 
131    If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
132    distributed to our local clients. */
133
134 bool silc_server_remove_clients_by_server(SilcServer server, 
135                                           SilcServerEntry entry,
136                                           bool server_signoff)
137 {
138   SilcIDCacheList list = NULL;
139   SilcIDCacheEntry id_cache = NULL;
140   SilcClientEntry client = NULL;
141   SilcBuffer idp;
142   SilcClientEntry *clients = NULL;
143   uint32 clients_c = 0;
144   unsigned char **argv = NULL;
145   uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
146   SilcHashTableList htl;
147   SilcChannelEntry channel;
148   SilcHashTable channels;
149   int i;
150
151   SILC_LOG_DEBUG(("Start"));
152
153   /* Allocate the hash table that holds the channels that require
154      channel key re-generation after we've removed this server's clients
155      from the channels. */
156   channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
157                                    NULL, NULL, TRUE);
158
159   if (server_signoff) {
160     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
161     argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
162     argv_lens = silc_realloc(argv_lens,  sizeof(*argv_lens) * (argc + 1));
163     argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
164     argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
165     memcpy(argv[argc], idp->data, idp->len);
166     argv_lens[argc] = idp->len;
167     argv_types[argc] = argc + 1;
168     argc++;
169     silc_buffer_free(idp);
170   }
171
172   if (silc_idcache_get_all(server->local_list->clients, &list)) {
173
174     if (silc_idcache_list_first(list, &id_cache)) {
175       while (id_cache) {
176         client = (SilcClientEntry)id_cache->context;
177         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
178           if (!silc_idcache_list_next(list, &id_cache))
179             break;
180           else
181             continue;
182         }
183
184         if (client->router != entry) {
185           if (server_signoff && client->connection) {
186             clients = silc_realloc(clients, 
187                                    sizeof(*clients) * (clients_c + 1));
188             clients[clients_c] = client;
189             clients_c++;
190           }
191
192           if (!silc_idcache_list_next(list, &id_cache))
193             break;
194           else
195             continue;
196         }
197
198         if (server_signoff) {
199           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
200           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
201           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
202                                    (argc + 1));
203           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
204                                     (argc + 1));
205           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
206           memcpy(argv[argc], idp->data, idp->len);
207           argv_lens[argc] = idp->len;
208           argv_types[argc] = argc + 1;
209           argc++;
210           silc_buffer_free(idp);
211         }
212
213         /* Remove the client entry */
214         silc_server_remove_clients_channels(server, NULL, client, channels);
215         silc_idlist_del_client(server->local_list, client);
216
217         if (!silc_idcache_list_next(list, &id_cache))
218           break;
219       }
220     }
221     silc_idcache_list_free(list);
222   }
223   
224   if (silc_idcache_get_all(server->global_list->clients, &list)) {
225
226     if (silc_idcache_list_first(list, &id_cache)) {
227       while (id_cache) {
228         client = (SilcClientEntry)id_cache->context;
229         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
230           if (!silc_idcache_list_next(list, &id_cache))
231             break;
232           else
233             continue;
234         }
235         
236         if (client->router != entry) {
237           if (server_signoff && client->connection) {
238             clients = silc_realloc(clients, 
239                                    sizeof(*clients) * (clients_c + 1));
240             clients[clients_c] = client;
241             clients_c++;
242           }
243
244           if (!silc_idcache_list_next(list, &id_cache))
245             break;
246           else
247             continue;
248         }
249
250         if (server_signoff) {
251           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
252           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
253           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
254                                    (argc + 1));
255           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
256                                     (argc + 1));
257           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
258           memcpy(argv[argc], idp->data, idp->len);
259           argv_lens[argc] = idp->len;
260           argv_types[argc] = argc + 1;
261           argc++;
262           silc_buffer_free(idp);
263         }
264
265         /* Remove the client entry */
266         silc_server_remove_clients_channels(server, NULL, client, channels);
267         silc_idlist_del_client(server->global_list, client);
268
269         if (!silc_idcache_list_next(list, &id_cache))
270           break;
271       }
272     }
273     silc_idcache_list_free(list);
274   }
275
276   /* Send the SERVER_SIGNOFF notify */
277   if (server_signoff) {
278     SilcBuffer args;
279
280     /* Send SERVER_SIGNOFF notify to our primary router */
281     if (!server->standalone && server->router &&
282         server->router != entry) {
283       args = silc_argument_payload_encode(1, argv, argv_lens,
284                                           argv_types);
285       silc_server_send_notify_args(server, 
286                                    server->router->connection,
287                                    server->server_type == SILC_SERVER ? 
288                                    FALSE : TRUE, 
289                                    SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
290                                    argc, args);
291       silc_buffer_free(args);
292     }
293
294     args = silc_argument_payload_encode(argc, argv, argv_lens,
295                                         argv_types);
296     /* Send to local clients */
297     for (i = 0; i < clients_c; i++) {
298       silc_server_send_notify_args(server, clients[i]->connection,
299                                    FALSE, SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
300                                    argc, args);
301     }
302
303     silc_free(clients);
304     silc_buffer_free(args);
305     for (i = 0; i < argc; i++)
306       silc_free(argv[i]);
307     silc_free(argv);
308     silc_free(argv_lens);
309     silc_free(argv_types);
310   }
311
312   /* We must now re-generate the channel key for all channels that had
313      this server's client(s) on the channel. As they left the channel we
314      must re-generate the channel key. */
315   silc_hash_table_list(channels, &htl);
316   while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
317     if (!silc_server_create_channel_key(server, channel, 0))
318       return FALSE;
319
320     /* Do not send the channel key if private channel key mode is set */
321     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
322       continue;
323
324     silc_server_send_channel_key(server, NULL, channel, 
325                                  server->server_type == SILC_ROUTER ? 
326                                  FALSE : !server->standalone);
327   }
328   silc_hash_table_free(channels);
329
330   return TRUE;
331 }
332
333 static SilcServerEntry
334 silc_server_update_clients_by_real_server(SilcServer server,
335                                           SilcServerEntry from,
336                                           SilcClientEntry client,
337                                           bool local,
338                                           SilcIDCacheEntry client_cache)
339 {
340   SilcServerEntry server_entry;
341   SilcIDCacheEntry id_cache = NULL;
342   SilcIDCacheList list;
343
344   if (!silc_idcache_get_all(server->local_list->servers, &list))
345     return NULL;
346
347   if (silc_idcache_list_first(list, &id_cache)) {
348     while (id_cache) {
349       server_entry = (SilcServerEntry)id_cache->context;
350       if (server_entry != from &&
351           SILC_ID_COMPARE(server_entry->id, client->id, 
352                           client->id->ip.data_len)) {
353         SILC_LOG_DEBUG(("Found (local) %s",
354                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
355
356         if (!server_entry->data.send_key && server_entry->router) {
357           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
358           /* If the client is not marked as local then move it to local list
359              since the server is local. */
360           if (!local) {
361             SILC_LOG_DEBUG(("Moving client to local list"));
362             silc_idcache_add(server->local_list->clients, client_cache->name,
363                              client_cache->id, client_cache->context,
364                              client_cache->expire);
365             silc_idcache_del_by_context(server->global_list->clients, client);
366           }
367           server_entry = server_entry->router;
368         } else {
369           /* If the client is not marked as local then move it to local list
370              since the server is local. */
371           if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
372             SILC_LOG_DEBUG(("Moving client to local list"));
373             silc_idcache_add(server->local_list->clients, client_cache->name,
374                              client_cache->id, client_cache->context,
375                              client_cache->expire);
376             silc_idcache_del_by_context(server->global_list->clients, client);
377           }
378         }
379
380         silc_idcache_list_free(list);
381         return server_entry;
382       }
383
384       if (!silc_idcache_list_next(list, &id_cache))
385         break;
386     }
387   }
388
389   silc_idcache_list_free(list);
390
391   if (!silc_idcache_get_all(server->global_list->servers, &list))
392     return NULL;
393
394   if (silc_idcache_list_first(list, &id_cache)) {
395     while (id_cache) {
396       server_entry = (SilcServerEntry)id_cache->context;
397       if (server_entry != from &&
398           SILC_ID_COMPARE(server_entry->id, client->id, 
399                           client->id->ip.data_len)) {
400         SILC_LOG_DEBUG(("Found (global) %s",
401                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
402
403         if (!server_entry->data.send_key && server_entry->router) {
404           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
405           /* If the client is marked as local then move it to global list
406              since the server is global. */
407           if (local) {
408             SILC_LOG_DEBUG(("Moving client to global list"));
409             silc_idcache_add(server->global_list->clients, client_cache->name,
410                              client_cache->id, client_cache->context,
411                              client_cache->expire);
412             silc_idcache_del_by_context(server->local_list->clients, client);
413           }
414           server_entry = server_entry->router;
415         } else {
416           /* If the client is marked as local then move it to global list
417              since the server is global. */
418           if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
419             SILC_LOG_DEBUG(("Moving client to global list"));
420             silc_idcache_add(server->global_list->clients, client_cache->name,
421                              client_cache->id, client_cache->context,
422                              client_cache->expire);
423             silc_idcache_del_by_context(server->local_list->clients, client);
424           }
425         }
426
427         silc_idcache_list_free(list);
428         return server_entry;
429       }
430
431       if (!silc_idcache_list_next(list, &id_cache))
432         break;
433     }
434   }
435
436   silc_idcache_list_free(list);
437
438   return NULL;
439 }
440
441 /* Updates the clients that are originated from the `from' to be originated
442    from the `to'. If the `resolve_real_server' is TRUE then this will
443    attempt to figure out which clients really are originated from the
444    `from' and which are originated from a server that we have connection
445    to, when we've acting as backup router. If it is FALSE the `to' will
446    be the new source. This function also removes the clients that are
447    *really* originated from `from' if `remove_from' is TRUE. These are
448    clients that the `from' owns, and not just clients that are behind
449    the `from'. */
450
451 void silc_server_update_clients_by_server(SilcServer server, 
452                                           SilcServerEntry from,
453                                           SilcServerEntry to,
454                                           bool resolve_real_server,
455                                           bool remove_from)
456 {
457   SilcIDCacheList list = NULL;
458   SilcIDCacheEntry id_cache = NULL;
459   SilcClientEntry client = NULL;
460   bool local;
461
462   SILC_LOG_DEBUG(("Start"));
463
464   SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
465                                                 SILC_ID_SERVER)));
466   SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
467                                           SILC_ID_SERVER)));
468
469
470   local = FALSE;
471   if (silc_idcache_get_all(server->global_list->clients, &list)) {
472     if (silc_idcache_list_first(list, &id_cache)) {
473       while (id_cache) {
474         client = (SilcClientEntry)id_cache->context;
475         
476
477         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
478           if (!silc_idcache_list_next(list, &id_cache))
479             break;
480           else
481             continue;
482         }
483
484         SILC_LOG_DEBUG(("Client (global) %s", 
485                         silc_id_render(client->id, SILC_ID_CLIENT)));
486         if (client->router)
487           SILC_LOG_DEBUG(("Client->router (global) %s", 
488                           silc_id_render(client->router->id, SILC_ID_SERVER)));
489
490         if (client->router == from) {
491           /* Skip clients that are *really* owned by the `from' */
492           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
493                                              client->id->ip.data_len)) {
494             SILC_LOG_DEBUG(("Found really owned client, skip it"));
495             if (!silc_idcache_list_next(list, &id_cache))
496               break;
497             else
498               continue;
499           }
500
501           if (resolve_real_server) {
502             client->router = 
503               silc_server_update_clients_by_real_server(server, from, client,
504                                                         local, id_cache);
505             if (!client->router)
506               client->router = to;
507           } else {
508             client->router = to;
509           }
510         }
511
512         if (!silc_idcache_list_next(list, &id_cache))
513           break;
514       }
515     }
516     silc_idcache_list_free(list);
517   }
518
519   local = TRUE;
520   if (silc_idcache_get_all(server->local_list->clients, &list)) {
521     if (silc_idcache_list_first(list, &id_cache)) {
522       while (id_cache) {
523         client = (SilcClientEntry)id_cache->context;
524
525         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
526           if (!silc_idcache_list_next(list, &id_cache))
527             break;
528           else
529             continue;
530         }
531
532         SILC_LOG_DEBUG(("Client (local) %s", 
533                         silc_id_render(client->id, SILC_ID_CLIENT)));
534         if (client->router)
535           SILC_LOG_DEBUG(("Client->router (local) %s", 
536                           silc_id_render(client->router->id, SILC_ID_SERVER)));
537
538         if (client->router == from) {
539           /* Skip clients that are *really* owned by the `from' */
540           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
541                                              client->id->ip.data_len)) {
542             SILC_LOG_DEBUG(("Found really owned client, skip it"));
543             if (!silc_idcache_list_next(list, &id_cache))
544               break;
545             else
546               continue;
547           }
548
549           if (resolve_real_server) {
550             client->router = 
551               silc_server_update_clients_by_real_server(server, from, client,
552                                                         local, id_cache);
553             if (!client->router)
554               client->router = from; /* on local list put old from */
555           } else {
556             client->router = to;
557           }
558         }
559
560         if (!silc_idcache_list_next(list, &id_cache))
561           break;
562       }
563     }
564     silc_idcache_list_free(list);
565   }
566
567   if (remove_from)
568     /* Now remove the clients that are still marked as orignated from the
569        `from'. These are the clients that really was owned by the `from' and
570        not just exist behind the `from'. */
571     silc_server_remove_clients_by_server(server, from, TRUE);
572 }
573
574 /* Updates servers that are from `from' to be originated from `to'.  This
575    will also update the server's connection to `to's connection. */
576
577 void silc_server_update_servers_by_server(SilcServer server, 
578                                           SilcServerEntry from,
579                                           SilcServerEntry to)
580 {
581   SilcIDCacheList list = NULL;
582   SilcIDCacheEntry id_cache = NULL;
583   SilcServerEntry server_entry = NULL;
584
585   SILC_LOG_DEBUG(("Start"));
586
587   if (silc_idcache_get_all(server->local_list->servers, &list)) {
588     if (silc_idcache_list_first(list, &id_cache)) {
589       while (id_cache) {
590         server_entry = (SilcServerEntry)id_cache->context;
591         if (server_entry->router == from) {
592           server_entry->router = to;
593           server_entry->connection = to->connection;
594         }
595         if (!silc_idcache_list_next(list, &id_cache))
596           break;
597       }
598     }
599     silc_idcache_list_free(list);
600   }
601
602   if (silc_idcache_get_all(server->global_list->servers, &list)) {
603     if (silc_idcache_list_first(list, &id_cache)) {
604       while (id_cache) {
605         server_entry = (SilcServerEntry)id_cache->context;
606         if (server_entry->router == from) {
607           server_entry->router = to;
608           server_entry->connection = to->connection;
609         }
610         if (!silc_idcache_list_next(list, &id_cache))
611           break;
612       }
613     }
614     silc_idcache_list_free(list);
615   }
616 }
617
618 /* Checks whether given channel has global users.  If it does this returns
619    TRUE and FALSE if there is only locally connected clients on the channel. */
620
621 bool silc_server_channel_has_global(SilcChannelEntry channel)
622 {
623   SilcChannelClientEntry chl;
624   SilcHashTableList htl;
625
626   silc_hash_table_list(channel->user_list, &htl);
627   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
628     if (chl->client->router)
629       return TRUE;
630   }
631
632   return FALSE;
633 }
634
635 /* Checks whether given channel has locally connected users.  If it does this
636    returns TRUE and FALSE if there is not one locally connected client. */
637
638 bool silc_server_channel_has_local(SilcChannelEntry channel)
639 {
640   SilcChannelClientEntry chl;
641   SilcHashTableList htl;
642
643   silc_hash_table_list(channel->user_list, &htl);
644   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
645     if (!chl->client->router)
646       return TRUE;
647   }
648
649   return FALSE;
650 }
651
652 /* Returns TRUE if the given client is on the channel.  FALSE if not. 
653    This works because we assure that the user list on the channel is
654    always in up to date thus we can only check the channel list from 
655    `client' which is faster than checking the user list from `channel'. */
656
657 bool silc_server_client_on_channel(SilcClientEntry client,
658                                    SilcChannelEntry channel)
659 {
660   if (!client || !channel)
661     return FALSE;
662
663   if (silc_hash_table_find(client->channels, channel, NULL, NULL))
664     return TRUE;
665
666   return FALSE;
667 }