init
This commit is contained in:
755
ircd/hash.c
Normal file
755
ircd/hash.c
Normal file
@@ -0,0 +1,755 @@
|
||||
/************************************************************************
|
||||
* IRC - Internet Relay Chat, ircd/hash.c
|
||||
* Copyright (C) 1991 Darren Reed
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)hash.c 2.10 7/3/93 (C) 1991 Darren Reed";
|
||||
#endif
|
||||
|
||||
#include "struct.h"
|
||||
#include "common.h"
|
||||
#include "sys.h"
|
||||
#include "hash.h"
|
||||
#include "h.h"
|
||||
|
||||
#ifdef DEBUGMODE
|
||||
static aHashEntry *clientTable = NULL;
|
||||
static aHashEntry *channelTable = NULL;
|
||||
static int clhits, clmiss;
|
||||
static int chhits, chmiss;
|
||||
int HASHSIZE = 2003;
|
||||
int CHANNELHASHSIZE = 607;
|
||||
#else
|
||||
static aHashEntry clientTable[HASHSIZE];
|
||||
static aHashEntry channelTable[CHANNELHASHSIZE];
|
||||
#endif
|
||||
|
||||
static int hash_mult[] = { 173, 179, 181, 191, 193, 197,
|
||||
199, 211, 223, 227, 229, 233,
|
||||
239, 241, 251, 257, 263, 269,
|
||||
271, 277, 281, 293, 307, 311,
|
||||
401, 409, 419, 421, 431, 433,
|
||||
439, 443, 449, 457, 461, 463
|
||||
};
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* hash_nick_name
|
||||
*
|
||||
* this function must be *quick*. Thus there should be no multiplication
|
||||
* or division or modulus in the inner loop. subtraction and other bit
|
||||
* operations allowed.
|
||||
*/
|
||||
int hash_nick_name(nname)
|
||||
char *nname;
|
||||
{
|
||||
Reg1 u_char *name = (u_char *)nname;
|
||||
Reg2 u_char ch;
|
||||
Reg4 int hash = 1, *tab;
|
||||
|
||||
for (tab = hash_mult; (ch = *name); name++, tab++)
|
||||
hash += tolower(ch) + *tab + hash;
|
||||
if (hash < 0)
|
||||
hash = -hash;
|
||||
hash %= HASHSIZE;
|
||||
return (hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
int hash_channel_name(hname)
|
||||
char *hname;
|
||||
{
|
||||
Reg1 u_char *name = (u_char *)hname;
|
||||
Reg2 u_char ch;
|
||||
Reg3 int i = 30;
|
||||
Reg4 int hash = 5, *tab;
|
||||
|
||||
for (tab = hash_mult; (ch = *name) && --i; name++, tab++)
|
||||
hash += tolower(ch) + *tab + hash + i + i;
|
||||
if (hash < 0)
|
||||
hash = -hash;
|
||||
hash %= CHANNELHASHSIZE;
|
||||
return (hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* clear_*_hash_table
|
||||
*
|
||||
* Nullify the hashtable and its contents so it is completely empty.
|
||||
*/
|
||||
void clear_client_hash_table()
|
||||
{
|
||||
#ifdef DEBUGMODE
|
||||
clhits = 0;
|
||||
clmiss = 0;
|
||||
if (!clientTable)
|
||||
clientTable = (aHashEntry *)MyMalloc(HASHSIZE *
|
||||
sizeof(aHashEntry));
|
||||
#endif
|
||||
|
||||
bzero((char *)clientTable, sizeof(aHashEntry) * HASHSIZE);
|
||||
}
|
||||
|
||||
void clear_channel_hash_table()
|
||||
{
|
||||
#ifdef DEBUGMODE
|
||||
chmiss = 0;
|
||||
chhits = 0;
|
||||
if (!channelTable)
|
||||
channelTable = (aHashEntry *)MyMalloc(CHANNELHASHSIZE *
|
||||
sizeof(aHashEntry));
|
||||
#endif
|
||||
bzero((char *)channelTable, sizeof(aHashEntry) * CHANNELHASHSIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* add_to_client_hash_table
|
||||
*/
|
||||
int add_to_client_hash_table(name, cptr)
|
||||
char *name;
|
||||
aClient *cptr;
|
||||
{
|
||||
Reg1 int hashv;
|
||||
|
||||
hashv = hash_nick_name(name);
|
||||
cptr->hnext = (aClient *)clientTable[hashv].list;
|
||||
clientTable[hashv].list = (void *)cptr;
|
||||
clientTable[hashv].links++;
|
||||
clientTable[hashv].hits++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_to_channel_hash_table
|
||||
*/
|
||||
int add_to_channel_hash_table(name, chptr)
|
||||
char *name;
|
||||
aChannel *chptr;
|
||||
{
|
||||
Reg1 int hashv;
|
||||
|
||||
hashv = hash_channel_name(name);
|
||||
chptr->hnextch = (aChannel *)channelTable[hashv].list;
|
||||
channelTable[hashv].list = (void *)chptr;
|
||||
channelTable[hashv].links++;
|
||||
channelTable[hashv].hits++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* del_from_client_hash_table
|
||||
*/
|
||||
int del_from_client_hash_table(name, cptr)
|
||||
char *name;
|
||||
aClient *cptr;
|
||||
{
|
||||
Reg1 aClient *tmp, *prev = NULL;
|
||||
Reg2 int hashv;
|
||||
|
||||
hashv = hash_nick_name(name);
|
||||
for (tmp = (aClient *)clientTable[hashv].list; tmp; tmp = tmp->hnext)
|
||||
{
|
||||
if (tmp == cptr)
|
||||
{
|
||||
if (prev)
|
||||
prev->hnext = tmp->hnext;
|
||||
else
|
||||
clientTable[hashv].list = (void *)tmp->hnext;
|
||||
tmp->hnext = NULL;
|
||||
if (clientTable[hashv].links > 0)
|
||||
{
|
||||
clientTable[hashv].links--;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
/*
|
||||
* Should never actually return from here and
|
||||
* if we do it is an error/inconsistency in the
|
||||
* hash table.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
prev = tmp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* del_from_channel_hash_table
|
||||
*/
|
||||
int del_from_channel_hash_table(name, chptr)
|
||||
char *name;
|
||||
aChannel *chptr;
|
||||
{
|
||||
Reg1 aChannel *tmp, *prev = NULL;
|
||||
Reg2 int hashv;
|
||||
|
||||
hashv = hash_channel_name(name);
|
||||
for (tmp = (aChannel *)channelTable[hashv].list; tmp;
|
||||
tmp = tmp->hnextch)
|
||||
{
|
||||
if (tmp == chptr)
|
||||
{
|
||||
if (prev)
|
||||
prev->hnextch = tmp->hnextch;
|
||||
else
|
||||
channelTable[hashv].list=(void *)tmp->hnextch;
|
||||
tmp->hnextch = NULL;
|
||||
if (channelTable[hashv].links > 0)
|
||||
{
|
||||
channelTable[hashv].links--;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
prev = tmp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hash_find_client
|
||||
*/
|
||||
aClient *hash_find_client(name, cptr)
|
||||
char *name;
|
||||
aClient *cptr;
|
||||
{
|
||||
Reg1 aClient *tmp;
|
||||
Reg2 aClient *prv = NULL;
|
||||
Reg3 aHashEntry *tmp3;
|
||||
int hashv;
|
||||
#ifdef TESTNET
|
||||
Reg4 aClient *tmp_fnd = NULL, *prv_fnd = NULL;
|
||||
#endif
|
||||
|
||||
hashv = hash_nick_name(name);
|
||||
tmp3 = &clientTable[hashv];
|
||||
|
||||
/*
|
||||
* Got the bucket, now search the chain.
|
||||
*/
|
||||
for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
|
||||
{
|
||||
if (IsPing(tmp))
|
||||
continue;
|
||||
#ifdef TESTNET
|
||||
if (mycmp(name, tmp->name) == 0)
|
||||
{
|
||||
if (tmp_fnd)
|
||||
sendto_ops("*** DEBUG ERROR *** : Found %s TWICE !",
|
||||
tmp->name);
|
||||
else
|
||||
{
|
||||
tmp_fnd=tmp;
|
||||
prv_fnd=prv;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (mycmp(name, tmp->name) == 0)
|
||||
goto c_move_to_top;
|
||||
#endif
|
||||
}
|
||||
#ifdef TESTNET
|
||||
if (tmp_fnd)
|
||||
{
|
||||
tmp=tmp_fnd;
|
||||
prv=prv_fnd;
|
||||
goto c_move_to_top;
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUGMODE
|
||||
clmiss++;
|
||||
#endif
|
||||
return (cptr);
|
||||
c_move_to_top:
|
||||
#ifdef DEBUGMODE
|
||||
clhits++;
|
||||
#endif
|
||||
/*
|
||||
* If the member of the hashtable we found isnt at the top of its
|
||||
* chain, put it there. This builds a most-frequently used order into
|
||||
* the chains of the hash table, giving speadier lookups on those nicks
|
||||
* which are being used currently. This same block of code is also
|
||||
* used for channels and servers for the same performance reasons.
|
||||
*/
|
||||
if (prv)
|
||||
{
|
||||
aClient *tmp2;
|
||||
|
||||
tmp2 = (aClient *)tmp3->list;
|
||||
tmp3->list = (void *)tmp;
|
||||
prv->hnext = tmp->hnext;
|
||||
tmp->hnext = tmp2;
|
||||
}
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_find_nickserver
|
||||
*/
|
||||
aClient *hash_find_nickserver(name, cptr)
|
||||
char *name;
|
||||
aClient *cptr;
|
||||
{
|
||||
Reg1 aClient *tmp;
|
||||
Reg2 aClient *prv = NULL;
|
||||
Reg3 aHashEntry *tmp3;
|
||||
int hashv;
|
||||
char *serv;
|
||||
|
||||
serv = index(name, '@');
|
||||
*serv++ = '\0';
|
||||
hashv = hash_nick_name(name);
|
||||
tmp3 = &clientTable[hashv];
|
||||
|
||||
/*
|
||||
* Got the bucket, now search the chain.
|
||||
*/
|
||||
for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
|
||||
if (mycmp(name, tmp->name) == 0 && tmp->user &&
|
||||
mycmp(serv, tmp->user->server->name) == 0)
|
||||
goto c_move_to_top;
|
||||
|
||||
#ifdef DEBUGMODE
|
||||
clmiss++;
|
||||
#endif
|
||||
*--serv = '\0';
|
||||
return (cptr);
|
||||
|
||||
c_move_to_top:
|
||||
#ifdef DEBUGMODE
|
||||
clhits++;
|
||||
#endif
|
||||
/*
|
||||
* If the member of the hashtable we found isnt at the top of its
|
||||
* chain, put it there. This builds a most-frequently used order into
|
||||
* the chains of the hash table, giving speadier lookups on those nicks
|
||||
* which are being used currently. This same block of code is also
|
||||
* used for channels and servers for the same performance reasons.
|
||||
*/
|
||||
if (prv)
|
||||
{
|
||||
aClient *tmp2;
|
||||
|
||||
tmp2 = (aClient *)tmp3->list;
|
||||
tmp3->list = (void *)tmp;
|
||||
prv->hnext = tmp->hnext;
|
||||
tmp->hnext = tmp2;
|
||||
}
|
||||
*--serv = '\0';
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_find_server
|
||||
*/
|
||||
aClient *hash_find_server(server, cptr)
|
||||
char *server;
|
||||
aClient *cptr;
|
||||
{
|
||||
Reg1 aClient *tmp, *prv = NULL;
|
||||
Reg2 char *t;
|
||||
Reg3 char ch;
|
||||
aHashEntry *tmp3;
|
||||
|
||||
int hashv;
|
||||
|
||||
hashv = hash_nick_name(server);
|
||||
tmp3 = &clientTable[hashv];
|
||||
|
||||
for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
|
||||
{
|
||||
if (!IsServer(tmp) && !IsMe(tmp))
|
||||
continue;
|
||||
if (mycmp(server, tmp->name) == 0)
|
||||
goto s_move_to_top;
|
||||
}
|
||||
t = ((char *)server + strlen(server));
|
||||
/*
|
||||
* Whats happening in this next loop ? Well, it takes a name like
|
||||
* foo.bar.edu and proceeds to search for *.edu and then *.bar.edu.
|
||||
* This is for checking full server names against masks although
|
||||
* it isnt often done this way in lieu of using matches().
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
t--;
|
||||
for (; t > server; t--)
|
||||
if (*(t+1) == '.')
|
||||
break;
|
||||
if (t <= server || *t == '*')
|
||||
break;
|
||||
ch = *t;
|
||||
*t = '*';
|
||||
/*
|
||||
* Dont need to check IsServer() here since nicknames cant
|
||||
*have *'s in them anyway.
|
||||
*/
|
||||
if (((tmp = hash_find_client(t, cptr))) != cptr)
|
||||
{
|
||||
*t = ch;
|
||||
return (tmp);
|
||||
}
|
||||
*t = ch;
|
||||
}
|
||||
#ifdef DEBUGMODE
|
||||
clmiss++;
|
||||
#endif
|
||||
return (cptr);
|
||||
s_move_to_top:
|
||||
#ifdef DEBUGMODE
|
||||
clhits++;
|
||||
#endif
|
||||
if (prv)
|
||||
{
|
||||
aClient *tmp2;
|
||||
|
||||
tmp2 = (aClient *)tmp3->list;
|
||||
tmp3->list = (void *)tmp;
|
||||
prv->hnext = tmp->hnext;
|
||||
tmp->hnext = tmp2;
|
||||
}
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_find_channel
|
||||
*/
|
||||
aChannel *hash_find_channel(name, chptr)
|
||||
char *name;
|
||||
aChannel *chptr;
|
||||
{
|
||||
int hashv;
|
||||
Reg1 aChannel *tmp, *prv = NULL;
|
||||
aHashEntry *tmp3;
|
||||
|
||||
hashv = hash_channel_name(name);
|
||||
tmp3 = &channelTable[hashv];
|
||||
|
||||
for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch)
|
||||
if (mycmp(name, tmp->chname) == 0)
|
||||
goto c_move_to_top;
|
||||
#ifdef DEBUGMODE
|
||||
chmiss++;
|
||||
#endif
|
||||
return chptr;
|
||||
c_move_to_top:
|
||||
#ifdef DEBUGMODE
|
||||
chhits++;
|
||||
#endif
|
||||
if (prv)
|
||||
{
|
||||
register aChannel *tmp2;
|
||||
|
||||
tmp2 = (aChannel *)tmp3->list;
|
||||
tmp3->list = (void *)tmp;
|
||||
prv->hnextch = tmp->hnextch;
|
||||
tmp->hnextch = tmp2;
|
||||
}
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: this command is not supposed to be an offical part of the ircd
|
||||
* protocol. It is simply here to help debug and to monitor the
|
||||
* performance of the hash functions and table, enabling a better
|
||||
* algorithm to be sought if this one becomes troublesome.
|
||||
* -avalon
|
||||
*/
|
||||
|
||||
int m_hash(cptr, sptr, parc, parv)
|
||||
aClient *cptr, *sptr;
|
||||
int parc;
|
||||
char *parv[];
|
||||
{
|
||||
#ifdef DEBUGMODE
|
||||
register int l, i;
|
||||
register aHashEntry *tab;
|
||||
int deepest = 0, deeplink = 0, showlist = 0, tothits = 0;
|
||||
int mosthit = 0, mosthits = 0, used = 0, used_now = 0, totlink = 0;
|
||||
int link_pop[10], size = HASHSIZE;
|
||||
char ch;
|
||||
aHashEntry *table;
|
||||
|
||||
if (parc > 1) {
|
||||
ch = *parv[1];
|
||||
if (islower(ch))
|
||||
table = clientTable;
|
||||
else {
|
||||
table = channelTable;
|
||||
size = CHANNELHASHSIZE;
|
||||
}
|
||||
if (ch == 'L' || ch == 'l')
|
||||
showlist = 1;
|
||||
} else {
|
||||
ch = '\0';
|
||||
table = clientTable;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
link_pop[i] = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
tab = &table[i];
|
||||
l = tab->links;
|
||||
if (showlist)
|
||||
sendto_one(sptr,
|
||||
"NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d",
|
||||
parv[0], i, tab->hits, l);
|
||||
if (l > 0) {
|
||||
if (l < 10)
|
||||
link_pop[l]++;
|
||||
else
|
||||
link_pop[9]++;
|
||||
used_now++;
|
||||
totlink += l;
|
||||
if (l > deepest) {
|
||||
deepest = l;
|
||||
deeplink = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
link_pop[0]++;
|
||||
l = tab->hits;
|
||||
if (l) {
|
||||
used++;
|
||||
tothits += l;
|
||||
if (l > mosthits) {
|
||||
mosthits = l;
|
||||
mosthit = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch((int)ch)
|
||||
{
|
||||
case 'V' : case 'v' :
|
||||
{
|
||||
register aClient *acptr;
|
||||
int bad = 0, listlength = 0;
|
||||
|
||||
for (acptr = client; acptr; acptr = acptr->next) {
|
||||
if (hash_find_client(acptr->name,acptr) != acptr) {
|
||||
if (ch == 'V')
|
||||
sendto_one(sptr, "NOTICE %s :Bad hash for %s",
|
||||
parv[0], acptr->name);
|
||||
bad++;
|
||||
}
|
||||
listlength++;
|
||||
}
|
||||
sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d",
|
||||
parv[0], listlength, bad);
|
||||
}
|
||||
case 'P' : case 'p' :
|
||||
for (i = 0; i < 10; i++)
|
||||
sendto_one(sptr,"NOTICE %s :Entires with %d links : %d",
|
||||
parv[0], i, link_pop[i]);
|
||||
return (0);
|
||||
case 'r' :
|
||||
{
|
||||
Reg1 aClient *acptr;
|
||||
|
||||
sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]);
|
||||
clear_client_hash_table();
|
||||
for (acptr = client; acptr; acptr = acptr->next)
|
||||
if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
|
||||
!IsPing(acptr))
|
||||
(void)add_to_client_hash_table(acptr->name, acptr);
|
||||
break;
|
||||
}
|
||||
case 'R' :
|
||||
{
|
||||
Reg1 aChannel *acptr;
|
||||
|
||||
sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]);
|
||||
clear_channel_hash_table();
|
||||
for (acptr = channel; acptr; acptr = acptr->nextch)
|
||||
(void)add_to_channel_hash_table(acptr->chname, acptr);
|
||||
break;
|
||||
}
|
||||
case 'H' :
|
||||
if (parc > 2)
|
||||
sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
|
||||
parv[0], parv[2],
|
||||
hash_channel_name(parv[2]));
|
||||
return (0);
|
||||
case 'h' :
|
||||
if (parc > 2)
|
||||
sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
|
||||
parv[0], parv[2],
|
||||
hash_nick_name(parv[2]));
|
||||
return (0);
|
||||
case 'n' :
|
||||
{
|
||||
aClient *tmp;
|
||||
int max;
|
||||
|
||||
if (parc <= 2)
|
||||
return (0);
|
||||
l = atoi(parv[2]) % HASHSIZE;
|
||||
if (parc > 3)
|
||||
max = atoi(parv[3]) % HASHSIZE;
|
||||
else
|
||||
max = l;
|
||||
for (;l <= max; l++)
|
||||
for (i = 0, tmp = (aClient *)clientTable[l].list; tmp;
|
||||
i++, tmp = tmp->hnext)
|
||||
{
|
||||
if (parv[1][2] == '1' && tmp != tmp->from)
|
||||
continue;
|
||||
sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
|
||||
parv[0], l, i, tmp->name);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
case 'N' :
|
||||
{
|
||||
aChannel *tmp;
|
||||
int max;
|
||||
|
||||
if (parc <= 2)
|
||||
return (0);
|
||||
l = atoi(parv[2]) % CHANNELHASHSIZE;
|
||||
if (parc > 3)
|
||||
max = atoi(parv[3]) % CHANNELHASHSIZE;
|
||||
else
|
||||
max = l;
|
||||
for (;l <= max; l++)
|
||||
for (i = 0, tmp = (aChannel *)channelTable[l].list; tmp;
|
||||
i++, tmp = tmp->hnextch)
|
||||
sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
|
||||
parv[0], l, i, tmp->chname);
|
||||
return (0);
|
||||
}
|
||||
case 'S' :
|
||||
#else
|
||||
if (parc>1&&!strcmp(parv[1],"sums")){
|
||||
#endif
|
||||
sendto_one(sptr, "NOTICE %s :SUSER SSERV", parv[0]);
|
||||
sendto_one(sptr, "NOTICE %s :SBSDC IRCDC", parv[0]);
|
||||
sendto_one(sptr, "NOTICE %s :CHANC SMISC", parv[0]);
|
||||
sendto_one(sptr, "NOTICE %s :HASHC VERSH", parv[0]);
|
||||
sendto_one(sptr, "NOTICE %s :MAKEF HOSTID", parv[0]);
|
||||
#ifndef DEBUGMODE
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
#ifdef DEBUGMODE
|
||||
case 'z' :
|
||||
{
|
||||
Reg1 aClient *acptr;
|
||||
|
||||
if (parc <= 2)
|
||||
return 0;
|
||||
l = atoi(parv[2]);
|
||||
if (l < 256)
|
||||
return 0;
|
||||
(void)free((char *)clientTable);
|
||||
clientTable = (aHashEntry *)malloc(sizeof(aHashEntry) * l);
|
||||
HASHSIZE = l;
|
||||
clear_client_hash_table();
|
||||
for (acptr = client; acptr; acptr = acptr->next)
|
||||
if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
|
||||
!IsPing(acptr))
|
||||
{
|
||||
acptr->hnext = NULL;
|
||||
(void)add_to_client_hash_table(acptr->name, acptr);
|
||||
}
|
||||
sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l);
|
||||
break;
|
||||
}
|
||||
case 'Z' :
|
||||
{
|
||||
Reg1 aChannel *acptr;
|
||||
|
||||
if (parc <= 2)
|
||||
return 0;
|
||||
l = atoi(parv[2]);
|
||||
if (l < 256)
|
||||
return 0;
|
||||
(void)free((char *)channelTable);
|
||||
channelTable = (aHashEntry *)malloc(sizeof(aHashEntry) * l);
|
||||
CHANNELHASHSIZE = l;
|
||||
clear_channel_hash_table();
|
||||
for (acptr = channel; acptr; acptr = acptr->nextch)
|
||||
{
|
||||
acptr->hnextch = NULL;
|
||||
(void)add_to_channel_hash_table(acptr->chname, acptr);
|
||||
}
|
||||
sendto_one(sptr, "NOTICE %s :CHANNELHASHSIZE now %d",
|
||||
parv[0], l);
|
||||
break;
|
||||
}
|
||||
default :
|
||||
break;
|
||||
}
|
||||
sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d",
|
||||
parv[0], totlink, used_now, size);
|
||||
if (!used_now)
|
||||
used_now = 1;
|
||||
sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %Full: %f",
|
||||
parv[0], (float)((1.0 * totlink) / (1.0 * used_now)),
|
||||
(float)((1.0 * used_now) / (1.0 * size)));
|
||||
sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d",
|
||||
parv[0], deeplink, deepest);
|
||||
if (!used)
|
||||
used = 1;
|
||||
sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f",
|
||||
parv[0], tothits, size-used,
|
||||
(float)((1.0 * tothits) / (1.0 * used)));
|
||||
sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d",
|
||||
parv[0], mosthit, mosthits);
|
||||
sendto_one(sptr,"NOTICE %s :Client hits %d miss %d",
|
||||
parv[0], clhits, clmiss);
|
||||
sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d",
|
||||
parv[0], chhits, chmiss);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user