]> jfr.im git - irc/freenode/solanum.git/blame - ircd/hash.c
make more snotes L_NETWIDE
[irc/freenode/solanum.git] / ircd / hash.c
CommitLineData
ae78a571
VY
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
ae78a571
VY
23 */
24
25#include "stdinc.h"
26#include "ircd_defs.h"
27#include "s_conf.h"
28#include "channel.h"
29#include "client.h"
ae78a571 30#include "hash.h"
4562c604 31#include "match.h"
ae78a571
VY
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"
77d3d2db 38#include "s_assert.h"
a4bf26dd
EM
39#include "rb_dictionary.h"
40#include "rb_radixtree.h"
c6d72037 41
4177311e 42rb_dictionary *client_connid_tree = NULL;
2fc6772e
EM
43rb_radixtree *client_id_tree = NULL;
44rb_radixtree *client_name_tree = NULL;
5c7c7d65 45
2fc6772e
EM
46rb_radixtree *channel_tree = NULL;
47rb_radixtree *resv_tree = NULL;
48rb_radixtree *hostname_tree = NULL;
46be39fa 49
ae78a571
VY
50/*
51 * look in whowas.c for the missing ...[WW_MAX]; entry
52 */
53
ae78a571
VY
54/* init_hash()
55 *
56 * clears the various hashtables
57 */
58void
59init_hash(void)
60{
a4bf26dd 61 client_connid_tree = rb_dictionary_create("client connid", rb_uint32cmp);
a4bf26dd
EM
62 client_id_tree = rb_radixtree_create("client id", NULL);
63 client_name_tree = rb_radixtree_create("client name", irccasecanon);
46be39fa 64
a4bf26dd
EM
65 channel_tree = rb_radixtree_create("channel", irccasecanon);
66 resv_tree = rb_radixtree_create("resv", irccasecanon);
d38c08c1 67
a4bf26dd 68 hostname_tree = rb_radixtree_create("hostname", irccasecanon);
ae78a571
VY
69}
70
2e45f5d8 71uint32_t
ae78a571
VY
72fnv_hash_upper(const unsigned char *s, int bits)
73{
2e45f5d8 74 uint32_t h = FNV1_32_INIT;
ae78a571
VY
75
76 while (*s)
77 {
7e6b5384 78 h ^= irctoupper(*s++);
ae78a571
VY
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
2e45f5d8 86uint32_t
ae78a571
VY
87fnv_hash(const unsigned char *s, int bits)
88{
2e45f5d8 89 uint32_t h = FNV1_32_INIT;
ae78a571
VY
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
2e45f5d8 101uint32_t
ae78a571
VY
102fnv_hash_len(const unsigned char *s, int bits, int len)
103{
2e45f5d8 104 uint32_t h = FNV1_32_INIT;
ae78a571
VY
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
2e45f5d8 116uint32_t
ae78a571
VY
117fnv_hash_upper_len(const unsigned char *s, int bits, int len)
118{
2e45f5d8 119 uint32_t h = FNV1_32_INIT;
ae78a571
VY
120 const unsigned char *x = s + len;
121 while (*s && s < x)
122 {
7e6b5384 123 h ^= irctoupper(*s++);
ae78a571
VY
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}
ae78a571 130
ae78a571
VY
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{
ae78a571
VY
138 if(EmptyString(name) || (client_p == NULL))
139 return;
140
a4bf26dd 141 rb_radixtree_add(client_id_tree, name, client_p);
ae78a571
VY
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{
ae78a571
VY
151 s_assert(name != NULL);
152 s_assert(client_p != NULL);
153 if(EmptyString(name) || (client_p == NULL))
154 return;
155
a4bf26dd 156 rb_radixtree_add(client_name_tree, name, client_p);
ae78a571
VY
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{
d38c08c1 166 rb_dlink_list *list;
ae78a571
VY
167
168 s_assert(hostname != NULL);
169 s_assert(client_p != NULL);
170 if(EmptyString(hostname) || (client_p == NULL))
171 return;
172
a4bf26dd 173 list = rb_radixtree_retrieve(hostname_tree, hostname);
d38c08c1
WP
174 if (list != NULL)
175 {
176 rb_dlinkAddAlloc(client_p, list);
177 return;
178 }
179
180 list = rb_malloc(sizeof(*list));
a4bf26dd 181 rb_radixtree_add(hostname_tree, hostname, list);
d38c08c1 182 rb_dlinkAddAlloc(client_p, list);
ae78a571
VY
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{
ae78a571
VY
192 s_assert(!EmptyString(name));
193 s_assert(aconf != NULL);
194 if(EmptyString(name) || aconf == NULL)
195 return;
196
a4bf26dd 197 rb_radixtree_add(resv_tree, name, aconf);
ae78a571
VY
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{
ae78a571
VY
207 s_assert(id != NULL);
208 s_assert(client_p != NULL);
209 if(EmptyString(id) || client_p == NULL)
210 return;
211
a4bf26dd 212 rb_radixtree_delete(client_id_tree, id);
ae78a571
VY
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{
ae78a571
VY
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
a4bf26dd 228 rb_radixtree_delete(client_name_tree, name);
ae78a571
VY
229}
230
231/* del_from_channel_hash()
55abcbb2 232 *
ae78a571
VY
233 * removes a channel from the channel hash table
234 */
235void
236del_from_channel_hash(const char *name, struct Channel *chptr)
237{
ae78a571
VY
238 s_assert(name != NULL);
239 s_assert(chptr != NULL);
240
241 if(EmptyString(name) || chptr == NULL)
242 return;
243
a4bf26dd 244 rb_radixtree_delete(channel_tree, name);
ae78a571
VY
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{
d38c08c1 254 rb_dlink_list *list;
ae78a571
VY
255
256 if(hostname == NULL || client_p == NULL)
257 return;
258
a4bf26dd 259 list = rb_radixtree_retrieve(hostname_tree, hostname);
d38c08c1
WP
260 if (list == NULL)
261 return;
262
263 rb_dlinkFindDestroy(client_p, list);
ae78a571 264
d38c08c1
WP
265 if (rb_dlink_list_length(list) == 0)
266 {
a4bf26dd 267 rb_radixtree_delete(hostname_tree, hostname);
d38c08c1
WP
268 rb_free(list);
269 }
ae78a571
VY
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{
ae78a571
VY
279 s_assert(name != NULL);
280 s_assert(aconf != NULL);
281 if(EmptyString(name) || aconf == NULL)
282 return;
283
a4bf26dd 284 rb_radixtree_delete(resv_tree, name);
ae78a571
VY
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{
ae78a571
VY
294 if(EmptyString(name))
295 return NULL;
296
a4bf26dd 297 return rb_radixtree_retrieve(client_id_tree, name);
ae78a571
VY
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{
ae78a571
VY
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
a4bf26dd 315 return rb_radixtree_retrieve(client_name_tree, name);
ae78a571
VY
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{
ae78a571
VY
325 s_assert(name != NULL);
326 if(EmptyString(name))
327 return NULL;
328
a4bf26dd 329 return rb_radixtree_retrieve(client_name_tree, name);
ae78a571
VY
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;
55abcbb2 340
ae78a571
VY
341 if(EmptyString(name))
342 return NULL;
343
55abcbb2 344 if((source_p == NULL || !MyClient(source_p)) &&
ae78a571
VY
345 IsDigit(*name) && strlen(name) == 3)
346 {
347 target_p = find_id(name);
348 return(target_p);
349 }
350
a4bf26dd 351 target_p = rb_radixtree_retrieve(client_name_tree, name);
bb4ac314 352 if (target_p != NULL)
ae78a571 353 {
bb4ac314
WP
354 if(IsServer(target_p) || IsMe(target_p))
355 return target_p;
ae78a571
VY
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{
d38c08c1 370 rb_dlink_list *hlist;
ae78a571
VY
371
372 if(EmptyString(hostname))
373 return NULL;
374
a4bf26dd 375 hlist = rb_radixtree_retrieve(hostname_tree, hostname);
d38c08c1
WP
376 if (hlist == NULL)
377 return NULL;
ae78a571 378
d38c08c1 379 return hlist->head;
ae78a571
VY
380}
381
382/* find_channel()
383 *
384 * finds a channel from the channel hash table
385 */
386struct Channel *
387find_channel(const char *name)
388{
ae78a571
VY
389 s_assert(name != NULL);
390 if(EmptyString(name))
391 return NULL;
392
a4bf26dd 393 return rb_radixtree_retrieve(channel_tree, name);
ae78a571
VY
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 *
aa7eff28 408get_or_create_channel(struct Client *client_p, const char *chname, bool *isnew)
ae78a571
VY
409{
410 struct Channel *chptr;
ae78a571
VY
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 {
a9227555 423 sendto_realops_snomask(SNO_DEBUG, L_NETWIDE,
ae78a571
VY
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);
b9a6f1e5 429 t[len] = '\0';
ae78a571
VY
430 s = t;
431 }
432
a4bf26dd 433 chptr = rb_radixtree_retrieve(channel_tree, s);
9b74b992 434 if (chptr != NULL)
ae78a571 435 {
9b74b992 436 if (isnew != NULL)
aa7eff28 437 *isnew = false;
9b74b992 438 return chptr;
ae78a571
VY
439 }
440
441 if(isnew != NULL)
aa7eff28 442 *isnew = true;
ae78a571
VY
443
444 chptr = allocate_channel(s);
ae78a571
VY
445 chptr->channelts = rb_current_time(); /* doesn't hurt to set it here */
446
9b74b992 447 rb_dlinkAdd(chptr, &chptr->node, &global_channel_list);
a4bf26dd 448 rb_radixtree_add(channel_tree, chptr->chname, chptr);
ae78a571
VY
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;
ae78a571
VY
461
462 s_assert(name != NULL);
463 if(EmptyString(name))
464 return NULL;
465
a4bf26dd 466 aconf = rb_radixtree_retrieve(resv_tree, name);
46be39fa 467 if (aconf != NULL)
ae78a571 468 {
46be39fa
WP
469 aconf->port++;
470 return aconf;
ae78a571
VY
471 }
472
473 return NULL;
474}
475
476void
477clear_resv_hash(void)
478{
479 struct ConfItem *aconf;
2fc6772e 480 rb_radixtree_iteration_state iter;
ae78a571 481
a4bf26dd 482 RB_RADIXTREE_FOREACH(aconf, &iter, resv_tree)
ae78a571 483 {
ae78a571
VY
484 /* skip temp resvs */
485 if(aconf->hold)
486 continue;
487
a4bf26dd 488 rb_radixtree_delete(resv_tree, aconf->host);
46be39fa 489 free_conf(aconf);
ae78a571 490 }
ae78a571
VY
491}
492
8bd5767b 493void
de7cf7e0 494add_to_cli_connid_hash(struct Client *client_p, uint32_t id)
8bd5767b 495{
de7cf7e0 496 rb_dictionary_add(client_connid_tree, RB_UINT_TO_POINTER(id), client_p);
8bd5767b
JT
497}
498
b5b4a0e7 499void
de7cf7e0 500del_from_cli_connid_hash(uint32_t id)
b5b4a0e7 501{
de7cf7e0 502 rb_dictionary_delete(client_connid_tree, RB_UINT_TO_POINTER(id));
8bd5767b
JT
503}
504
505struct Client *
5c7c7d65 506find_cli_connid_hash(uint32_t connid)
8bd5767b 507{
de7cf7e0 508 return rb_dictionary_retrieve(client_connid_tree, RB_UINT_TO_POINTER(connid));
c6d72037 509}