ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 7484
Committed: Wed Mar 16 09:28:14 2016 UTC (9 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 16085 byte(s)
Log Message:
- hash.c: remove unused header includes

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 7006 * Copyright (c) 1997-2016 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * USA
20     */
21    
22 michael 2916 /*! \file hash.c
23     * \brief Hash table management.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 michael 1309 #include "conf.h"
30 adx 30 #include "channel.h"
31     #include "channel_mode.h"
32     #include "client.h"
33     #include "hash.h"
34 michael 6161 #include "id.h"
35 michael 982 #include "rng_mt.h"
36 adx 30 #include "userhost.h"
37     #include "irc_string.h"
38     #include "ircd.h"
39     #include "numeric.h"
40     #include "send.h"
41     #include "memory.h"
42     #include "dbuf.h"
43    
44    
45 michael 5460 static unsigned int hashf_xor_key;
46 adx 30
47     /* The actual hash tables, They MUST be of the same HASHSIZE, variable
48     * size tables could be supported but the rehash routine should also
49 michael 2916 * rebuild the transformation maps, I kept the tables of equal size
50 adx 30 * so that I can use one hash function.
51     */
52     static struct Client *idTable[HASHSIZE];
53     static struct Client *clientTable[HASHSIZE];
54     static struct Channel *channelTable[HASHSIZE];
55     static struct UserHost *userhostTable[HASHSIZE];
56    
57    
58 michael 6393 /* hash_init()
59 adx 30 *
60     * inputs - NONE
61     * output - NONE
62     * side effects - Initialize the maps used by hash
63     * functions and clear the tables
64     */
65     void
66 michael 1798 hash_init(void)
67 adx 30 {
68 michael 7031 do
69     hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */
70     while (!hashf_xor_key);
71 adx 30 }
72    
73     /*
74     * New hash function based on the Fowler/Noll/Vo (FNV) algorithm from
75     * http://www.isthe.com/chongo/tech/comp/fnv/
76     *
77     * Here, we use the FNV-1 method, which gives slightly better results
78     * than FNV-1a. -Michael
79     */
80     unsigned int
81     strhash(const char *name)
82     {
83     const unsigned char *p = (const unsigned char *)name;
84     unsigned int hval = FNV1_32_INIT;
85    
86 michael 1826 if (EmptyString(p))
87 adx 30 return 0;
88 michael 4890
89     for (; *p; ++p)
90 adx 30 {
91     hval += (hval << 1) + (hval << 4) + (hval << 7) +
92     (hval << 8) + (hval << 24);
93 michael 982 hval ^= (ToLower(*p) ^ hashf_xor_key);
94 adx 30 }
95    
96 michael 982 return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1));
97 adx 30 }
98    
99     /************************** Externally visible functions ********************/
100    
101     /* Optimization note: in these functions I supposed that the CSE optimization
102     * (Common Subexpression Elimination) does its work decently, this means that
103     * I avoided introducing new variables to do the work myself and I did let
104     * the optimizer play with more free registers, actual tests proved this
105     * solution to be faster than doing things like tmp2=tmp->hnext... and then
106     * use tmp2 myself which would have given less freedom to the optimizer.
107     */
108    
109     /* hash_add_client()
110     *
111     * inputs - pointer to client
112     * output - NONE
113     * side effects - Adds a client's name in the proper hash linked
114     * list, can't fail, client_p must have a non-null
115     * name or expect a coredump, the name is infact
116     * taken from client_p->name
117     */
118     void
119     hash_add_client(struct Client *client_p)
120     {
121 michael 4977 const unsigned int hashv = strhash(client_p->name);
122 adx 30
123     client_p->hnext = clientTable[hashv];
124     clientTable[hashv] = client_p;
125     }
126    
127     /* hash_add_channel()
128     *
129     * inputs - pointer to channel
130     * output - NONE
131     * side effects - Adds a channel's name in the proper hash linked
132     * list, can't fail. chptr must have a non-null name
133     * or expect a coredump. As before the name is taken
134     * from chptr->name, we do hash its entire lenght
135     * since this proved to be statistically faster
136     */
137     void
138     hash_add_channel(struct Channel *chptr)
139     {
140 michael 4977 const unsigned int hashv = strhash(chptr->name);
141 adx 30
142     chptr->hnextch = channelTable[hashv];
143     channelTable[hashv] = chptr;
144     }
145    
146     void
147     hash_add_userhost(struct UserHost *userhost)
148     {
149 michael 4977 const unsigned int hashv = strhash(userhost->host);
150 adx 30
151     userhost->next = userhostTable[hashv];
152     userhostTable[hashv] = userhost;
153     }
154    
155     void
156     hash_add_id(struct Client *client_p)
157     {
158 michael 4977 const unsigned int hashv = strhash(client_p->id);
159 adx 30
160     client_p->idhnext = idTable[hashv];
161     idTable[hashv] = client_p;
162     }
163    
164     /* hash_del_id()
165     *
166     * inputs - pointer to client
167     * output - NONE
168     * side effects - Removes an ID from the hash linked list
169     */
170     void
171     hash_del_id(struct Client *client_p)
172     {
173 michael 4977 const unsigned int hashv = strhash(client_p->id);
174 adx 30 struct Client *tmp = idTable[hashv];
175    
176 michael 3241 if (tmp)
177 adx 30 {
178     if (tmp == client_p)
179     {
180     idTable[hashv] = client_p->idhnext;
181     client_p->idhnext = client_p;
182     }
183     else
184     {
185     while (tmp->idhnext != client_p)
186     if ((tmp = tmp->idhnext) == NULL)
187     return;
188    
189     tmp->idhnext = tmp->idhnext->idhnext;
190     client_p->idhnext = client_p;
191     }
192     }
193     }
194    
195     /* hash_del_client()
196     *
197     * inputs - pointer to client
198     * output - NONE
199     * side effects - Removes a Client's name from the hash linked list
200     */
201     void
202     hash_del_client(struct Client *client_p)
203     {
204 michael 4977 const unsigned int hashv = strhash(client_p->name);
205 adx 30 struct Client *tmp = clientTable[hashv];
206    
207 michael 3241 if (tmp)
208 adx 30 {
209     if (tmp == client_p)
210     {
211     clientTable[hashv] = client_p->hnext;
212     client_p->hnext = client_p;
213     }
214     else
215     {
216     while (tmp->hnext != client_p)
217     if ((tmp = tmp->hnext) == NULL)
218     return;
219    
220     tmp->hnext = tmp->hnext->hnext;
221     client_p->hnext = client_p;
222     }
223     }
224     }
225    
226     /* hash_del_userhost()
227     *
228     * inputs - pointer to userhost
229     * output - NONE
230     * side effects - Removes a userhost from the hash linked list
231     */
232     void
233     hash_del_userhost(struct UserHost *userhost)
234     {
235 michael 4977 const unsigned int hashv = strhash(userhost->host);
236 adx 30 struct UserHost *tmp = userhostTable[hashv];
237    
238 michael 3241 if (tmp)
239 adx 30 {
240     if (tmp == userhost)
241     {
242     userhostTable[hashv] = userhost->next;
243     userhost->next = userhost;
244     }
245     else
246     {
247     while (tmp->next != userhost)
248     if ((tmp = tmp->next) == NULL)
249     return;
250    
251     tmp->next = tmp->next->next;
252     userhost->next = userhost;
253     }
254     }
255     }
256    
257     /* hash_del_channel()
258     *
259     * inputs - pointer to client
260     * output - NONE
261     * side effects - Removes the channel's name from the corresponding
262     * hash linked list
263     */
264     void
265     hash_del_channel(struct Channel *chptr)
266     {
267 michael 4977 const unsigned int hashv = strhash(chptr->name);
268 adx 30 struct Channel *tmp = channelTable[hashv];
269    
270 michael 3241 if (tmp)
271 adx 30 {
272     if (tmp == chptr)
273     {
274     channelTable[hashv] = chptr->hnextch;
275     chptr->hnextch = chptr;
276     }
277     else
278     {
279     while (tmp->hnextch != chptr)
280     if ((tmp = tmp->hnextch) == NULL)
281     return;
282    
283     tmp->hnextch = tmp->hnextch->hnextch;
284     chptr->hnextch = chptr;
285     }
286     }
287     }
288    
289 michael 1169 /* hash_find_client()
290 adx 30 *
291     * inputs - pointer to name
292     * output - NONE
293     * side effects - New semantics: finds a client whose name is 'name'
294     * if can't find one returns NULL. If it finds one moves
295     * it to the top of the list and returns it.
296     */
297     struct Client *
298 michael 1169 hash_find_client(const char *name)
299 adx 30 {
300 michael 4977 const unsigned int hashv = strhash(name);
301 adx 30 struct Client *client_p;
302    
303 michael 3241 if ((client_p = clientTable[hashv]))
304 adx 30 {
305     if (irccmp(name, client_p->name))
306     {
307     struct Client *prev;
308    
309 michael 3241 while (prev = client_p, (client_p = client_p->hnext))
310 adx 30 {
311     if (!irccmp(name, client_p->name))
312     {
313     prev->hnext = client_p->hnext;
314     client_p->hnext = clientTable[hashv];
315     clientTable[hashv] = client_p;
316     break;
317     }
318     }
319     }
320     }
321    
322     return client_p;
323     }
324    
325     struct Client *
326     hash_find_id(const char *name)
327     {
328 michael 4977 const unsigned int hashv = strhash(name);
329 adx 30 struct Client *client_p;
330    
331 michael 3242 if ((client_p = idTable[hashv]))
332 adx 30 {
333 michael 880 if (strcmp(name, client_p->id))
334 adx 30 {
335     struct Client *prev;
336    
337 michael 3242 while (prev = client_p, (client_p = client_p->idhnext))
338 adx 30 {
339 michael 880 if (!strcmp(name, client_p->id))
340 adx 30 {
341     prev->idhnext = client_p->idhnext;
342     client_p->idhnext = idTable[hashv];
343     idTable[hashv] = client_p;
344     break;
345     }
346     }
347     }
348     }
349    
350     return client_p;
351     }
352    
353     struct Client *
354 michael 1169 hash_find_server(const char *name)
355 adx 30 {
356 michael 4977 const unsigned int hashv = strhash(name);
357 adx 30 struct Client *client_p = NULL;
358    
359     if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
360 michael 1397 return hash_find_id(name);
361 adx 30
362 michael 3242 if ((client_p = clientTable[hashv]))
363 adx 30 {
364     if ((!IsServer(client_p) && !IsMe(client_p)) ||
365     irccmp(name, client_p->name))
366     {
367     struct Client *prev;
368    
369 michael 3242 while (prev = client_p, (client_p = client_p->hnext))
370 adx 30 {
371     if ((IsServer(client_p) || IsMe(client_p)) &&
372     !irccmp(name, client_p->name))
373     {
374     prev->hnext = client_p->hnext;
375     client_p->hnext = clientTable[hashv];
376     clientTable[hashv] = client_p;
377     break;
378     }
379     }
380     }
381     }
382    
383 michael 1118 return client_p;
384 adx 30 }
385    
386     /* hash_find_channel()
387     *
388     * inputs - pointer to name
389     * output - NONE
390 michael 2916 * side effects - New semantics: finds a channel whose name is 'name',
391 adx 30 * if can't find one returns NULL, if can find it moves
392     * it to the top of the list and returns it.
393     */
394     struct Channel *
395     hash_find_channel(const char *name)
396     {
397 michael 4977 const unsigned int hashv = strhash(name);
398 adx 30 struct Channel *chptr = NULL;
399    
400 michael 3242 if ((chptr = channelTable[hashv]))
401 adx 30 {
402 michael 4618 if (irccmp(name, chptr->name))
403 adx 30 {
404     struct Channel *prev;
405    
406 michael 3242 while (prev = chptr, (chptr = chptr->hnextch))
407 adx 30 {
408 michael 4618 if (!irccmp(name, chptr->name))
409 adx 30 {
410     prev->hnextch = chptr->hnextch;
411     chptr->hnextch = channelTable[hashv];
412     channelTable[hashv] = chptr;
413     break;
414     }
415     }
416     }
417     }
418    
419     return chptr;
420     }
421    
422 michael 6393 struct UserHost *
423     hash_find_userhost(const char *host)
424     {
425     const unsigned int hashv = strhash(host);
426     struct UserHost *userhost;
427    
428     if ((userhost = userhostTable[hashv]))
429     {
430     if (irccmp(host, userhost->host))
431     {
432     struct UserHost *prev;
433    
434     while (prev = userhost, (userhost = userhost->next))
435     {
436     if (!irccmp(host, userhost->host))
437     {
438     prev->next = userhost->next;
439     userhost->next = userhostTable[hashv];
440     userhostTable[hashv] = userhost;
441     break;
442     }
443     }
444     }
445     }
446    
447     return userhost;
448     }
449    
450 adx 30 /* hash_get_bucket(int type, unsigned int hashv)
451     *
452     * inputs - hash value (must be between 0 and HASHSIZE - 1)
453     * output - NONE
454     * returns - pointer to first channel in channelTable[hashv]
455     * if that exists;
456     * NULL if there is no channel in that place;
457     * NULL if hashv is an invalid number.
458     * side effects - NONE
459     */
460     void *
461     hash_get_bucket(int type, unsigned int hashv)
462     {
463     assert(hashv < HASHSIZE);
464 michael 4977
465 adx 30 if (hashv >= HASHSIZE)
466 michael 6393 return NULL;
467 adx 30
468     switch (type)
469     {
470     case HASH_TYPE_ID:
471     return idTable[hashv];
472     break;
473     case HASH_TYPE_CHANNEL:
474     return channelTable[hashv];
475     break;
476     case HASH_TYPE_CLIENT:
477     return clientTable[hashv];
478     break;
479     case HASH_TYPE_USERHOST:
480     return userhostTable[hashv];
481     break;
482     default:
483     assert(0);
484     }
485    
486     return NULL;
487     }
488    
489     /*
490     * Safe list code.
491     *
492     * The idea is really quite simple. As the link lists pointed to in
493     * each "bucket" of the channel hash table are traversed atomically
494     * there is no locking needed. Overall, yes, inconsistent reported
495     * state can still happen, but normally this isn't a big deal.
496     * I don't like sticking the code into hash.c but oh well. Moreover,
497     * if a hash isn't used in future, oops.
498     *
499     * - Dianora
500     */
501    
502     /* exceeding_sendq()
503     *
504     * inputs - pointer to client to check
505     * output - 1 if client is in danger of blowing its sendq
506     * 0 if it is not.
507     * side effects -
508     *
509     * Sendq limit is fairly conservative at 1/2 (In original anyway)
510     */
511     static int
512 michael 2757 exceeding_sendq(const struct Client *to)
513 adx 30 {
514 michael 4588 if (dbuf_length(&to->connection->buf_sendq) > (get_sendq(&to->connection->confs) / 2))
515 adx 30 return 1;
516     else
517     return 0;
518     }
519    
520     void
521 michael 3289 free_list_task(struct Client *source_p)
522 adx 30 {
523 michael 4870 struct ListTask *const lt = source_p->connection->list_task;
524 michael 4815 dlink_node *node = NULL, *node_next = NULL;
525 adx 30
526 michael 6385 dlinkDelete(&lt->node, &listing_client_list);
527 adx 30
528 michael 4815 DLINK_FOREACH_SAFE(node, node_next, lt->show_mask.head)
529 adx 30 {
530 michael 7032 xfree(node->data);
531 michael 4815 free_dlink_node(node);
532 adx 30 }
533    
534 michael 4815 DLINK_FOREACH_SAFE(node, node_next, lt->hide_mask.head)
535 adx 30 {
536 michael 7032 xfree(node->data);
537 michael 4815 free_dlink_node(node);
538 adx 30 }
539    
540 michael 7032 xfree(lt);
541 michael 4868 source_p->connection->list_task = NULL;
542 adx 30 }
543    
544     /* list_allow_channel()
545     *
546     * inputs - channel name
547     * - pointer to a list task
548     * output - 1 if the channel is to be displayed
549     * 0 otherwise
550     * side effects -
551     */
552     static int
553 michael 4618 list_allow_channel(const char *name, const struct ListTask *lt)
554 adx 30 {
555 michael 4815 const dlink_node *node = NULL;
556 adx 30
557 michael 4815 DLINK_FOREACH(node, lt->show_mask.head)
558     if (match(node->data, name) != 0)
559 adx 30 return 0;
560    
561 michael 4815 DLINK_FOREACH(node, lt->hide_mask.head)
562     if (match(node->data, name) == 0)
563 adx 30 return 0;
564    
565     return 1;
566     }
567    
568     /* list_one_channel()
569     *
570     * inputs - client pointer to return result to
571     * - pointer to channel to list
572     * - pointer to ListTask structure
573     * output - none
574     * side effects -
575     */
576     static void
577 michael 3288 list_one_channel(struct Client *source_p, struct Channel *chptr)
578 adx 30 {
579 michael 4870 const struct ListTask *const lt = source_p->connection->list_task;
580 michael 2616 char listbuf[MODEBUFLEN] = "";
581     char modebuf[MODEBUFLEN] = "";
582     char parabuf[MODEBUFLEN] = "";
583    
584 michael 2495 if (SecretChannel(chptr) &&
585 michael 3428 !(HasUMode(source_p, UMODE_ADMIN) || IsMember(source_p, chptr)))
586 adx 30 return;
587 michael 4890
588 michael 3288 if (dlink_list_length(&chptr->members) < lt->users_min ||
589     dlink_list_length(&chptr->members) > lt->users_max ||
590 michael 4818 (chptr->creationtime != 0 &&
591     ((unsigned int)chptr->creationtime < lt->created_min ||
592     (unsigned int)chptr->creationtime > lt->created_max)) ||
593 michael 3288 (unsigned int)chptr->topic_time < lt->topicts_min ||
594 adx 30 (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
595 michael 3288 lt->topicts_max)
596 adx 30 return;
597    
598 michael 4489 if (lt->topic[0] && match(lt->topic, chptr->topic))
599     return;
600    
601 michael 4618 if (!list_allow_channel(chptr->name, lt))
602 adx 30 return;
603 michael 2616
604 michael 4486 channel_modes(chptr, source_p, modebuf, parabuf);
605 michael 2616
606 michael 4486 if (chptr->topic[0])
607     snprintf(listbuf, sizeof(listbuf), "[%s] ", modebuf);
608     else
609     snprintf(listbuf, sizeof(listbuf), "[%s]", modebuf);
610 michael 2616
611 michael 4618 sendto_one_numeric(source_p, &me, RPL_LIST, chptr->name,
612 michael 3109 dlink_list_length(&chptr->members),
613     listbuf, chptr->topic);
614 adx 30 }
615    
616     /* safe_list_channels()
617     *
618     * inputs - pointer to client requesting list
619     * output - 0/1
620     * side effects - safely list all channels to source_p
621     *
622     * Walk the channel buckets, ensure all pointers in a bucket are
623     * traversed before blocking on a sendq. This means, no locking is needed.
624     *
625     * - Dianora
626     */
627     void
628 michael 3288 safe_list_channels(struct Client *source_p, int only_unmasked_channels)
629 adx 30 {
630 michael 4870 struct ListTask *const lt = source_p->connection->list_task;
631 adx 30 struct Channel *chptr = NULL;
632    
633     if (!only_unmasked_channels)
634     {
635 michael 3288 for (unsigned int i = lt->hash_index; i < HASHSIZE; ++i)
636 adx 30 {
637 michael 3291 if (exceeding_sendq(source_p))
638 adx 30 {
639 michael 3288 lt->hash_index = i;
640     return; /* Still more to do */
641 adx 30 }
642    
643     for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
644 michael 3288 list_one_channel(source_p, chptr);
645 adx 30 }
646     }
647     else
648     {
649 michael 4815 dlink_node *node = NULL;
650 adx 30
651 michael 4815 DLINK_FOREACH(node, lt->show_mask.head)
652     if ((chptr = hash_find_channel(node->data)))
653 michael 3288 list_one_channel(source_p, chptr);
654 adx 30 }
655    
656 michael 3289 free_list_task(source_p);
657 michael 3109 sendto_one_numeric(source_p, &me, RPL_LISTEND);
658 adx 30 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision