/* * hAddClient * Adds a client's name in the proper hash linked list, can't fail, * cptr must have a non-null name or expect a coredump, the name is * infact taken from cptr->name */ int hAddClient(struct Client *cptr) { HASHREGS hashv = strhash(cli_name(cptr)); cli_hnext(cptr) = clientTable[hashv]; clientTable[hashv] = cptr; return 0; }
/* * hSeekClient * New semantics: finds a client whose name is 'name' and whose * status is one of those marked in TMask, if can't find one * returns NULL. If it finds one moves it to the top of the list * and returns it. */ struct Client* hSeekClient(const char *name, int TMask) { HASHREGS hashv = strhash(name); struct Client *cptr = clientTable[hashv]; if (cptr) { if (0 == (cli_status(cptr) & TMask) || 0 != ircd_strcmp(name, cli_name(cptr))) { struct Client* prev; while (prev = cptr, cptr = cli_hnext(cptr)) { if ((cli_status(cptr) & TMask) && (0 == ircd_strcmp(name, cli_name(cptr)))) { cli_hnext(prev) = cli_hnext(cptr); cli_hnext(cptr) = clientTable[hashv]; clientTable[hashv] = cptr; break; } } } } return cptr; }
/* * hChangeClient * Removes the old name of a client from a linked list and adds * the new one to another linked list, there is a slight chanche * that this is useless if the two hashes are the same but it still * would need to move the name to the top of the list. * As always it's responsibility of the caller to check that * both newname and cptr->name are valid names (not "" or NULL). * Typically, to change the nick of an already hashed client: * if (!BadPtr(newname) && ClearTheNameSomeHow(newname)) { * hChangeClient(cptr, newname); * strcpy(cptr->name, newname); * }; * There isn't an equivalent function for channels since they * don't change name. */ int hChangeClient(struct Client *cptr, const char *newname) { HASHREGS newhash = strhash(newname); assert(0 != cptr); hRemClient(cptr); cli_hnext(cptr) = clientTable[newhash]; clientTable[newhash] = cptr; return 0; }
int m_hash(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { int max_chain = 0; int buckets = 0; int count = 0; struct Client* cl; struct Channel* ch; int i; sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Hash Table Statistics", sptr); for (i = 0; i < HASHSIZE; ++i) { if ((cl = clientTable[i])) { int len = 0; ++buckets; for ( ; cl; cl = cli_hnext(cl)) ++len; if (len > max_chain) max_chain = len; count += len; } } sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Client: entries: %d buckets: %d " "max chain: %d", sptr, count, buckets, max_chain); buckets = 0; count = 0; max_chain = 0; for (i = 0; i < HASHSIZE; ++i) { if ((ch = channelTable[i])) { int len = 0; ++buckets; for ( ; ch; ch = ch->hnext) ++len; if (len > max_chain) max_chain = len; count += len; } } sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Channel: entries: %d buckets: %d " "max chain: %d", sptr, count, buckets, max_chain); return 0; }
/* * Create a new struct Client 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!!). */ struct Client* make_client(struct Client *from, int status) { struct Client* cptr = 0; struct Connection* con = 0; 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 */ 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_local(cptr) = 1; /* Set certain fields of the struct Client */ cli_since(cptr) = cli_lasttime(cptr) = cli_firsttime(cptr) = CurrentTime; cli_lastnick(cptr) = TStime(); } else con = cli_connect(from); /* use 'from's connection */ assert(0 != con); assert(con_verify(con)); cli_magic(cptr) = CLIENT_MAGIC; cli_connect(cptr) = con; /* set the connection and other fields */ cli_status(cptr) = status; cli_hnext(cptr) = cptr; strcpy(cli_username(cptr), "unknown"); return cptr; }
/* * hRemClient * Removes a Client's name from the hash linked list */ int hRemClient(struct Client *cptr) { HASHREGS hashv = strhash(cli_name(cptr)); struct Client *tmp = clientTable[hashv]; if (tmp == cptr) { clientTable[hashv] = cli_hnext(cptr); cli_hnext(cptr) = cptr; return 0; } while (tmp) { if (cli_hnext(tmp) == cptr) { cli_hnext(tmp) = cli_hnext(cli_hnext(tmp)); cli_hnext(cptr) = cptr; return 0; } tmp = cli_hnext(tmp); } return -1; }
/** 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), 0); /* 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 */ } } cli_connect(cptr) = 0; dealloc_client(cptr); /* actually destroy the client */ }