2 * ircd-ratbox: A slightly useful ircd.
3 * hash.c: Maintains hashtables.
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
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.
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.
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
26 #include "ircd_defs.h"
33 #include "irc_string.h"
40 #include "s_newconf.h"
42 dlink_list
*clientTable
;
43 dlink_list
*channelTable
;
45 dlink_list
*resvTable
;
46 dlink_list
*hostTable
;
47 dlink_list
*helpTable
;
51 * look in whowas.c for the missing ...[WW_MAX]; entry
57 * The server uses a chained hash table to provide quick and efficient
58 * hash table maintenance (providing the hash function works evenly over
59 * the input range). The hash table is thus not susceptible to problems
60 * of filling all the buckets or the need to rehash.
61 * It is expected that the hash table would look something like this
63 * +-----+ +-----+ +-----+ +-----+
64 * ---| 224 |----| 225 |----| 226 |---| 227 |---
65 * +-----+ +-----+ +-----+ +-----+
67 * +-----+ +-----+ +-----+
69 * +-----+ +-----+ +-----+
75 * A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
77 * The order shown above is just one instant of the server.
80 * The hash functions currently used are based Fowler/Noll/Vo hashes
81 * which work amazingly well and have a extremely low collision rate
82 * For more info see http://www.isthe.com/chongo/tech/comp/fnv/index.html
89 * clears the various hashtables
94 clientTable
= MyMalloc(sizeof(dlink_list
) * U_MAX
);
95 idTable
= MyMalloc(sizeof(dlink_list
) * U_MAX
);
96 ndTable
= MyMalloc(sizeof(dlink_list
) * U_MAX
);
97 channelTable
= MyMalloc(sizeof(dlink_list
) * CH_MAX
);
98 hostTable
= MyMalloc(sizeof(dlink_list
) * HOST_MAX
);
99 resvTable
= MyMalloc(sizeof(dlink_list
) * R_MAX
);
100 helpTable
= MyMalloc(sizeof(dlink_list
) * HELP_MAX
);
103 #ifndef RICER_HASHING
105 fnv_hash_upper(const unsigned char *s
, int bits
)
107 u_int32_t h
= FNV1_32_INIT
;
112 h
+= (h
<<1) + (h
<<4) + (h
<<7) + (h
<< 8) + (h
<< 24);
114 h
= (h
>> bits
) ^ (h
& ((2^bits
)-1));
119 fnv_hash(const unsigned char *s
, int bits
)
121 u_int32_t h
= FNV1_32_INIT
;
126 h
+= (h
<<1) + (h
<<4) + (h
<<7) + (h
<< 8) + (h
<< 24);
128 h
= (h
>> bits
) ^ (h
& ((2^bits
)-1));
133 fnv_hash_len(const unsigned char *s
, int bits
, int len
)
135 u_int32_t h
= FNV1_32_INIT
;
136 const unsigned char *x
= s
+ len
;
140 h
+= (h
<<1) + (h
<<4) + (h
<<7) + (h
<< 8) + (h
<< 24);
142 h
= (h
>> bits
) ^ (h
& ((2^bits
)-1));
147 fnv_hash_upper_len(const unsigned char *s
, int bits
, int len
)
149 u_int32_t h
= FNV1_32_INIT
;
150 const unsigned char *x
= s
+ len
;
154 h
+= (h
<<1) + (h
<<4) + (h
<<7) + (h
<< 8) + (h
<< 24);
156 h
= (h
>> bits
) ^ (h
& ((2^bits
)-1));
163 * hashes a nickname, first converting to lowercase
166 hash_nick(const char *name
)
168 return fnv_hash_upper((const unsigned char *) name
, U_MAX_BITS
);
173 * hashes an id, case is kept
176 hash_id(const char *name
)
178 return fnv_hash((const unsigned char *) name
, U_MAX_BITS
);
183 * hashes a channel name, based on first 30 chars only for efficiency
186 hash_channel(const char *name
)
188 return fnv_hash_upper_len((const unsigned char *) name
, CH_MAX_BITS
, 30);
193 * hashes a hostname, based on first 30 chars only, as thats likely to
194 * be more dynamic than rest.
197 hash_hostname(const char *name
)
199 return fnv_hash_upper_len((const unsigned char *) name
, HOST_MAX_BITS
, 30);
204 * hashes a resv channel name, based on first 30 chars only
207 hash_resv(const char *name
)
209 return fnv_hash_upper_len((const unsigned char *) name
, R_MAX_BITS
, 30);
213 hash_help(const char *name
)
219 h
+= (unsigned int) (ToLower(*name
++) & 0xDF);
222 return (h
% HELP_MAX
);
227 * adds an entry to the id hash table
230 add_to_id_hash(const char *name
, struct Client
*client_p
)
234 if(EmptyString(name
) || (client_p
== NULL
))
237 hashv
= hash_id(name
);
238 dlinkAddAlloc(client_p
, &idTable
[hashv
]);
241 /* add_to_client_hash()
243 * adds an entry (client/server) to the client hash table
246 add_to_client_hash(const char *name
, struct Client
*client_p
)
250 s_assert(name
!= NULL
);
251 s_assert(client_p
!= NULL
);
252 if(EmptyString(name
) || (client_p
== NULL
))
255 hashv
= hash_nick(name
);
256 dlinkAddAlloc(client_p
, &clientTable
[hashv
]);
259 /* add_to_hostname_hash()
261 * adds a client entry to the hostname hash table
264 add_to_hostname_hash(const char *hostname
, struct Client
*client_p
)
268 s_assert(hostname
!= NULL
);
269 s_assert(client_p
!= NULL
);
270 if(EmptyString(hostname
) || (client_p
== NULL
))
273 hashv
= hash_hostname(hostname
);
274 dlinkAddAlloc(client_p
, &hostTable
[hashv
]);
277 /* add_to_resv_hash()
279 * adds a resv channel entry to the resv hash table
282 add_to_resv_hash(const char *name
, struct ConfItem
*aconf
)
286 s_assert(!EmptyString(name
));
287 s_assert(aconf
!= NULL
);
288 if(EmptyString(name
) || aconf
== NULL
)
291 hashv
= hash_resv(name
);
292 dlinkAddAlloc(aconf
, &resvTable
[hashv
]);
296 add_to_help_hash(const char *name
, struct cachefile
*hptr
)
300 if(EmptyString(name
) || hptr
== NULL
)
303 hashv
= hash_help(name
);
304 dlinkAddAlloc(hptr
, &helpTable
[hashv
]);
308 add_to_nd_hash(const char *name
, struct nd_entry
*nd
)
310 nd
->hashv
= hash_nick(name
);
311 dlinkAdd(nd
, &nd
->hnode
, &ndTable
[nd
->hashv
]);
314 /* del_from_id_hash()
316 * removes an id from the id hash table
319 del_from_id_hash(const char *id
, struct Client
*client_p
)
323 s_assert(id
!= NULL
);
324 s_assert(client_p
!= NULL
);
325 if(EmptyString(id
) || client_p
== NULL
)
329 dlinkFindDestroy(client_p
, &idTable
[hashv
]);
332 /* del_from_client_hash()
334 * removes a client/server from the client hash table
337 del_from_client_hash(const char *name
, struct Client
*client_p
)
341 /* no s_asserts, this can happen when removing a client that
344 if(EmptyString(name
) || client_p
== NULL
)
347 hashv
= hash_nick(name
);
348 dlinkFindDestroy(client_p
, &clientTable
[hashv
]);
351 /* del_from_channel_hash()
353 * removes a channel from the channel hash table
356 del_from_channel_hash(const char *name
, struct Channel
*chptr
)
360 s_assert(name
!= NULL
);
361 s_assert(chptr
!= NULL
);
363 if(EmptyString(name
) || chptr
== NULL
)
366 hashv
= hash_channel(name
);
367 dlinkFindDestroy(chptr
, &channelTable
[hashv
]);
370 /* del_from_hostname_hash()
372 * removes a client entry from the hostname hash table
375 del_from_hostname_hash(const char *hostname
, struct Client
*client_p
)
379 if(hostname
== NULL
|| client_p
== NULL
)
382 hashv
= hash_hostname(hostname
);
384 dlinkFindDestroy(client_p
, &hostTable
[hashv
]);
387 /* del_from_resv_hash()
389 * removes a resv entry from the resv hash table
392 del_from_resv_hash(const char *name
, struct ConfItem
*aconf
)
396 s_assert(name
!= NULL
);
397 s_assert(aconf
!= NULL
);
398 if(EmptyString(name
) || aconf
== NULL
)
401 hashv
= hash_resv(name
);
403 dlinkFindDestroy(aconf
, &resvTable
[hashv
]);
407 clear_help_hash(void)
410 dlink_node
*next_ptr
;
413 HASH_WALK_SAFE(i
, HELP_MAX
, ptr
, next_ptr
, helpTable
)
415 free_cachefile(ptr
->data
);
416 dlinkDestroy(ptr
, &helpTable
[i
]);
423 * finds a client entry from the id hash table
426 find_id(const char *name
)
428 struct Client
*target_p
;
432 if(EmptyString(name
))
435 hashv
= hash_id(name
);
437 DLINK_FOREACH(ptr
, idTable
[hashv
].head
)
439 target_p
= ptr
->data
;
441 if(strcmp(name
, target_p
->id
) == 0)
448 /* hash_find_masked_server()
450 * Whats happening in this next loop ? Well, it takes a name like
451 * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu.
452 * This is for checking full server names against masks although
453 * it isnt often done this way in lieu of using matches().
455 * Rewrote to do *.bar.edu first, which is the most likely case,
456 * also made const correct
459 static struct Client
*
460 hash_find_masked_server(struct Client
*source_p
, const char *name
)
462 char buf
[HOSTLEN
+ 1];
465 struct Client
*server
;
467 if('*' == *name
|| '.' == *name
)
470 /* copy it across to give us a buffer to work on */
471 strlcpy(buf
, name
, sizeof(buf
));
473 while ((s
= strchr(p
, '.')) != 0)
477 * Dont need to check IsServer() here since nicknames cant
478 * have *'s in them anyway.
480 if((server
= find_server(source_p
, s
)))
490 * finds a client/server/masked server entry from the hash
493 find_any_client(const char *name
)
495 struct Client
*target_p
;
499 s_assert(name
!= NULL
);
500 if(EmptyString(name
))
503 /* hunting for an id, not a nick */
505 return (find_id(name
));
507 hashv
= hash_nick(name
);
509 DLINK_FOREACH(ptr
, clientTable
[hashv
].head
)
511 target_p
= ptr
->data
;
513 if(irccmp(name
, target_p
->name
) == 0)
517 /* wasnt found, look for a masked server */
518 return hash_find_masked_server(NULL
, name
);
523 * finds a client/server entry from the client hash table
526 find_client(const char *name
)
528 struct Client
*target_p
;
532 s_assert(name
!= NULL
);
533 if(EmptyString(name
))
536 /* hunting for an id, not a nick */
538 return (find_id(name
));
540 hashv
= hash_nick(name
);
542 DLINK_FOREACH(ptr
, clientTable
[hashv
].head
)
544 target_p
= ptr
->data
;
546 if(irccmp(name
, target_p
->name
) == 0)
553 /* find_named_client()
555 * finds a client/server entry from the client hash table
558 find_named_client(const char *name
)
560 struct Client
*target_p
;
564 s_assert(name
!= NULL
);
565 if(EmptyString(name
))
568 hashv
= hash_nick(name
);
570 DLINK_FOREACH(ptr
, clientTable
[hashv
].head
)
572 target_p
= ptr
->data
;
574 if(irccmp(name
, target_p
->name
) == 0)
583 * finds a server from the client hash table
586 find_server(struct Client
*source_p
, const char *name
)
588 struct Client
*target_p
;
592 if(EmptyString(name
))
595 if((source_p
== NULL
|| !MyClient(source_p
)) &&
596 IsDigit(*name
) && strlen(name
) == 3)
598 target_p
= find_id(name
);
602 hashv
= hash_nick(name
);
604 DLINK_FOREACH(ptr
, clientTable
[hashv
].head
)
606 target_p
= ptr
->data
;
608 if((IsServer(target_p
) || IsMe(target_p
)) &&
609 irccmp(name
, target_p
->name
) == 0)
613 /* wasnt found, look for a masked server */
614 return hash_find_masked_server(source_p
, name
);
619 * finds a hostname dlink list from the hostname hash table.
620 * we return the full dlink list, because you can have multiple
621 * entries with the same hostname
624 find_hostname(const char *hostname
)
628 if(EmptyString(hostname
))
631 hashv
= hash_hostname(hostname
);
633 return hostTable
[hashv
].head
;
638 * finds a channel from the channel hash table
641 find_channel(const char *name
)
643 struct Channel
*chptr
;
647 s_assert(name
!= NULL
);
648 if(EmptyString(name
))
651 hashv
= hash_channel(name
);
653 DLINK_FOREACH(ptr
, channelTable
[hashv
].head
)
657 if(irccmp(name
, chptr
->chname
) == 0)
665 * get_or_create_channel
666 * inputs - client pointer
668 * - pointer to int flag whether channel was newly created or not
669 * output - returns channel block or NULL if illegal name
670 * - also modifies *isnew
672 * Get Channel block for chname (and allocate a new channel
673 * block, if it didn't exist before).
676 get_or_create_channel(struct Client
*client_p
, const char *chname
, int *isnew
)
678 struct Channel
*chptr
;
682 const char *s
= chname
;
691 if(IsServer(client_p
))
693 sendto_realops_snomask(SNO_DEBUG
, L_NETWIDE
,
694 "*** Long channel name from %s (%d > %d): %s",
695 client_p
->name
, len
, CHANNELLEN
, s
);
699 *(t
+ CHANNELLEN
) = '\0';
703 hashv
= hash_channel(s
);
705 DLINK_FOREACH(ptr
, channelTable
[hashv
].head
)
709 if(irccmp(s
, chptr
->chname
) == 0)
720 chptr
= allocate_channel(s
);
722 dlinkAdd(chptr
, &chptr
->node
, &global_channel_list
);
724 chptr
->channelts
= CurrentTime
; /* doesn't hurt to set it here */
726 dlinkAddAlloc(chptr
, &channelTable
[hashv
]);
733 * hunts for a resv entry in the resv hash table
736 hash_find_resv(const char *name
)
738 struct ConfItem
*aconf
;
742 s_assert(name
!= NULL
);
743 if(EmptyString(name
))
746 hashv
= hash_resv(name
);
748 DLINK_FOREACH(ptr
, resvTable
[hashv
].head
)
752 if(!irccmp(name
, aconf
->name
))
763 hash_find_help(const char *name
, int flags
)
765 struct cachefile
*hptr
;
769 if(EmptyString(name
))
772 hashv
= hash_help(name
);
774 DLINK_FOREACH(ptr
, helpTable
[hashv
].head
)
778 if((irccmp(name
, hptr
->name
) == 0) &&
779 (hptr
->flags
& flags
))
787 clear_resv_hash(void)
789 struct ConfItem
*aconf
;
791 dlink_node
*next_ptr
;
794 HASH_WALK_SAFE(i
, R_MAX
, ptr
, next_ptr
, resvTable
)
798 /* skip temp resvs */
802 free_conf(ptr
->data
);
803 dlinkDestroy(ptr
, &resvTable
[i
]);
809 hash_find_nd(const char *name
)
815 if(EmptyString(name
))
818 hashv
= hash_nick(name
);
820 DLINK_FOREACH(ptr
, ndTable
[hashv
].head
)
824 if(!irccmp(name
, nd
->name
))
832 output_hash(struct Client
*source_p
, const char *name
, int length
, int *counts
, int deepest
)
834 unsigned long total
= 0;
837 sendto_one_numeric(source_p
, RPL_STATSDEBUG
,
838 "B :%s Hash Statistics", name
);
840 sendto_one_numeric(source_p
, RPL_STATSDEBUG
,
841 "B :Size: %d Empty: %d (%.3f%%)",
843 (float) ((counts
[0]*100) / (float) length
));
845 for(i
= 1; i
< 11; i
++)
847 total
+= (counts
[i
] * i
);
850 /* dont want to divide by 0! --fl */
851 if(counts
[0] != length
)
852 sendto_one_numeric(source_p
, RPL_STATSDEBUG
,
853 "B :Average depth: %.3f/%.3f Highest depth: %d",
854 (float) (total
/ (length
- counts
[0])),
855 (float) (total
/ length
), deepest
);
857 for(i
= 0; i
< 11; i
++)
859 sendto_one_numeric(source_p
, RPL_STATSDEBUG
,
860 "B :Nodes with %d entries: %d",
867 count_hash(struct Client
*source_p
, dlink_list
*table
, int length
, const char *name
)
873 memset(counts
, 0, sizeof(counts
));
875 for(i
= 0; i
< length
; i
++)
877 if(dlink_list_length(&table
[i
]) >= 10)
880 counts
[dlink_list_length(&table
[i
])]++;
882 if(dlink_list_length(&table
[i
]) > deepest
)
883 deepest
= dlink_list_length(&table
[i
]);
886 output_hash(source_p
, name
, length
, counts
, deepest
);
890 hash_stats(struct Client
*source_p
)
892 count_hash(source_p
, channelTable
, CH_MAX
, "Channel");
893 sendto_one_numeric(source_p
, RPL_STATSDEBUG
, "B :--");
894 count_hash(source_p
, clientTable
, U_MAX
, "Client");
895 sendto_one_numeric(source_p
, RPL_STATSDEBUG
, "B :--");
896 count_hash(source_p
, idTable
, U_MAX
, "ID");
897 sendto_one_numeric(source_p
, RPL_STATSDEBUG
, "B :--");
898 count_hash(source_p
, hostTable
, HOST_MAX
, "Hostname");