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