/** Set a server's numeric nick. * @param[in] cptr %Client that announced the server (ignored). * @param[in,out] server %Server that is being assigned a numnick. * @param[in] yxx %Numeric nickname for server. */ void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx) { unsigned int index; if (5 == strlen(yxx)) { ircd_strncpy(cli_yxx(server), yxx, 2); ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3); } else { (cli_yxx(server))[0] = yxx[0]; cli_serv(server)->nn_capacity[0] = yxx[1]; cli_serv(server)->nn_capacity[1] = yxx[2]; } cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity); index = base64toint(cli_yxx(server)); if (index >= lastNNServer) lastNNServer = index + 1; server_list[index] = server; /* Note, exit_one_client uses the fact that `client_list' != NULL to * determine that SetServerYXX has been called - and then calls * ClearServerYXX. However, freeing the allocation happens in free_client() */ cli_serv(server)->client_list = (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*)); }
/** Register numeric of new (remote) client. * See @ref numnicks for more details. * Add it to the appropriate client_list. * @param[in] acptr %User being registered. * @param[in] yxx User's numnick. */ void SetRemoteNumNick(struct Client* acptr, const char *yxx) { struct Client** acptrp; struct Client* server = cli_user(acptr)->server; if (5 == strlen(yxx)) { strcpy(cli_yxx(acptr), yxx + 2); } else { (cli_yxx(acptr))[0] = *++yxx; (cli_yxx(acptr))[1] = *++yxx; (cli_yxx(acptr))[2] = 0; } Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr), base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask)); acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask]; if (*acptrp) { /* * this exits the old client in the array, not the client * that is being set */ exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)"); } *acptrp = acptr; }
/** Set a server's numeric nick. * See @ref numnicks for more details. * @param[in] c %Server that is being assigned a numnick. * @param[in] numeric Numnick value for server. */ void SetYXXServerName(struct Client* c, unsigned int numeric) { assert(0 != c); assert(numeric < NN_MAX_SERVER); inttobase64(cli_yxx(c), numeric, 2); if (numeric >= lastNNServer) lastNNServer = numeric + 1; server_list[numeric] = c; }
static void stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat, char* param) { struct Client *acptr; /* lowercase 'v' is for human-readable, * uppercase 'V' is for machine-readable */ if (stat == 'v') send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, "%-20s %-20s Flags Hops Numeric Lag RTT Up Down " "Clients/Max Proto %-10s :Info", "Servername", "Uplink", "LinkTS"); for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (param && match(param, cli_name(acptr))) /* narrow search */ continue; send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ? "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i " "P%-2i %Tu :%s" : "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s", cli_name(acptr), cli_name(cli_serv(acptr)->up), IsBurst(acptr) ? 'B' : '-', IsBurstAck(acptr) ? 'A' : '-', IsHub(acptr) ? 'H' : '-', IsService(acptr) ? 'S' : '-', cli_hopcount(acptr), NumServ(acptr), base64toint(cli_yxx(acptr)), cli_serv(acptr)->lag, cli_serv(acptr)->asll_rtt, cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from, cli_serv(acptr)->clients, cli_serv(acptr)->nn_mask, cli_serv(acptr)->prot, cli_serv(acptr)->timestamp, cli_info(acptr)); } }
/** Register numeric of new (local) client. * See @ref numnicks for more details. * Assign a numnick and add it to our client_list. * @param[in] cptr %User being registered. */ int SetLocalNumNick(struct Client *cptr) { static unsigned int last_nn = 0; struct Client** client_list = cli_serv(&me)->client_list; unsigned int mask = cli_serv(&me)->nn_mask; unsigned int count = 0; assert(cli_user(cptr)->server == &me); while (client_list[last_nn & mask]) { if (++count == NN_MAX_CLIENT) { assert(count < NN_MAX_CLIENT); return 0; } if (++last_nn == NN_MAX_CLIENT) last_nn = 0; } client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */ inttobase64(cli_yxx(cptr), last_nn, 3); if (++last_nn == NN_MAX_CLIENT) last_nn = 0; return 1; }
/** Set a server's capacity. * @param[in] c %Server whose capacity is being set. * @param[in] capacity Maximum number of clients the server supports. */ void SetYXXCapacity(struct Client* c, unsigned int capacity) { unsigned int max_clients = 16; /* * Calculate mask to be used for the maximum number of clients */ while (max_clients < capacity) max_clients <<= 1; /* * Sanity checks */ if (max_clients > NN_MAX_CLIENT) { fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d " "too large ! Please decrease this value.\n", max_clients - NN_MAX_CLIENT); exit(-1); } --max_clients; inttobase64(cli_serv(c)->nn_capacity, max_clients, 3); cli_serv(c)->nn_mask = max_clients; /* Our Numeric Nick mask */ cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1, sizeof(struct Client*)); server_list[base64toint(cli_yxx(c))] = c; }
/** Unassign a server's numnick. * @param[in] server %Server that should be removed from the numnick table. */ void ClearServerYXX(const struct Client *server) { unsigned int index = base64toint(cli_yxx(server)); if (server_list[index] == server) /* Sanity check */ server_list[index] = 0; }
/* Rewritten by Run - 24 sept 94 */ static void exit_one_client(struct Client* bcptr, const char* comment) { struct SLink *lp; struct Ban *bp; if (cli_serv(bcptr) && cli_serv(bcptr)->client_list) /* Was SetServerYXX called ? */ ClearServerYXX(bcptr); /* Removes server from server_list[] */ if (IsUser(bcptr)) { /* * clear out uping requests */ if (IsUPing(bcptr)) uping_cancel(bcptr, 0); /* * Stop a running /LIST clean */ if (MyUser(bcptr) && cli_listing(bcptr)) { MyFree(cli_listing(bcptr)); cli_listing(bcptr) = NULL; } /* * If a person is on a channel, send a QUIT notice * to every client (person) on the same channel (so * that the client can show the "**signoff" message). * (Note: The notice is to the local clients *only*) */ sendcmdto_common_channels_butone(bcptr, CMD_QUIT, NULL, ":%s", comment); remove_user_from_all_channels(bcptr); /* Clean up invitefield */ while ((lp = cli_user(bcptr)->invited)) del_invite(bcptr, lp->value.chptr); /* Clean up silencefield */ while ((bp = cli_user(bcptr)->silence)) { cli_user(bcptr)->silence = bp->next; free_ban(bp); } /* Clean up snotice lists */ if (MyUser(bcptr)) set_snomask(bcptr, ~0, SNO_DEL); if (IsInvisible(bcptr)) { assert(UserStats.inv_clients > 0); --UserStats.inv_clients; } if (IsOper(bcptr)) { assert(UserStats.opers > 0); --UserStats.opers; } if (MyConnect(bcptr)) Count_clientdisconnects(bcptr, UserStats); else Count_remoteclientquits(UserStats, bcptr); } else if (IsServer(bcptr)) { /* Remove downlink list node of uplink */ remove_dlink(&(cli_serv(cli_serv(bcptr)->up))->down, cli_serv(bcptr)->updown); cli_serv(bcptr)->updown = 0; if (MyConnect(bcptr)) Count_serverdisconnects(UserStats); else Count_remoteserverquits(UserStats); } else if (IsMe(bcptr)) { sendto_opmask_butone(0, SNO_OLDSNO, "ERROR: tried to exit me! : %s", comment); return; /* ...must *never* exit self! */ } else if (IsUnknown(bcptr) || IsConnecting(bcptr) || IsHandshake(bcptr)) Count_unknowndisconnects(UserStats); /* * Update IPregistry */ if (IsIPChecked(bcptr)) IPcheck_disconnect(bcptr); /* * Remove from serv->client_list * NOTE: user is *always* NULL if this is a server */ if (cli_user(bcptr)) { assert(!IsServer(bcptr)); /* bcptr->user->server->serv->client_list[IndexYXX(bcptr)] = NULL; */ RemoveYXXClient(cli_user(bcptr)->server, cli_yxx(bcptr)); } /* Remove bcptr from the client list */ #ifdef DEBUGMODE if (hRemClient(bcptr) != 0) Debug((DEBUG_ERROR, "%p !in tab %s[%s] %p %p %p %d %d %p", bcptr, cli_name(bcptr), cli_from(bcptr) ? cli_sockhost(cli_from(bcptr)) : "??host", cli_from(bcptr), cli_next(bcptr), cli_prev(bcptr), cli_fd(bcptr), cli_status(bcptr), cli_user(bcptr))); #else hRemClient(bcptr); #endif remove_client_from_list(bcptr); }