X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Flist.c;h=f6a11328ffedbc84b6f3f4a65309aa77b6bd9c15;hb=ccb26232551f5cf6abbddd0cfe175bc32ddf20f1;hp=2e4a23bcafa79a34be70ffea403a4076ede35ab6;hpb=b6521be94946bdb488f23c71754ea34a29757b8f;p=ircu2.10.12-pk.git diff --git a/ircd/list.c b/ircd/list.c index 2e4a23b..f6a1132 100644 --- a/ircd/list.c +++ b/ircd/list.c @@ -17,517 +17,535 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/** @file + * @brief Singly and doubly linked list manipulation implementation. + * @version $Id$ + */ +#include "config.h" -#include "sys.h" -#include "h.h" -#include "struct.h" +#include "list.h" +#include "client.h" +#include "ircd.h" +#include "ircd_alloc.h" +#include "ircd_events.h" +#include "ircd_log.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "listener.h" +#include "match.h" #include "numeric.h" -#include "send.h" +#include "res.h" +#include "s_auth.h" +#include "s_bsd.h" #include "s_conf.h" -#include "class.h" -#include "match.h" -#include "ircd.h" -#include "s_serv.h" -#include "support.h" +#include "s_debug.h" #include "s_misc.h" -#include "s_bsd.h" -#include "whowas.h" -#include "res.h" -#include "common.h" -#include "list.h" #include "s_user.h" -#include "opercmds.h" +#include "send.h" +#include "struct.h" +#include "whowas.h" -RCSTAG_CC("$Id$"); +/* #include -- Now using assert in ircd_log.h */ +#include /* offsetof */ +#include /* close */ +#include -#ifdef DEBUGMODE +/** Stores linked list statistics for various types of lists. */ static struct liststats { - int inuse; -} cloc, crem, users, servs, links, classs, aconfs; -#endif + size_t alloc; /**< Number of structures ever allocated. */ + size_t inuse; /**< Number of structures currently in use. */ + size_t mem; /**< Memory used by in-use structures. */ +} clients, connections, servs, links; + +/** Linked list of currently unused Client structures. */ +static struct Client* clientFreeList; -void outofmemory(); +/** Linked list of currently unused Connection structures. */ +static struct Connection* connectionFreeList; -#ifdef DEBUGMODE -void initlists(void) +/** Linked list of currently unused SLink structures. */ +static struct SLink* slinkFreeList; + +/** Initialize the list manipulation support system. + * Pre-allocate MAXCONNECTIONS Client and Connection structures. + */ +void init_list(void) { - memset(&cloc, 0, sizeof(cloc)); - memset(&crem, 0, sizeof(crem)); - memset(&users, 0, sizeof(users)); - memset(&servs, 0, sizeof(servs)); - memset(&links, 0, sizeof(links)); - memset(&classs, 0, sizeof(classs)); - memset(&aconfs, 0, sizeof(aconfs)); + struct Client* cptr; + struct Connection* con; + int i; + /* + * pre-allocate MAXCONNECTIONS clients and connections + */ + for (i = 0; i < MAXCONNECTIONS; ++i) { + cptr = (struct Client*) MyMalloc(sizeof(struct Client)); + cli_next(cptr) = clientFreeList; + clientFreeList = cptr; + clients.alloc++; + + con = (struct Connection*) MyMalloc(sizeof(struct Connection)); + con_next(con) = connectionFreeList; + connectionFreeList = con; + connections.alloc++; + } } -#endif -void outofmemory(void) +/** Allocate a new Client structure. + * If #clientFreeList != NULL, use the head of that list. + * Otherwise, allocate a new structure. + * @return Newly allocated Client. + */ +static struct Client* alloc_client(void) { - Debug((DEBUG_FATAL, "Out of memory: restarting server...")); - restart("Out of Memory"); + struct Client* cptr = clientFreeList; + + if (!cptr) { + cptr = (struct Client*) MyMalloc(sizeof(struct Client)); + clients.alloc++; + } else + clientFreeList = cli_next(cptr); + + clients.inuse++; + + memset(cptr, 0, sizeof(struct Client)); + + return cptr; } -/* - * Create a new aClient structure and set it to initial state. - * - * from == NULL, create local client (a client connected to a socket). - * - * from != NULL, create remote client (behind a socket associated with - * the client defined by 'from'). - * ('from' is a local client!!). +/** Release a Client structure by prepending it to #clientFreeList. + * @param[in] cptr Client that is no longer being used. */ -aClient *make_client(aClient *from, int status) +static void dealloc_client(struct Client* cptr) { - Reg1 aClient *cptr = NULL; - Reg2 size_t size = CLIENT_REMOTE_SIZE; + assert(cli_verify(cptr)); + assert(0 == cli_connect(cptr)); - /* - * Check freelists first to see if we can grab a client without - * having to call malloc. - */ - if (!from) - size = CLIENT_LOCAL_SIZE; - - if (!(cptr = (aClient *)RunMalloc(size))) - outofmemory(); - memset(cptr, 0, size); /* All variables are 0 by default */ - -#ifdef DEBUGMODE - if (size == CLIENT_LOCAL_SIZE) - cloc.inuse++; - else - crem.inuse++; -#endif + --clients.inuse; - /* Note: structure is zero (memset) */ - cptr->from = from ? from : cptr; /* 'from' of local client is self! */ - cptr->fd = -1; - cptr->status = status; - strcpy(cptr->username, "unknown"); - if (size == CLIENT_LOCAL_SIZE) - { - cptr->since = cptr->lasttime = cptr->firsttime = now; - cptr->lastnick = TStime(); - cptr->nextnick = now - NICK_DELAY; - cptr->nexttarget = now - (TARGET_DELAY * (STARTTARGETS - 1)); - cptr->authfd = -1; - } - return (cptr); + cli_next(cptr) = clientFreeList; + clientFreeList = cptr; + + cli_magic(cptr) = 0; } -void free_client(aClient *cptr) +/** Allocate a new Connection structure. + * If #connectionFreeList != NULL, use the head of that list. + * Otherwise, allocate a new structure. + * @return Newly allocated Connection. + */ +static struct Connection* alloc_connection(void) { - RunFree(cptr); + struct Connection* con = connectionFreeList; + + if (!con) { + con = (struct Connection*) MyMalloc(sizeof(struct Connection)); + connections.alloc++; + } else + connectionFreeList = con_next(con); + + connections.inuse++; + + memset(con, 0, sizeof(struct Connection)); + timer_init(&(con_proc(con))); + + return con; } -/* - * 'make_user' add's an User information block to a client - * if it was not previously allocated. +/** Release a Connection and all memory associated with it. + * The connection's DNS reply field is freed, its file descriptor is + * closed, its msgq and sendq are cleared, and its associated Listener + * is dereferenced. Then it is prepended to #connectionFreeList. + * @param[in] con Connection to free. */ -anUser *make_user(aClient *cptr) +static void dealloc_connection(struct Connection* con) { - Reg1 anUser *user; + assert(con_verify(con)); + assert(!t_active(&(con_proc(con)))); + assert(!t_onqueue(&(con_proc(con)))); - user = cptr->user; - if (!user) - { - if (!(user = (anUser *)RunMalloc(sizeof(anUser)))) - outofmemory(); - memset(user, 0, sizeof(anUser)); /* All variables are 0 by default */ -#ifdef DEBUGMODE - users.inuse++; -#endif - user->refcnt = 1; - *user->host = 0; - cptr->user = user; - } - return user; + Debug((DEBUG_LIST, "Deallocating connection %p", con)); + + if (-1 < con_fd(con)) + close(con_fd(con)); + MsgQClear(&(con_sendQ(con))); + client_drop_sendq(con); + DBufClear(&(con_recvQ(con))); + if (con_listener(con)) + release_listener(con_listener(con)); + + --connections.inuse; + + con_next(con) = connectionFreeList; + connectionFreeList = con; + + con_magic(con) = 0; } -aServer *make_server(aClient *cptr) +/** Allocate a new client and initialize it. + * If \a from == NULL, initialize the fields for a local client, + * including allocating a Connection for him; otherwise initialize the + * fields for a remote client.. + * @param[in] from Server connection that introduced the client (or + * NULL). + * @param[in] status Initial Client::cli_status value. + * @return Newly allocated and initialized Client. + */ +struct Client* make_client(struct Client *from, int status) { - Reg1 aServer *serv = cptr->serv; + struct Client* cptr = 0; - if (!serv) - { - if (!(serv = (aServer *)RunMalloc(sizeof(aServer)))) - outofmemory(); - memset(serv, 0, sizeof(aServer)); /* All variables are 0 by default */ -#ifdef DEBUGMODE - servs.inuse++; -#endif - cptr->serv = serv; - *serv->by = '\0'; - DupString(serv->last_error_msg, "<>"); /* String must be non-empty */ + assert(!from || cli_verify(from)); + + cptr = alloc_client(); + + assert(0 != cptr); + assert(!cli_magic(cptr)); + assert(0 == from || 0 != cli_connect(from)); + + if (!from) { /* local client, allocate a struct Connection */ + struct Connection *con = alloc_connection(); + + assert(0 != con); + assert(!con_magic(con)); + + con_magic(con) = CONNECTION_MAGIC; + con_fd(con) = -1; /* initialize struct Connection */ + con_freeflag(con) = 0; + con_nextnick(con) = CurrentTime - NICK_DELAY; + con_nexttarget(con) = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1)); + con_handler(con) = UNREGISTERED_HANDLER; + con_client(con) = cptr; + + cli_connect(cptr) = con; /* set the connection and other fields */ + cli_since(cptr) = cli_lasttime(cptr) = cli_firsttime(cptr) = CurrentTime; + cli_lastnick(cptr) = TStime(); + } else + cli_connect(cptr) = cli_connect(from); /* use 'from's connection */ + + assert(con_verify(cli_connect(cptr))); + + cli_magic(cptr) = CLIENT_MAGIC; + cli_status(cptr) = status; + cli_hnext(cptr) = cptr; + strcpy(cli_username(cptr), "unknown"); + + return cptr; +} + +/** Release a Connection. + * @param[in] con Connection to free. + */ +void free_connection(struct Connection* con) +{ + if (!con) + return; + + assert(con_verify(con)); + assert(0 == con_client(con)); + + dealloc_connection(con); /* deallocate the connection */ +} + +/** Release a Client. + * In addition to the cleanup done by dealloc_client(), this will free + * any pending auth request, free the connection for local clients, + * and delete the processing timer for the client. + * @param[in] cptr Client to free. + */ +void free_client(struct Client* cptr) +{ + if (!cptr) + return; + /* + * forget to remove the client from the hash table? + */ + assert(cli_verify(cptr)); + assert(cli_hnext(cptr) == cptr); + /* or from linked list? */ + assert(cli_next(cptr) == 0); + assert(cli_prev(cptr) == 0); + + Debug((DEBUG_LIST, "Freeing client %s [%p], connection %p", cli_name(cptr), + cptr, cli_connect(cptr))); + + if (cli_auth(cptr)) + destroy_auth_request(cli_auth(cptr)); + + /* Make sure we didn't magically get re-added to the list */ + assert(cli_next(cptr) == 0); + assert(cli_prev(cptr) == 0); + + if (cli_from(cptr) == cptr) { /* in other words, we're local */ + cli_from(cptr) = 0; + /* timer must be marked as not active */ + if (!cli_freeflag(cptr) && !t_active(&(cli_proc(cptr)))) + dealloc_connection(cli_connect(cptr)); /* connection not open anymore */ + else { + if (-1 < cli_fd(cptr) && cli_freeflag(cptr) & FREEFLAG_SOCKET) + socket_del(&(cli_socket(cptr))); /* queue a socket delete */ + if (cli_freeflag(cptr) & FREEFLAG_TIMER) + timer_del(&(cli_proc(cptr))); /* queue a timer delete */ + } } - return cptr->serv; + + cli_connect(cptr) = 0; + + dealloc_client(cptr); /* actually destroy the client */ } -/* - * free_user - * - * Decrease user reference count by one and realease block, if count reaches 0. +/** Allocate a new Server object for a client. + * If Client::cli_serv == NULL, allocate a Server structure for it and + * initialize it. + * @param[in] cptr %Client to make into a server. + * @return The value of cli_serv(\a cptr). */ -void free_user(anUser *user, aClient *cptr) +struct Server *make_server(struct Client *cptr) { - if (--user->refcnt == 0) + struct Server *serv = cli_serv(cptr); + + assert(cli_verify(cptr)); + + if (!serv) { - if (user->away) - RunFree(user->away); - /* - * sanity check - */ - if (user->joined || user->invited || user->channel) -#ifdef DEBUGMODE - dumpcore("%p user (%s!%s@%s) %p %p %p %d %d", - cptr, cptr ? cptr->name : "", - user->username, user->host, user, - user->invited, user->channel, user->joined, user->refcnt); -#else - sendto_ops("* %p user (%s!%s@%s) %p %p %p %d %d *", - cptr, cptr ? cptr->name : "", - user->username, user->host, user, - user->invited, user->channel, user->joined, user->refcnt); -#endif - RunFree(user); -#ifdef DEBUGMODE - users.inuse--; -#endif + serv = (struct Server*) MyMalloc(sizeof(struct Server)); + assert(0 != serv); + memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */ + servs.inuse++; + servs.alloc++; + cli_serv(cptr) = serv; + cli_serv(cptr)->lag = 60000; + *serv->by = '\0'; + DupString(serv->last_error_msg, "<>"); /* String must be non-empty */ } + return cli_serv(cptr); } -/* - * Taken the code from ExitOneClient() for this and placed it here. - * - avalon +/** Remove \a cptr from lists that it is a member of. + * Specifically, this delinks \a cptr from #GlobalClientList, updates + * the whowas history list, frees its Client::cli_user and + * Client::cli_serv fields, and finally calls free_client() on it. + * @param[in] cptr Client to remove from lists and free. */ -void remove_client_from_list(aClient *cptr) +void remove_client_from_list(struct Client *cptr) { - checklist(); - if (cptr->prev) - cptr->prev->next = cptr->next; - else + assert(cli_verify(cptr)); + assert(con_verify(cli_connect(cptr))); + assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr))); + assert(!cli_next(cptr) || cli_verify(cli_next(cptr))); + assert(!IsMe(cptr)); + + /* Only try remove cptr from the list if it IS in the list. + * cli_next(cptr) cannot be NULL here, as &me is always the end + * the list, and we never remove &me. -GW + */ + if(cli_next(cptr)) { - client = cptr->next; - client->prev = NULL; + if (cli_prev(cptr)) + cli_next(cli_prev(cptr)) = cli_next(cptr); + else { + GlobalClientList = cli_next(cptr); + cli_prev(GlobalClientList) = 0; + } + cli_prev(cli_next(cptr)) = cli_prev(cptr); } - if (cptr->next) - cptr->next->prev = cptr->prev; - if (IsUser(cptr) && cptr->user) - { + cli_next(cptr) = cli_prev(cptr) = 0; + + if (IsUser(cptr) && cli_user(cptr)) { add_history(cptr, 0); off_history(cptr); } - if (cptr->user) - free_user(cptr->user, cptr); - if (cptr->serv) - { - if (cptr->serv->user) - free_user(cptr->serv->user, cptr); - if (cptr->serv->client_list) - RunFree(cptr->serv->client_list); - RunFree(cptr->serv->last_error_msg); - RunFree(cptr->serv); -#ifdef DEBUGMODE - servs.inuse--; -#endif + if (cli_user(cptr)) { + free_user(cli_user(cptr)); + cli_user(cptr) = 0; + } + + if (cli_serv(cptr)) { + if (cli_serv(cptr)->user) { + free_user(cli_serv(cptr)->user); + cli_serv(cptr)->user = 0; + } + if (cli_serv(cptr)->client_list) + MyFree(cli_serv(cptr)->client_list); + MyFree(cli_serv(cptr)->last_error_msg); + MyFree(cli_serv(cptr)); + --servs.inuse; + --servs.alloc; } -#ifdef DEBUGMODE - if (cptr->fd == -2) - cloc.inuse--; - else - crem.inuse--; -#endif free_client(cptr); - return; } -/* - * Although only a small routine, it appears in a number of places - * as a collection of a few lines...functions like this *should* be - * in this file, shouldnt they ? after all, this is list.c, isn't it ? - * -avalon +/** Link \a cptr into #GlobalClientList. + * @param[in] cptr Client to link into the global list. */ -void add_client_to_list(aClient *cptr) +void add_client_to_list(struct Client *cptr) { + assert(cli_verify(cptr)); + assert(cli_next(cptr) == 0); + assert(cli_prev(cptr) == 0); + /* * Since we always insert new clients to the top of the list, * this should mean the "me" is the bottom most item in the list. + * XXX - don't always count on the above, things change */ - cptr->next = client; - client = cptr; - if (cptr->next) - cptr->next->prev = cptr; - return; + cli_prev(cptr) = 0; + cli_next(cptr) = GlobalClientList; + GlobalClientList = cptr; + if (cli_next(cptr)) + cli_prev(cli_next(cptr)) = cptr; } -/* - * Look for ptr in the linked listed pointed to by link. +#if 0 +/** Perform a very CPU-intensive verification of %GlobalClientList. + * This checks the Client::cli_magic and Client::cli_prev field for + * each element in the list, and also checks that there are no loops. + * Any detected error will lead to an assertion failure. */ -Link *find_user_link(Link *lp, aClient *ptr) +void verify_client_list(void) { - if (ptr) - while (lp) - { - if (lp->value.cptr == ptr) - return (lp); - lp = lp->next; - } - return NULL; + struct Client *client, *prev = 0; + unsigned int visited = 0; + + for (client = GlobalClientList; client; client = cli_next(client), ++visited) { + /* Verify that this is a valid client, not a free'd one */ + assert(cli_verify(client)); + /* Verify that the list hasn't suddenly jumped around */ + assert(cli_prev(client) == prev); + /* Verify that the list hasn't become circular */ + assert(cli_next(client) != GlobalClientList); + assert(visited <= clients.alloc); + /* Remember what should precede us */ + prev = client; + } } +#endif /* DEBUGMODE */ -Link *make_link(void) +/** Allocate a new SLink element. + * Pulls from #slinkFreeList if it contains anything, else it + * allocates a new one from the heap. + * @return Newly allocated list element. + */ +struct SLink* make_link(void) { - Reg1 Link *lp; - - lp = (Link *)RunMalloc(sizeof(Link)); -#ifdef DEBUGMODE - links.inuse++; +#if 1 + struct SLink* lp = (struct SLink*) MyMalloc(sizeof(struct SLink)); +#else + struct SLink* lp = slinkFreeList; + if (lp) + slinkFreeList = lp->next; + else { + lp = (struct SLink*) MyMalloc(sizeof(struct SLink)); + links.alloc++; + } #endif + assert(0 != lp); + links.inuse++; + memset(lp, 0, sizeof(*lp)); return lp; } -void free_link(Link *lp) +/** Release a singly linked list element. + * @param[in] lp List element to mark as unused. + */ +void free_link(struct SLink* lp) { - RunFree(lp); -#ifdef DEBUGMODE - links.inuse--; + if (lp) { +#if 1 + MyFree(lp); +#else + lp->next = slinkFreeList; + slinkFreeList = lp; #endif + links.inuse--; + } } -Dlink *add_dlink(Dlink **lpp, aClient *cp) +/** Add an element to a doubly linked list. + * If \a lpp points to a non-NULL pointer, its DLink::prev field is + * updated to point to the newly allocated element. Regardless, + * \a lpp is overwritten with the pointer to the new link. + * @param[in,out] lpp Pointer to insertion location. + * @param[in] cp %Client to put in newly allocated element. + * @return Allocated link structure (same as \a lpp on output). + */ +struct DLink *add_dlink(struct DLink **lpp, struct Client *cp) { - register Dlink *lp; - lp = (Dlink *)RunMalloc(sizeof(Dlink)); + struct DLink* lp = (struct DLink*) MyMalloc(sizeof(struct DLink)); + assert(0 != lp); lp->value.cptr = cp; - lp->prev = NULL; + lp->prev = 0; if ((lp->next = *lpp)) lp->next->prev = lp; *lpp = lp; return lp; } -void remove_dlink(Dlink **lpp, Dlink *lp) +/** Remove a node from a doubly linked list. + * @param[out] lpp Pointer to next list element. + * @param[in] lp List node to unlink. + */ +void remove_dlink(struct DLink **lpp, struct DLink *lp) { - if (lp->prev) - { + assert(0 != lpp); + assert(0 != lp); + + if (lp->prev) { if ((lp->prev->next = lp->next)) lp->next->prev = lp->prev; } else if ((*lpp = lp->next)) lp->next->prev = NULL; - RunFree(lp); + MyFree(lp); } -aConfClass *make_class(void) -{ - Reg1 aConfClass *tmp; - - tmp = (aConfClass *) RunMalloc(sizeof(aConfClass)); -#ifdef DEBUGMODE - classs.inuse++; -#endif - return tmp; -} - -void free_class(aConfClass * tmp) -{ - RunFree(tmp); -#ifdef DEBUGMODE - classs.inuse--; -#endif -} - -aConfItem *make_conf(void) -{ - Reg1 aConfItem *aconf; - - aconf = (struct ConfItem *)RunMalloc(sizeof(aConfItem)); -#ifdef DEBUGMODE - aconfs.inuse++; -#endif - memset(&aconf->ipnum, 0, sizeof(struct in_addr)); - aconf->next = NULL; - aconf->host = aconf->passwd = aconf->name = NULL; - aconf->status = CONF_ILLEGAL; - aconf->clients = 0; - aconf->port = 0; - aconf->hold = 0; - aconf->confClass = NULL; - return (aconf); -} - -void delist_conf(aConfItem *aconf) +/** Report memory usage of a list to \a cptr. + * @param[in] cptr Client requesting information. + * @param[in] lstats List statistics descriptor. + * @param[in] itemname Plural name of item type. + * @param[in,out] totals If non-null, accumulates item counts and memory usage. + */ +void send_liststats(struct Client *cptr, const struct liststats *lstats, + const char *itemname, struct liststats *totals) { - if (aconf == conf) - conf = conf->next; - else + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s: inuse %zu(%zu) alloc %zu", + itemname, lstats->inuse, lstats->mem, lstats->alloc); + if (totals) { - aConfItem *bconf; - - for (bconf = conf; aconf != bconf->next; bconf = bconf->next); - bconf->next = aconf->next; + totals->inuse += lstats->inuse; + totals->alloc += lstats->alloc; + totals->mem += lstats->mem; } - aconf->next = NULL; -} - -void free_conf(aConfItem *aconf) -{ - del_queries((char *)aconf); - RunFree(aconf->host); - if (aconf->passwd) - memset(aconf->passwd, 0, strlen(aconf->passwd)); - RunFree(aconf->passwd); - RunFree(aconf->name); - RunFree(aconf); -#ifdef DEBUGMODE - aconfs.inuse--; -#endif - return; } -aGline *make_gline(int is_ipmask, char *host, char *reason, - char *name, time_t expire) -{ - Reg4 aGline *agline; -#ifdef WT_BADCHAN - int gtype=0; - if(*host == '#') gtype=1; /* BAD CHANNEL GLINE */ -#endif - - agline = (struct Gline *)RunMalloc(sizeof(aGline)); /* alloc memory */ - DupString(agline->host, host); /* copy vital information */ - DupString(agline->reason, reason); - DupString(agline->name, name); - agline->expire = expire; - agline->gflags = GLINE_ACTIVE; /* gline is active */ - if (is_ipmask) - SetGlineIsIpMask(agline); - -#ifdef WT_BADCHAN - if(gtype) - { agline->next = badchan; /* link it into the list */ - return (badchan = agline); - } -#endif - agline->next = gline; /* link it into the list */ - return (gline = agline); -} - -aGline *find_gline(aClient *cptr, aGline **pgline) +/** Report memory usage of list elements to \a cptr. + * @param[in] cptr Client requesting information. + * @param[in] name Unused pointer. + */ +void send_listinfo(struct Client *cptr, char *name) { - Reg3 aGline *agline = gline, *a2gline = NULL; - - while (agline) - { /* look through all glines */ - if (agline->expire <= TStime()) - { /* handle expired glines */ - free_gline(agline, a2gline); - agline = a2gline ? a2gline->next : gline; - if (!agline) - break; /* agline == NULL means gline == NULL */ - continue; - } - - /* Does gline match? */ - /* Added a check against the user's IP address as well -Kev */ - if ((GlineIsIpMask(agline) ? - match(agline->host, inetntoa(cptr->ip)) : - match(agline->host, cptr->sockhost)) == 0 && - match(agline->name, cptr->user->username) == 0) - { - if (pgline) - *pgline = a2gline; /* If they need it, give them the previous gline - entry (probably for free_gline, below) */ - return agline; - } + struct liststats total; + struct liststats confs; + struct ConfItem *conf; - a2gline = agline; - agline = agline->next; - } + memset(&total, 0, sizeof(total)); - return NULL; /* found no glines */ -} + clients.mem = clients.inuse * sizeof(struct Client); + send_liststats(cptr, &clients, "Clients", &total); -void free_gline(aGline *agline, aGline *pgline) -{ - if (pgline) - pgline->next = agline->next; /* squeeze agline out */ - else - { -#ifdef WT_BADCHAN - if(*agline->host =='#') - { - badchan = agline->next; - } - else -#endif - gline = agline->next; - } + connections.mem = connections.inuse * sizeof(struct Connection); + send_liststats(cptr, &connections, "Connections", &total); - RunFree(agline->host); /* and free up the memory */ - RunFree(agline->reason); - RunFree(agline->name); - RunFree(agline); -} + servs.mem = servs.inuse * sizeof(struct Server); + send_liststats(cptr, &servs, "Servers", &total); -#ifdef WT_BADCHAN -int bad_channel(char *name) -{ aGline *agline; + links.mem = links.inuse * sizeof(struct SLink); + send_liststats(cptr, &links, "Links", &total); - agline=badchan; - while(agline) - { - if ((agline->gflags&GLINE_ACTIVE) && (agline->expire >TStime()) && - !mmatch(agline->host,name)) - { return 1; - } - agline=agline->next; - } - return 0; -} -#endif + confs.alloc = GlobalConfCount; + confs.mem = confs.alloc * sizeof(GlobalConfCount); + for (confs.inuse = 0, conf = GlobalConfList; conf; conf = conf->next) + confs.inuse++; + send_liststats(cptr, &confs, "Confs", &total); -#ifdef DEBUGMODE -void send_listinfo(aClient *cptr, char *name) -{ - int inuse = 0, mem = 0, tmp = 0; - - sendto_one(cptr, ":%s %d %s :Local: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, inuse += cloc.inuse, - tmp = cloc.inuse * CLIENT_LOCAL_SIZE); - mem += tmp; - sendto_one(cptr, ":%s %d %s :Remote: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, - crem.inuse, tmp = crem.inuse * CLIENT_REMOTE_SIZE); - mem += tmp; - inuse += crem.inuse; - sendto_one(cptr, ":%s %d %s :Users: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, users.inuse, - tmp = users.inuse * sizeof(anUser)); - mem += tmp; - inuse += users.inuse, - sendto_one(cptr, ":%s %d %s :Servs: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, servs.inuse, - tmp = servs.inuse * sizeof(aServer)); - mem += tmp; - inuse += servs.inuse, - sendto_one(cptr, ":%s %d %s :Links: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, links.inuse, - tmp = links.inuse * sizeof(Link)); - mem += tmp; - inuse += links.inuse, - sendto_one(cptr, ":%s %d %s :Classes: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, classs.inuse, - tmp = classs.inuse * sizeof(aConfClass)); - mem += tmp; - inuse += classs.inuse, - sendto_one(cptr, ":%s %d %s :Confs: inuse: %d(%d)", - me.name, RPL_STATSDEBUG, name, aconfs.inuse, - tmp = aconfs.inuse * sizeof(aConfItem)); - mem += tmp; - inuse += aconfs.inuse, - sendto_one(cptr, ":%s %d %s :Totals: inuse %d %d", - me.name, RPL_STATSDEBUG, name, inuse, mem); + send_liststats(cptr, &total, "Totals", NULL); } - -#endif