]> jfr.im git - solanum.git/blame_incremental - ircd/hash.c
chmode: Get elevated access for op-only queries
[solanum.git] / ircd / hash.c
... / ...
CommitLineData
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * hash.c: Maintains hashtables.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
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; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 */
24
25#include "stdinc.h"
26#include "ircd_defs.h"
27#include "s_conf.h"
28#include "channel.h"
29#include "client.h"
30#include "hash.h"
31#include "match.h"
32#include "ircd.h"
33#include "numeric.h"
34#include "send.h"
35#include "msg.h"
36#include "cache.h"
37#include "s_newconf.h"
38#include "s_assert.h"
39#include "rb_dictionary.h"
40#include "rb_radixtree.h"
41
42rb_dictionary *client_connid_tree = NULL;
43rb_radixtree *client_id_tree = NULL;
44rb_radixtree *client_name_tree = NULL;
45
46rb_radixtree *channel_tree = NULL;
47rb_radixtree *resv_tree = NULL;
48rb_radixtree *hostname_tree = NULL;
49
50/*
51 * look in whowas.c for the missing ...[WW_MAX]; entry
52 */
53
54/* init_hash()
55 *
56 * clears the various hashtables
57 */
58void
59init_hash(void)
60{
61 client_connid_tree = rb_dictionary_create("client connid", rb_uint32cmp);
62 client_id_tree = rb_radixtree_create("client id", NULL);
63 client_name_tree = rb_radixtree_create("client name", irccasecanon);
64
65 channel_tree = rb_radixtree_create("channel", irccasecanon);
66 resv_tree = rb_radixtree_create("resv", irccasecanon);
67
68 hostname_tree = rb_radixtree_create("hostname", irccasecanon);
69}
70
71uint32_t
72fnv_hash_upper(const unsigned char *s, int bits)
73{
74 uint32_t h = FNV1_32_INIT;
75
76 while (*s)
77 {
78 h ^= irctoupper(*s++);
79 h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
80 }
81 if (bits < 32)
82 h = ((h >> bits) ^ h) & ((1<<bits)-1);
83 return h;
84}
85
86uint32_t
87fnv_hash(const unsigned char *s, int bits)
88{
89 uint32_t h = FNV1_32_INIT;
90
91 while (*s)
92 {
93 h ^= *s++;
94 h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
95 }
96 if (bits < 32)
97 h = ((h >> bits) ^ h) & ((1<<bits)-1);
98 return h;
99}
100
101uint32_t
102fnv_hash_len(const unsigned char *s, int bits, int len)
103{
104 uint32_t h = FNV1_32_INIT;
105 const unsigned char *x = s + len;
106 while (*s && s < x)
107 {
108 h ^= *s++;
109 h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
110 }
111 if (bits < 32)
112 h = ((h >> bits) ^ h) & ((1<<bits)-1);
113 return h;
114}
115
116uint32_t
117fnv_hash_upper_len(const unsigned char *s, int bits, int len)
118{
119 uint32_t h = FNV1_32_INIT;
120 const unsigned char *x = s + len;
121 while (*s && s < x)
122 {
123 h ^= irctoupper(*s++);
124 h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
125 }
126 if (bits < 32)
127 h = ((h >> bits) ^ h) & ((1<<bits)-1);
128 return h;
129}
130
131/* add_to_id_hash()
132 *
133 * adds an entry to the id hash table
134 */
135void
136add_to_id_hash(const char *name, struct Client *client_p)
137{
138 if(EmptyString(name) || (client_p == NULL))
139 return;
140
141 rb_radixtree_add(client_id_tree, name, client_p);
142}
143
144/* add_to_client_hash()
145 *
146 * adds an entry (client/server) to the client hash table
147 */
148void
149add_to_client_hash(const char *name, struct Client *client_p)
150{
151 s_assert(name != NULL);
152 s_assert(client_p != NULL);
153 if(EmptyString(name) || (client_p == NULL))
154 return;
155
156 rb_radixtree_add(client_name_tree, name, client_p);
157}
158
159/* add_to_hostname_hash()
160 *
161 * adds a client entry to the hostname hash table
162 */
163void
164add_to_hostname_hash(const char *hostname, struct Client *client_p)
165{
166 rb_dlink_list *list;
167
168 s_assert(hostname != NULL);
169 s_assert(client_p != NULL);
170 if(EmptyString(hostname) || (client_p == NULL))
171 return;
172
173 list = rb_radixtree_retrieve(hostname_tree, hostname);
174 if (list != NULL)
175 {
176 rb_dlinkAddAlloc(client_p, list);
177 return;
178 }
179
180 list = rb_malloc(sizeof(*list));
181 rb_radixtree_add(hostname_tree, hostname, list);
182 rb_dlinkAddAlloc(client_p, list);
183}
184
185/* add_to_resv_hash()
186 *
187 * adds a resv channel entry to the resv hash table
188 */
189void
190add_to_resv_hash(const char *name, struct ConfItem *aconf)
191{
192 s_assert(!EmptyString(name));
193 s_assert(aconf != NULL);
194 if(EmptyString(name) || aconf == NULL)
195 return;
196
197 rb_radixtree_add(resv_tree, name, aconf);
198}
199
200/* del_from_id_hash()
201 *
202 * removes an id from the id hash table
203 */
204void
205del_from_id_hash(const char *id, struct Client *client_p)
206{
207 s_assert(id != NULL);
208 s_assert(client_p != NULL);
209 if(EmptyString(id) || client_p == NULL)
210 return;
211
212 rb_radixtree_delete(client_id_tree, id);
213}
214
215/* del_from_client_hash()
216 *
217 * removes a client/server from the client hash table
218 */
219void
220del_from_client_hash(const char *name, struct Client *client_p)
221{
222 /* no s_asserts, this can happen when removing a client that
223 * is unregistered.
224 */
225 if(EmptyString(name) || client_p == NULL)
226 return;
227
228 rb_radixtree_delete(client_name_tree, name);
229}
230
231/* del_from_channel_hash()
232 *
233 * removes a channel from the channel hash table
234 */
235void
236del_from_channel_hash(const char *name, struct Channel *chptr)
237{
238 s_assert(name != NULL);
239 s_assert(chptr != NULL);
240
241 if(EmptyString(name) || chptr == NULL)
242 return;
243
244 rb_radixtree_delete(channel_tree, name);
245}
246
247/* del_from_hostname_hash()
248 *
249 * removes a client entry from the hostname hash table
250 */
251void
252del_from_hostname_hash(const char *hostname, struct Client *client_p)
253{
254 rb_dlink_list *list;
255
256 if(hostname == NULL || client_p == NULL)
257 return;
258
259 list = rb_radixtree_retrieve(hostname_tree, hostname);
260 if (list == NULL)
261 return;
262
263 rb_dlinkFindDestroy(client_p, list);
264
265 if (rb_dlink_list_length(list) == 0)
266 {
267 rb_radixtree_delete(hostname_tree, hostname);
268 rb_free(list);
269 }
270}
271
272/* del_from_resv_hash()
273 *
274 * removes a resv entry from the resv hash table
275 */
276void
277del_from_resv_hash(const char *name, struct ConfItem *aconf)
278{
279 s_assert(name != NULL);
280 s_assert(aconf != NULL);
281 if(EmptyString(name) || aconf == NULL)
282 return;
283
284 rb_radixtree_delete(resv_tree, name);
285}
286
287/* find_id()
288 *
289 * finds a client entry from the id hash table
290 */
291struct Client *
292find_id(const char *name)
293{
294 if(EmptyString(name))
295 return NULL;
296
297 return rb_radixtree_retrieve(client_id_tree, name);
298}
299
300/* find_client()
301 *
302 * finds a client/server entry from the client hash table
303 */
304struct Client *
305find_client(const char *name)
306{
307 s_assert(name != NULL);
308 if(EmptyString(name))
309 return NULL;
310
311 /* hunting for an id, not a nick */
312 if(IsDigit(*name))
313 return (find_id(name));
314
315 return rb_radixtree_retrieve(client_name_tree, name);
316}
317
318/* find_named_client()
319 *
320 * finds a client/server entry from the client hash table
321 */
322struct Client *
323find_named_client(const char *name)
324{
325 s_assert(name != NULL);
326 if(EmptyString(name))
327 return NULL;
328
329 return rb_radixtree_retrieve(client_name_tree, name);
330}
331
332/* find_server()
333 *
334 * finds a server from the client hash table
335 */
336struct Client *
337find_server(struct Client *source_p, const char *name)
338{
339 struct Client *target_p;
340
341 if(EmptyString(name))
342 return NULL;
343
344 if((source_p == NULL || !MyClient(source_p)) &&
345 IsDigit(*name) && strlen(name) == 3)
346 {
347 target_p = find_id(name);
348 return(target_p);
349 }
350
351 target_p = rb_radixtree_retrieve(client_name_tree, name);
352 if (target_p != NULL)
353 {
354 if(IsServer(target_p) || IsMe(target_p))
355 return target_p;
356 }
357
358 return NULL;
359}
360
361/* find_hostname()
362 *
363 * finds a hostname rb_dlink list from the hostname hash table.
364 * we return the full rb_dlink list, because you can have multiple
365 * entries with the same hostname
366 */
367rb_dlink_node *
368find_hostname(const char *hostname)
369{
370 rb_dlink_list *hlist;
371
372 if(EmptyString(hostname))
373 return NULL;
374
375 hlist = rb_radixtree_retrieve(hostname_tree, hostname);
376 if (hlist == NULL)
377 return NULL;
378
379 return hlist->head;
380}
381
382/* find_channel()
383 *
384 * finds a channel from the channel hash table
385 */
386struct Channel *
387find_channel(const char *name)
388{
389 s_assert(name != NULL);
390 if(EmptyString(name))
391 return NULL;
392
393 return rb_radixtree_retrieve(channel_tree, name);
394}
395
396/*
397 * get_or_create_channel
398 * inputs - client pointer
399 * - channel name
400 * - pointer to int flag whether channel was newly created or not
401 * output - returns channel block or NULL if illegal name
402 * - also modifies *isnew
403 *
404 * Get Channel block for chname (and allocate a new channel
405 * block, if it didn't exist before).
406 */
407struct Channel *
408get_or_create_channel(struct Client *client_p, const char *chname, bool *isnew)
409{
410 struct Channel *chptr;
411 int len;
412 const char *s = chname;
413
414 if(EmptyString(s))
415 return NULL;
416
417 len = strlen(s);
418 if(len > CHANNELLEN)
419 {
420 char *t;
421 if(IsServer(client_p))
422 {
423 sendto_realops_snomask(SNO_DEBUG, L_ALL,
424 "*** Long channel name from %s (%d > %d): %s",
425 client_p->name, len, CHANNELLEN, s);
426 }
427 len = CHANNELLEN;
428 t = LOCAL_COPY(s);
429 t[len] = '\0';
430 s = t;
431 }
432
433 chptr = rb_radixtree_retrieve(channel_tree, s);
434 if (chptr != NULL)
435 {
436 if (isnew != NULL)
437 *isnew = false;
438 return chptr;
439 }
440
441 if(isnew != NULL)
442 *isnew = true;
443
444 chptr = allocate_channel(s);
445 chptr->channelts = rb_current_time(); /* doesn't hurt to set it here */
446
447 rb_dlinkAdd(chptr, &chptr->node, &global_channel_list);
448 rb_radixtree_add(channel_tree, chptr->chname, chptr);
449
450 return chptr;
451}
452
453/* hash_find_resv()
454 *
455 * hunts for a resv entry in the resv hash table
456 */
457struct ConfItem *
458hash_find_resv(const char *name)
459{
460 struct ConfItem *aconf;
461
462 s_assert(name != NULL);
463 if(EmptyString(name))
464 return NULL;
465
466 aconf = rb_radixtree_retrieve(resv_tree, name);
467 if (aconf != NULL)
468 {
469 aconf->port++;
470 return aconf;
471 }
472
473 return NULL;
474}
475
476void
477clear_resv_hash(void)
478{
479 struct ConfItem *aconf;
480 rb_radixtree_iteration_state iter;
481
482 RB_RADIXTREE_FOREACH(aconf, &iter, resv_tree)
483 {
484 /* skip temp resvs */
485 if(aconf->hold)
486 continue;
487
488 rb_radixtree_delete(resv_tree, aconf->host);
489 free_conf(aconf);
490 }
491}
492
493void
494add_to_cli_connid_hash(struct Client *client_p, uint32_t id)
495{
496 rb_dictionary_add(client_connid_tree, RB_UINT_TO_POINTER(id), client_p);
497}
498
499void
500del_from_cli_connid_hash(uint32_t id)
501{
502 rb_dictionary_delete(client_connid_tree, RB_UINT_TO_POINTER(id));
503}
504
505struct Client *
506find_cli_connid_hash(uint32_t connid)
507{
508 return rb_dictionary_retrieve(client_connid_tree, RB_UINT_TO_POINTER(connid));
509}