mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-02 09:46:39 +02:00
Rewrite hash table code to use SipHash (more to follow)
This commit is contained in:
+6
-4
@@ -368,9 +368,11 @@ extern time_t timeout_query_list(time_t);
|
||||
extern time_t expire_cache(time_t);
|
||||
extern void del_queries(char *);
|
||||
|
||||
extern void clear_channel_hash_table();
|
||||
extern void clear_client_hash_table();
|
||||
extern void clear_watch_hash_table();
|
||||
extern uint64_t siphash(const char *in, const char *k);
|
||||
extern uint64_t siphash_nocase(const char *in, const char *k);
|
||||
extern void siphash_generate_key(char *k);
|
||||
extern void init_hash(void);
|
||||
uint64_t hash_whowas_name(const char *name);
|
||||
extern int add_to_client_hash_table(char *, aClient *);
|
||||
extern int del_from_client_hash_table(char *, aClient *);
|
||||
extern int add_to_id_hash_table(char *, aClient *);
|
||||
@@ -383,7 +385,7 @@ extern int hash_check_watch(aClient *, int);
|
||||
extern int hash_del_watch_list(aClient *);
|
||||
extern void count_watch_memory(int *, u_long *);
|
||||
extern aWatch *hash_get_watch(char *);
|
||||
extern aChannel *hash_get_chan_bucket(unsigned int);
|
||||
extern aChannel *hash_get_chan_bucket(uint64_t);
|
||||
extern aClient *hash_find_client(const char *, aClient *);
|
||||
extern aClient *hash_find_id(const char *, aClient *);
|
||||
extern aClient *hash_find_nickserver(const char *, aClient *);
|
||||
|
||||
+5
-26
@@ -22,6 +22,11 @@
|
||||
#ifndef __hash_include__
|
||||
#define __hash_include__
|
||||
|
||||
#define NICK_HASH_TABLE_SIZE 16384
|
||||
#define CHAN_HASH_TABLE_SIZE 16384
|
||||
#define WATCH_HASH_TABLE_SIZE 16384
|
||||
#define WHOWAS_HASH_TABLE_SIZE 16384
|
||||
|
||||
typedef struct hashentry {
|
||||
int hits;
|
||||
int links;
|
||||
@@ -34,32 +39,6 @@ typedef struct hashentry {
|
||||
#define BITS_PER_COL_MASK 0x7
|
||||
#define MAX_SUB (1<<BITS_PER_COL)
|
||||
|
||||
/* Client hash table
|
||||
* used in hash.c
|
||||
*/
|
||||
|
||||
#define U_MAX_INITIAL 2048
|
||||
#define U_MAX_INITIAL_MASK (U_MAX_INITIAL-1)
|
||||
#define U_MAX (U_MAX_INITIAL*MAX_SUB)
|
||||
|
||||
/* Channel hash table
|
||||
* used in hash.c
|
||||
*/
|
||||
|
||||
#define CH_MAX_INITIAL 2048
|
||||
#define CH_MAX_INITIAL_MASK (CH_MAX_INITIAL-1)
|
||||
#define CH_MAX (CH_MAX_INITIAL*MAX_SUB)
|
||||
|
||||
/* Who was hash table
|
||||
* used in whowas.c
|
||||
*/
|
||||
|
||||
#define WW_MAX_INITIAL 16
|
||||
#define WW_MAX_INITIAL_MASK (WW_MAX_INITIAL-1)
|
||||
#define WW_MAX (WW_MAX_INITIAL*MAX_SUB)
|
||||
|
||||
#define WATCHHASHSIZE 10007 /* prime number */
|
||||
|
||||
/*
|
||||
* Throttling
|
||||
*/
|
||||
|
||||
+282
-192
@@ -19,160 +19,279 @@
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
ID_Copyright("(C) 1991 Darren Reed");
|
||||
ID_Notes("2.10 7/3/93");
|
||||
|
||||
static struct list_head clientTable[U_MAX];
|
||||
static struct list_head idTable[U_MAX];
|
||||
static aHashEntry channelTable[CH_MAX];
|
||||
|
||||
/*
|
||||
* look in whowas.c for the missing ...[WW_MAX]; entry - Dianora */
|
||||
/*
|
||||
* Hashing.
|
||||
*
|
||||
* The server uses a chained hash table to provide quick and efficient
|
||||
* hash table mantainence (providing the hash function works evenly
|
||||
* over the input range). The hash table is thus not susceptible to
|
||||
* problems of filling all the buckets or the need to rehash. It is
|
||||
* expected that the hash table would look somehting like this during
|
||||
* use: +-----+ +-----+ +-----+ +-----+
|
||||
* ---| 224 |----| 225 |----| 226 |---| 227 |---
|
||||
* +-----+ +-----+ +-----+ +-----+
|
||||
* | | |
|
||||
* +-----+ +-----+ +-----+
|
||||
* | A | | C | | D |
|
||||
* +-----+ +-----+ +-----+
|
||||
* |
|
||||
* +-----+
|
||||
* | B |
|
||||
* +-----+
|
||||
*
|
||||
* A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
|
||||
*
|
||||
* The order shown above is just one instant of the server. Each time a
|
||||
* lookup is made on an entry in the hash table and it is found, the
|
||||
* entry is moved to the top of the chain.
|
||||
*
|
||||
* ^^^^^^^^^^^^^^^^ **** Not anymore - Dianora
|
||||
*
|
||||
/* Next #define's, the siphash() and siphash_nocase() functions are based
|
||||
* on the SipHash reference C implementation to which the following applies:
|
||||
* Copyright (c) 2012-2016 Jean-Philippe Aumasson
|
||||
* <jeanphilippe.aumasson@gmail.com>
|
||||
* Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
|
||||
* Further enhancements were made by:
|
||||
* Copyright (c) 2017 Salvatore Sanfilippo <antirez@gmail.com>
|
||||
* To the extent possible under law, the author(s) have dedicated all copyright
|
||||
* and related and neighboring rights to this software to the public domain
|
||||
* worldwide. This software is distributed without any warranty.
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*
|
||||
* In addition to above, Bram Matthys (Syzop), did some minor enhancements,
|
||||
* such as dropping the uint8_t stuff (in UnrealIRCd char is always unsigned)
|
||||
* and getting rid of the length argument.
|
||||
*
|
||||
* The end result are simple functions for API end-users and we encourage
|
||||
* everyone to use these two hash functions everywhere in UnrealIRCd.
|
||||
*/
|
||||
/* Take equal propotions from the size of int on all arcitechtures */
|
||||
#define BITS_IN_int ( sizeof(int) * CHAR_BIT )
|
||||
#define THREE_QUARTERS ((int) ((BITS_IN_int * 3) / 4))
|
||||
#define ONE_EIGHTH ((int) (BITS_IN_int / 8))
|
||||
#define HIGH_BITS ( ~((unsigned int)(~0) >> ONE_EIGHTH ))
|
||||
|
||||
unsigned int hash_nn_name(const char *hname)
|
||||
{
|
||||
unsigned int hash_value, i;
|
||||
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
|
||||
|
||||
for (hash_value = 0; *hname; ++hname)
|
||||
{
|
||||
/* Shift hash-value by one eights of int for adding every letter */
|
||||
hash_value = (hash_value << ONE_EIGHTH) + tolower(*hname);
|
||||
/* If the next shift would cause an overflow... */
|
||||
if ((i = hash_value & HIGH_BITS) != 0)
|
||||
/* Then wrap the upper quarter of bits back to the value */
|
||||
hash_value = (hash_value ^
|
||||
(i >> THREE_QUARTERS)) & ~HIGH_BITS;
|
||||
}
|
||||
#define U32TO8_LE(p, v) \
|
||||
(p)[0] = (char)((v)); \
|
||||
(p)[1] = (char)((v) >> 8); \
|
||||
(p)[2] = (char)((v) >> 16); \
|
||||
(p)[3] = (char)((v) >> 24);
|
||||
|
||||
return (hash_value);
|
||||
}
|
||||
#define U64TO8_LE(p, v) \
|
||||
U32TO8_LE((p), (uint32_t)((v))); \
|
||||
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
|
||||
|
||||
#define U8TO64_LE(p) \
|
||||
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
|
||||
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
|
||||
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
|
||||
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
|
||||
|
||||
unsigned hash_nick_name(const char *nname)
|
||||
{
|
||||
unsigned hash = 0;
|
||||
int hash2 = 0;
|
||||
int ret;
|
||||
char lower;
|
||||
#define U8TO64_LE_NOCASE(p) \
|
||||
(((uint64_t)(tolower((p)[0]))) | \
|
||||
((uint64_t)(tolower((p)[1])) << 8) | \
|
||||
((uint64_t)(tolower((p)[2])) << 16) | \
|
||||
((uint64_t)(tolower((p)[3])) << 24) | \
|
||||
((uint64_t)(tolower((p)[4])) << 32) | \
|
||||
((uint64_t)(tolower((p)[5])) << 40) | \
|
||||
((uint64_t)(tolower((p)[6])) << 48) | \
|
||||
((uint64_t)(tolower((p)[7])) << 56))
|
||||
|
||||
while (*nname)
|
||||
{
|
||||
lower = tolower(*nname);
|
||||
hash = (hash << 1) + lower;
|
||||
hash2 = (hash2 >> 1) + lower;
|
||||
nname++;
|
||||
}
|
||||
ret = ((hash & U_MAX_INITIAL_MASK) << BITS_PER_COL) +
|
||||
(hash2 & BITS_PER_COL_MASK);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* hash_channel_name
|
||||
*
|
||||
* calculate a hash value on at most the first 30 characters of the
|
||||
* channel name. Most names are short than this or dissimilar in this
|
||||
* range. There is little or no point hashing on a full channel name
|
||||
* which maybe 255 chars long.
|
||||
#define SIPROUND \
|
||||
do { \
|
||||
v0 += v1; \
|
||||
v1 = ROTL(v1, 13); \
|
||||
v1 ^= v0; \
|
||||
v0 = ROTL(v0, 32); \
|
||||
v2 += v3; \
|
||||
v3 = ROTL(v3, 16); \
|
||||
v3 ^= v2; \
|
||||
v0 += v3; \
|
||||
v3 = ROTL(v3, 21); \
|
||||
v3 ^= v0; \
|
||||
v2 += v1; \
|
||||
v1 = ROTL(v1, 17); \
|
||||
v1 ^= v2; \
|
||||
v2 = ROTL(v2, 32); \
|
||||
} while (0)
|
||||
|
||||
/** Generic hash function in UnrealIRCd.
|
||||
* @param str The string to hash (NUL-terminated)
|
||||
* @param k The key to use for hashing (16 bytes, not NUL terminated)
|
||||
* @returns Hash result as a 64 bit unsigned integer.
|
||||
* @notes The key (k) should be random and must stay the same for
|
||||
* as long as you use the function for your specific hash table.
|
||||
* Simply use the following on boot: siphash_generate_key(k);
|
||||
*/
|
||||
unsigned int hash_channel_name(char *name)
|
||||
uint64_t siphash(const char *in, const char *k)
|
||||
{
|
||||
unsigned char *hname = (unsigned char *)name;
|
||||
unsigned int hash = 0;
|
||||
int hash2 = 0;
|
||||
char lower;
|
||||
int i = 30;
|
||||
uint64_t hash;
|
||||
char *out = (char*) &hash;
|
||||
size_t inlen = strlen(in);
|
||||
uint64_t v0 = 0x736f6d6570736575ULL;
|
||||
uint64_t v1 = 0x646f72616e646f6dULL;
|
||||
uint64_t v2 = 0x6c7967656e657261ULL;
|
||||
uint64_t v3 = 0x7465646279746573ULL;
|
||||
uint64_t k0 = U8TO64_LE(k);
|
||||
uint64_t k1 = U8TO64_LE(k + 8);
|
||||
uint64_t m;
|
||||
const char *end = in + inlen - (inlen % sizeof(uint64_t));
|
||||
const int left = inlen & 7;
|
||||
uint64_t b = ((uint64_t)inlen) << 56;
|
||||
v3 ^= k1;
|
||||
v2 ^= k0;
|
||||
v1 ^= k1;
|
||||
v0 ^= k0;
|
||||
|
||||
while (*hname && --i)
|
||||
{
|
||||
lower = tolower(*hname);
|
||||
hash = (hash << 1) + lower;
|
||||
hash2 = (hash2 >> 1) + lower;
|
||||
hname++;
|
||||
}
|
||||
return ((hash & CH_MAX_INITIAL_MASK) << BITS_PER_COL) +
|
||||
(hash2 & BITS_PER_COL_MASK);
|
||||
for (; in != end; in += 8) {
|
||||
m = U8TO64_LE(in);
|
||||
v3 ^= m;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
|
||||
v0 ^= m;
|
||||
}
|
||||
|
||||
switch (left) {
|
||||
case 7: b |= ((uint64_t)in[6]) << 48; /* fallthrough */
|
||||
case 6: b |= ((uint64_t)in[5]) << 40; /* fallthrough */
|
||||
case 5: b |= ((uint64_t)in[4]) << 32; /* fallthrough */
|
||||
case 4: b |= ((uint64_t)in[3]) << 24; /* fallthrough */
|
||||
case 3: b |= ((uint64_t)in[2]) << 16; /* fallthrough */
|
||||
case 2: b |= ((uint64_t)in[1]) << 8; /* fallthrough */
|
||||
case 1: b |= ((uint64_t)in[0]); break;
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
v3 ^= b;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
|
||||
v0 ^= b;
|
||||
v2 ^= 0xff;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
|
||||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
U64TO8_LE(out, b);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
unsigned int hash_whowas_name(char *name)
|
||||
{
|
||||
unsigned char *nname = (unsigned char *)name;
|
||||
unsigned int hash = 0;
|
||||
int hash2 = 0;
|
||||
int ret;
|
||||
char lower;
|
||||
|
||||
while (*nname)
|
||||
{
|
||||
lower = tolower(*nname);
|
||||
hash = (hash << 1) + lower;
|
||||
hash2 = (hash2 >> 1) + lower;
|
||||
nname++;
|
||||
}
|
||||
ret = ((hash & WW_MAX_INITIAL_MASK) << BITS_PER_COL) +
|
||||
(hash2 & BITS_PER_COL_MASK);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* clear_*_hash_table
|
||||
*
|
||||
* Nullify the hashtable and its contents so it is completely empty.
|
||||
/** Generic hash function in UnrealIRCd - case insensitive.
|
||||
* This deals with IRC case-insensitive matches, which is
|
||||
* what you need for things like nicks and channels.
|
||||
* @param str The string to hash (NUL-terminated)
|
||||
* @param k The key to use for hashing (16 bytes, not NUL terminated)
|
||||
* @returns Hash result as a 64 bit unsigned integer.
|
||||
* @notes The key (k) should be random and must stay the same for
|
||||
* as long as you use the function for your specific hash table.
|
||||
* Simply use the following on boot: siphash_generate_key(k);
|
||||
*/
|
||||
void clear_client_hash_table(void)
|
||||
uint64_t siphash_nocase(const char *in, const char *k)
|
||||
{
|
||||
uint64_t hash;
|
||||
char *out = (char*) &hash;
|
||||
size_t inlen = strlen(in);
|
||||
uint64_t v0 = 0x736f6d6570736575ULL;
|
||||
uint64_t v1 = 0x646f72616e646f6dULL;
|
||||
uint64_t v2 = 0x6c7967656e657261ULL;
|
||||
uint64_t v3 = 0x7465646279746573ULL;
|
||||
uint64_t k0 = U8TO64_LE(k);
|
||||
uint64_t k1 = U8TO64_LE(k + 8);
|
||||
uint64_t m;
|
||||
const char *end = in + inlen - (inlen % sizeof(uint64_t));
|
||||
const int left = inlen & 7;
|
||||
uint64_t b = ((uint64_t)inlen) << 56;
|
||||
v3 ^= k1;
|
||||
v2 ^= k0;
|
||||
v1 ^= k1;
|
||||
v0 ^= k0;
|
||||
|
||||
for (; in != end; in += 8) {
|
||||
m = U8TO64_LE_NOCASE(in);
|
||||
v3 ^= m;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
|
||||
v0 ^= m;
|
||||
}
|
||||
|
||||
switch (left) {
|
||||
case 7: b |= ((uint64_t)tolower(in[6])) << 48; /* fallthrough */
|
||||
case 6: b |= ((uint64_t)tolower(in[5])) << 40; /* fallthrough */
|
||||
case 5: b |= ((uint64_t)tolower(in[4])) << 32; /* fallthrough */
|
||||
case 4: b |= ((uint64_t)tolower(in[3])) << 24; /* fallthrough */
|
||||
case 3: b |= ((uint64_t)tolower(in[2])) << 16; /* fallthrough */
|
||||
case 2: b |= ((uint64_t)tolower(in[1])) << 8; /* fallthrough */
|
||||
case 1: b |= ((uint64_t)tolower(in[0])); break;
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
v3 ^= b;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
|
||||
v0 ^= b;
|
||||
v2 ^= 0xff;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
|
||||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
U64TO8_LE(out, b);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void siphash_generate_key(char *k)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
k[i] = getrandom8();
|
||||
}
|
||||
|
||||
static struct list_head clientTable[NICK_HASH_TABLE_SIZE];
|
||||
static struct list_head idTable[NICK_HASH_TABLE_SIZE];
|
||||
static aHashEntry channelTable[CHAN_HASH_TABLE_SIZE];
|
||||
static aWatch *watchTable[WATCH_HASH_TABLE_SIZE];
|
||||
|
||||
static char siphashkey_nick[16];
|
||||
static char siphashkey_chan[16];
|
||||
static char siphashkey_watch[16];
|
||||
static char siphashkey_whowas[16];
|
||||
|
||||
extern char unreallogo[];
|
||||
|
||||
/** Initialize all hash tables */
|
||||
void init_hash(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < U_MAX; i++)
|
||||
siphash_generate_key(siphashkey_nick);
|
||||
siphash_generate_key(siphashkey_chan);
|
||||
siphash_generate_key(siphashkey_watch);
|
||||
siphash_generate_key(siphashkey_whowas);
|
||||
|
||||
for (i = 0; i < NICK_HASH_TABLE_SIZE; i++)
|
||||
INIT_LIST_HEAD(&clientTable[i]);
|
||||
|
||||
for (i = 0; i < U_MAX; i++)
|
||||
for (i = 0; i < NICK_HASH_TABLE_SIZE; i++)
|
||||
INIT_LIST_HEAD(&idTable[i]);
|
||||
|
||||
memset(channelTable, 0, sizeof(channelTable));
|
||||
memset(watchTable, 0, sizeof(watchTable));
|
||||
|
||||
if (strcmp(BASE_VERSION, &unreallogo[337]))
|
||||
loop.tainted = 1;
|
||||
}
|
||||
|
||||
void clear_channel_hash_table(void)
|
||||
uint64_t hash_nick_name(const char *name)
|
||||
{
|
||||
memset(channelTable, 0, sizeof(channelTable));
|
||||
return siphash_nocase(name, siphashkey_nick) % NICK_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
uint64_t hash_channel_name(const char *name)
|
||||
{
|
||||
return siphash_nocase(name, siphashkey_chan) % CHAN_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
uint64_t hash_watch_nick_name(const char *name)
|
||||
{
|
||||
return siphash_nocase(name, siphashkey_watch) % WATCH_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
uint64_t hash_whowas_name(const char *name)
|
||||
{
|
||||
return siphash_nocase(name, siphashkey_whowas) % WHOWAS_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_to_client_hash_table
|
||||
*/
|
||||
int add_to_client_hash_table(char *name, aClient *cptr)
|
||||
int add_to_client_hash_table(char *name, aClient *cptr)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
/*
|
||||
* If you see this, you have probably found your way to why changing the
|
||||
* base version made the IRCd become weird. This has been the case in all
|
||||
@@ -196,9 +315,9 @@ int add_to_client_hash_table(char *name, aClient *cptr)
|
||||
/*
|
||||
* add_to_client_hash_table
|
||||
*/
|
||||
int add_to_id_hash_table(char *name, aClient *cptr)
|
||||
int add_to_id_hash_table(char *name, aClient *cptr)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
hashv = hash_nick_name(name);
|
||||
list_add(&cptr->id_hash, &idTable[hashv]);
|
||||
return 0;
|
||||
@@ -207,9 +326,9 @@ int add_to_id_hash_table(char *name, aClient *cptr)
|
||||
/*
|
||||
* add_to_channel_hash_table
|
||||
*/
|
||||
int add_to_channel_hash_table(char *name, aChannel *chptr)
|
||||
int add_to_channel_hash_table(char *name, aChannel *chptr)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
|
||||
hashv = hash_channel_name(name);
|
||||
chptr->hnextch = (aChannel *)channelTable[hashv].list;
|
||||
@@ -221,7 +340,7 @@ int add_to_channel_hash_table(char *name, aChannel *chptr)
|
||||
/*
|
||||
* del_from_client_hash_table
|
||||
*/
|
||||
int del_from_client_hash_table(char *name, aClient *cptr)
|
||||
int del_from_client_hash_table(char *name, aClient *cptr)
|
||||
{
|
||||
if (!list_empty(&cptr->client_hash))
|
||||
list_del(&cptr->client_hash);
|
||||
@@ -231,7 +350,7 @@ int del_from_client_hash_table(char *name, aClient *cptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int del_from_id_hash_table(char *name, aClient *cptr)
|
||||
int del_from_id_hash_table(char *name, aClient *cptr)
|
||||
{
|
||||
if (!list_empty(&cptr->id_hash))
|
||||
list_del(&cptr->id_hash);
|
||||
@@ -244,10 +363,10 @@ int del_from_id_hash_table(char *name, aClient *cptr)
|
||||
/*
|
||||
* del_from_channel_hash_table
|
||||
*/
|
||||
int del_from_channel_hash_table(char *name, aChannel *chptr)
|
||||
int del_from_channel_hash_table(char *name, aChannel *chptr)
|
||||
{
|
||||
aChannel *tmp, *prev = NULL;
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
|
||||
hashv = hash_channel_name(name);
|
||||
for (tmp = (aChannel *)channelTable[hashv].list; tmp;
|
||||
@@ -279,7 +398,7 @@ int del_from_channel_hash_table(char *name, aChannel *chptr)
|
||||
aClient *hash_find_client(const char *name, aClient *cptr)
|
||||
{
|
||||
aClient *tmp;
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
|
||||
hashv = hash_nick_name(name);
|
||||
list_for_each_entry(tmp, &clientTable[hashv], client_hash)
|
||||
@@ -294,7 +413,7 @@ aClient *hash_find_client(const char *name, aClient *cptr)
|
||||
aClient *hash_find_id(const char *name, aClient *cptr)
|
||||
{
|
||||
aClient *tmp;
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
|
||||
hashv = hash_nick_name(name);
|
||||
list_for_each_entry(tmp, &idTable[hashv], id_hash)
|
||||
@@ -340,7 +459,7 @@ aClient *hash_find_nickserver(const char *str, aClient *cptr)
|
||||
aClient *hash_find_server(const char *server, aClient *cptr)
|
||||
{
|
||||
aClient *tmp;
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
|
||||
hashv = hash_nick_name(server);
|
||||
list_for_each_entry(tmp, &clientTable[hashv], client_hash)
|
||||
@@ -361,7 +480,7 @@ aClient *hash_find_server(const char *server, aClient *cptr)
|
||||
*/
|
||||
aChannel *hash_find_channel(char *name, aChannel *chptr)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
aChannel *tmp;
|
||||
aHashEntry *tmp3;
|
||||
|
||||
@@ -375,70 +494,43 @@ aChannel *hash_find_channel(char *name, aChannel *chptr)
|
||||
}
|
||||
return chptr;
|
||||
}
|
||||
aChannel *hash_get_chan_bucket(unsigned int hashv)
|
||||
|
||||
aChannel *hash_get_chan_bucket(uint64_t hashv)
|
||||
{
|
||||
if (hashv > CH_MAX)
|
||||
if (hashv > CHAN_HASH_TABLE_SIZE)
|
||||
return NULL;
|
||||
return (aChannel *)channelTable[hashv].list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rough figure of the datastructures for notify:
|
||||
*
|
||||
* NOTIFY HASH cptr1
|
||||
* | |- nick1
|
||||
* nick1-|- cptr1 |- nick2
|
||||
* | |- cptr2 cptr3
|
||||
* | |- cptr3 cptr2 |- nick1
|
||||
* | |- nick1
|
||||
* nick2-|- cptr2 |- nick2
|
||||
* |- cptr1
|
||||
*
|
||||
* add-to-notify-hash-table:
|
||||
* del-from-notify-hash-table:
|
||||
* hash-del-notify-list:
|
||||
* hash-check-notify:
|
||||
* hash-get-notify:
|
||||
*/
|
||||
|
||||
static aWatch *watchTable[WATCHHASHSIZE];
|
||||
|
||||
void count_watch_memory(int *count, u_long *memory)
|
||||
{
|
||||
int i = WATCHHASHSIZE;
|
||||
aWatch *anptr;
|
||||
|
||||
|
||||
while (i--) {
|
||||
int i = WATCH_HASH_TABLE_SIZE;
|
||||
aWatch *anptr;
|
||||
|
||||
while (i--)
|
||||
{
|
||||
anptr = watchTable[i];
|
||||
while (anptr) {
|
||||
while (anptr)
|
||||
{
|
||||
(*count)++;
|
||||
(*memory) += sizeof(aWatch)+strlen(anptr->nick);
|
||||
anptr = anptr->hnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
extern char unreallogo[];
|
||||
void clear_watch_hash_table(void)
|
||||
{
|
||||
memset((char *)watchTable, '\0', sizeof(watchTable));
|
||||
if (strcmp(BASE_VERSION, &unreallogo[337]))
|
||||
loop.tainted = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_to_watch_hash_table
|
||||
*/
|
||||
int add_to_watch_hash_table(char *nick, aClient *cptr, int awaynotify)
|
||||
int add_to_watch_hash_table(char *nick, aClient *cptr, int awaynotify)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
aWatch *anptr;
|
||||
Link *lp;
|
||||
|
||||
|
||||
/* Get the right bucket... */
|
||||
hashv = hash_nick_name(nick)%WATCHHASHSIZE;
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
/* Find the right nick (header) in the bucket, or NULL... */
|
||||
if ((anptr = (aWatch *)watchTable[hashv]))
|
||||
@@ -483,9 +575,9 @@ int add_to_watch_hash_table(char *nick, aClient *cptr, int awaynotify)
|
||||
/*
|
||||
* hash_check_watch
|
||||
*/
|
||||
int hash_check_watch(aClient *cptr, int reply)
|
||||
int hash_check_watch(aClient *cptr, int reply)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
aWatch *anptr;
|
||||
Link *lp;
|
||||
int awaynotify = 0;
|
||||
@@ -495,7 +587,7 @@ int hash_check_watch(aClient *cptr, int reply)
|
||||
|
||||
|
||||
/* Get us the right bucket */
|
||||
hashv = hash_nick_name(cptr->name)%WATCHHASHSIZE;
|
||||
hashv = hash_watch_nick_name(cptr->name);
|
||||
|
||||
/* Find the right header in this bucket */
|
||||
if ((anptr = (aWatch *)watchTable[hashv]))
|
||||
@@ -548,16 +640,15 @@ int hash_check_watch(aClient *cptr, int reply)
|
||||
/*
|
||||
* hash_get_watch
|
||||
*/
|
||||
aWatch *hash_get_watch(char *name)
|
||||
aWatch *hash_get_watch(char *nick)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
aWatch *anptr;
|
||||
|
||||
|
||||
hashv = hash_nick_name(name)%WATCHHASHSIZE;
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
if ((anptr = (aWatch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, name))
|
||||
while (anptr && mycmp(anptr->nick, nick))
|
||||
anptr = anptr->hnext;
|
||||
|
||||
return anptr;
|
||||
@@ -566,15 +657,14 @@ aWatch *hash_get_watch(char *name)
|
||||
/*
|
||||
* del_from_watch_hash_table
|
||||
*/
|
||||
int del_from_watch_hash_table(char *nick, aClient *cptr)
|
||||
int del_from_watch_hash_table(char *nick, aClient *cptr)
|
||||
{
|
||||
unsigned int hashv;
|
||||
unsigned int hashv;
|
||||
aWatch *anptr, *nlast = NULL;
|
||||
Link *lp, *last = NULL;
|
||||
|
||||
|
||||
|
||||
/* Get the bucket for this nick... */
|
||||
hashv = hash_nick_name(nick)%WATCHHASHSIZE;
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
/* Find the right header, maintaining last-link pointer... */
|
||||
if ((anptr = (aWatch *)watchTable[hashv]))
|
||||
@@ -683,7 +773,7 @@ int hash_del_watch_list(aClient *cptr)
|
||||
if (!anptr->watch) {
|
||||
aWatch *np2, *nl;
|
||||
|
||||
hashv = hash_nick_name(anptr->nick)%WATCHHASHSIZE;
|
||||
hashv = hash_watch_nick_name(anptr->nick);
|
||||
|
||||
nl = NULL;
|
||||
np2 = watchTable[hashv];
|
||||
|
||||
+5
-5
@@ -925,6 +925,8 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
|
||||
timeofday = time(NULL);
|
||||
|
||||
init_random(); /* needs to be done very early!! */
|
||||
|
||||
memset(&botmotd, '\0', sizeof(aMotdFile));
|
||||
memset(&rules, '\0', sizeof(aMotdFile));
|
||||
memset(&opermotd, '\0', sizeof(aMotdFile));
|
||||
@@ -933,6 +935,9 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
memset(&svsmotd, '\0', sizeof(aMotdFile));
|
||||
memset(&me, 0, sizeof(me));
|
||||
me.local = MyMallocEx(sizeof(aLocalClient));
|
||||
bzero(&loop, sizeof(loop));
|
||||
|
||||
init_hash();
|
||||
|
||||
SetupEvents();
|
||||
|
||||
@@ -993,7 +998,6 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
tkl_init();
|
||||
umode_init();
|
||||
extcmode_init();
|
||||
init_random(); /* needs to be done very early!! */
|
||||
clear_scache_hash_table();
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
/* Make it so we can dump core */
|
||||
@@ -1236,10 +1240,6 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
fprintf(stderr, "This server can handle %d concurrent sockets (%d clients + %d reserve)\n\n",
|
||||
maxclients+CLIENTS_RESERVE, maxclients, CLIENTS_RESERVE);
|
||||
#endif
|
||||
clear_client_hash_table();
|
||||
clear_channel_hash_table();
|
||||
clear_watch_hash_table();
|
||||
bzero(&loop, sizeof(loop));
|
||||
init_CommandHash();
|
||||
initwhowas();
|
||||
initstats();
|
||||
|
||||
@@ -46,7 +46,7 @@ Cmode_t EXTMODE_HISTORY = 0L;
|
||||
*/
|
||||
#define HISTORY_SPREAD 16
|
||||
#define HISTORY_MAX_OFF_SECS 128
|
||||
#define HISTORY_CLEAN_PER_LOOP (CH_MAX/HISTORY_SPREAD)
|
||||
#define HISTORY_CLEAN_PER_LOOP (CHAN_HASH_TABLE_SIZE/HISTORY_SPREAD)
|
||||
#define HISTORY_TIMER_EVERY (HISTORY_MAX_OFF_SECS/HISTORY_SPREAD)
|
||||
|
||||
/* Forward declarations */
|
||||
@@ -538,7 +538,7 @@ EVENT(history_clean)
|
||||
}
|
||||
}
|
||||
hashnum++;
|
||||
if (hashnum >= CH_MAX)
|
||||
if (hashnum >= CHAN_HASH_TABLE_SIZE)
|
||||
hashnum = 0;
|
||||
} while(loopcnt++ < HISTORY_CLEAN_PER_LOOP);
|
||||
}
|
||||
|
||||
@@ -294,8 +294,8 @@ void _send_list(aClient *cptr)
|
||||
* and record that number as the number to start next time send_list
|
||||
* is called for this user. So, this function will almost always send
|
||||
* back more lines than specified by numsend (though not by much,
|
||||
* assuming CH_MAX is was well picked). So be conservative in your choice
|
||||
* of numsend. -Rak
|
||||
* assuming the hashing algorithm works well). Be conservative in your
|
||||
* choice of numsend. -Rak
|
||||
*/
|
||||
|
||||
/* Begin of /list? then send official channels. */
|
||||
@@ -315,7 +315,7 @@ void _send_list(aClient *cptr)
|
||||
}
|
||||
}
|
||||
|
||||
for (hashnum = lopt->starthash; hashnum < CH_MAX; hashnum++)
|
||||
for (hashnum = lopt->starthash; hashnum < CHAN_HASH_TABLE_SIZE; hashnum++)
|
||||
{
|
||||
if (numsend > 0)
|
||||
for (chptr = hash_get_chan_bucket(hashnum);
|
||||
@@ -394,7 +394,7 @@ void _send_list(aClient *cptr)
|
||||
}
|
||||
|
||||
/* All done */
|
||||
if (hashnum == CH_MAX)
|
||||
if (hashnum == CHAN_HASH_TABLE_SIZE)
|
||||
{
|
||||
sendnumeric(cptr, RPL_LISTEND);
|
||||
free_str_list(cptr->user->lopt->yeslist);
|
||||
|
||||
@@ -870,10 +870,11 @@ int stats_mem(aClient *sptr, char *para)
|
||||
|
||||
sendnumericfmt(sptr, RPL_STATSDEBUG,
|
||||
"Hash: client %d(%ld) chan %d(%ld) watch %d(%ld)",
|
||||
U_MAX,
|
||||
(long)(sizeof(aHashEntry) * U_MAX), CH_MAX,
|
||||
(long)(sizeof(aHashEntry) * CH_MAX), WATCHHASHSIZE,
|
||||
(long)(sizeof(aWatch *) * WATCHHASHSIZE));
|
||||
NICK_HASH_TABLE_SIZE,
|
||||
(long)(sizeof(aHashEntry) * NICK_HASH_TABLE_SIZE),
|
||||
CHAN_HASH_TABLE_SIZE,
|
||||
(long)(sizeof(aHashEntry) * CHAN_HASH_TABLE_SIZE), WATCH_HASH_TABLE_SIZE,
|
||||
(long)(sizeof(aWatch *) * WATCH_HASH_TABLE_SIZE));
|
||||
|
||||
for (link = freelink; link; link = link->next)
|
||||
fl++;
|
||||
@@ -886,9 +887,9 @@ int stats_mem(aClient *sptr, char *para)
|
||||
|
||||
tot = totww + totch + totcl + com + cl * sizeof(aClass) + db + rm;
|
||||
tot += fl * sizeof(Link);
|
||||
tot += sizeof(aHashEntry) * U_MAX;
|
||||
tot += sizeof(aHashEntry) * CH_MAX;
|
||||
tot += sizeof(aWatch *) * WATCHHASHSIZE;
|
||||
tot += sizeof(aHashEntry) * NICK_HASH_TABLE_SIZE;
|
||||
tot += sizeof(aHashEntry) * CHAN_HASH_TABLE_SIZE;
|
||||
tot += sizeof(aWatch *) * WATCH_HASH_TABLE_SIZE;
|
||||
|
||||
sendnumericfmt(sptr, RPL_STATSDEBUG, "Total: ww %ld ch %ld cl %ld co %ld db %ld",
|
||||
totww, totch, totcl, com, db);
|
||||
|
||||
@@ -53,9 +53,8 @@ MOD_UNLOAD(m_whowas)
|
||||
}
|
||||
|
||||
/* externally defined functions */
|
||||
extern unsigned int hash_whowas_name(char *);
|
||||
extern MODVAR aWhowas WHOWAS[NICKNAMEHISTORYLENGTH];
|
||||
extern MODVAR aWhowas *WHOWASHASH[WW_MAX];
|
||||
extern aWhowas MODVAR WHOWAS[NICKNAMEHISTORYLENGTH];
|
||||
extern aWhowas MODVAR *WHOWASHASH[WHOWAS_HASH_TABLE_SIZE];
|
||||
|
||||
/*
|
||||
** m_whowas
|
||||
|
||||
+6
-6
@@ -19,8 +19,9 @@
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
/* externally defined functions */
|
||||
unsigned int hash_whowas_name(char *); /* defined in hash.c */
|
||||
// FIXME: move this to m_whowas,
|
||||
// Consider making add_history an efunc? Or via a hook?
|
||||
// Some users may not want to load m_whowas at all.
|
||||
|
||||
/* internally defined function */
|
||||
static void add_whowas_to_clist(aWhowas **, aWhowas *);
|
||||
@@ -29,9 +30,9 @@ static void add_whowas_to_list(aWhowas **, aWhowas *);
|
||||
static void del_whowas_from_list(aWhowas **, aWhowas *);
|
||||
|
||||
aWhowas MODVAR WHOWAS[NICKNAMEHISTORYLENGTH];
|
||||
aWhowas MODVAR *WHOWASHASH[WW_MAX];
|
||||
aWhowas MODVAR *WHOWASHASH[WHOWAS_HASH_TABLE_SIZE];
|
||||
|
||||
MODVAR int whowas_next = 0;
|
||||
MODVAR int whowas_next = 0;
|
||||
|
||||
void add_history(aClient *cptr, int online)
|
||||
{
|
||||
@@ -144,7 +145,7 @@ void initwhowas()
|
||||
bzero((char *)&WHOWAS[i], sizeof(aWhowas));
|
||||
WHOWAS[i].hashv = -1;
|
||||
}
|
||||
for (i = 0; i < WW_MAX; i++)
|
||||
for (i = 0; i < WHOWAS_HASH_TABLE_SIZE; i++)
|
||||
WHOWASHASH[i] = NULL;
|
||||
}
|
||||
|
||||
@@ -176,7 +177,6 @@ static void add_whowas_to_list(aWhowas ** bucket, aWhowas * whowas)
|
||||
|
||||
static void del_whowas_from_list(aWhowas ** bucket, aWhowas * whowas)
|
||||
{
|
||||
|
||||
if (whowas->prev)
|
||||
whowas->prev->next = whowas->next;
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user