/** Report connection classes to a client. * @param[in] sptr Client requesting statistics. * @param[in] sd Stats descriptor for request (ignored). * @param[in] param Extra parameter from user (ignored). */ void report_classes(struct Client *sptr, const struct StatDesc *sd, char *param) { struct ConnectionClass *cltmp; for (cltmp = connClassList; cltmp; cltmp = cltmp->next) send_reply(sptr, RPL_STATSYLINE, (cltmp->valid ? 'Y' : 'y'), ConClass(cltmp), PingFreq(cltmp), ConFreq(cltmp), MaxLinks(cltmp), MaxSendq(cltmp), Links(cltmp) - 1); }
struct Class * make_class(void) { struct Class *tmp; tmp = rb_malloc(sizeof(struct Class)); ConFreq(tmp) = DEFAULT_CONNECTFREQUENCY; PingFreq(tmp) = DEFAULT_PINGFREQUENCY; MaxUsers(tmp) = 1; MaxSendq(tmp) = DEFAULT_SENDQ; tmp->ip_limits = rb_new_patricia(PATRICIA_BITS); return tmp; }
/** Initialize the connection class list. * A connection class named "default" is created, with ping frequency, * connection frequency, maximum links and max SendQ values from the * corresponding configuration features. */ void init_class(void) { if (!connClassList) { connClassList = (struct ConnectionClass*) make_class(); connClassList->next = 0; } /* We had better not try and free this... */ ConClass(connClassList) = "default"; PingFreq(connClassList) = feature_int(FEAT_PINGFREQUENCY); ConFreq(connClassList) = feature_int(FEAT_CONNECTFREQUENCY); MaxLinks(connClassList) = feature_int(FEAT_MAXIMUM_LINKS); MaxSendq(connClassList) = feature_uint(FEAT_DEFAULTMAXSENDQLENGTH); connClassList->valid = 1; Links(connClassList) = 1; }
/** Make sure we have a connection class named \a name. * If one does not exist, create it. Then set its ping frequency, * connection frequency, maximum link count, and max SendQ according * to the parameters. * @param[in] name Connection class name. * @param[in] ping Ping frequency for clients in this class. * @param[in] confreq Connection frequency for clients. * @param[in] maxli Maximum link count for class. * @param[in] sendq Max SendQ for clients. */ void add_class(char *name, unsigned int ping, unsigned int confreq, unsigned int maxli, unsigned int sendq) { struct ConnectionClass* p; Debug((DEBUG_DEBUG, "Add Class %s: cf: %u pf: %u ml: %u sq: %d", name, confreq, ping, maxli, sendq)); assert(name != NULL); p = do_find_class(name, 1); if (!p) p = make_class(); else MyFree(ConClass(p)); ConClass(p) = name; ConFreq(p) = confreq; PingFreq(p) = ping; MaxLinks(p) = maxli; MaxSendq(p) = (sendq > 0U) ? sendq : feature_uint(FEAT_DEFAULTMAXSENDQLENGTH); p->valid = 1; }
/** Unlink (and dereference) invalid connection classes. * This is used in combination with class_mark_delete() during rehash * to get rid of connection classes that are no longer in the * configuration. */ void class_delete_marked(void) { struct ConnectionClass* cl; struct ConnectionClass* prev; Debug((DEBUG_DEBUG, "Class check:")); for (prev = cl = connClassList; cl; cl = prev->next) { Debug((DEBUG_DEBUG, "Class %s : CF: %d PF: %d ML: %d LI: %d SQ: %d", ConClass(cl), ConFreq(cl), PingFreq(cl), MaxLinks(cl), Links(cl), MaxSendq(cl))); /* * unlink marked classes, delete unreferenced ones */ if (cl->valid || Links(cl) > 1) prev = cl; else { prev->next = cl->next; free_class(cl); } } }
/* * close_connection * Close the physical connection. This function must make * MyConnect(client_p) == FALSE, and set client_p->from == NULL. */ void close_connection(struct Client *client_p) { struct ConfItem *conf; struct AccessItem *aconf; struct ClassItem *aclass; assert(NULL != client_p); if (!IsDead(client_p)) { /* attempt to flush any pending dbufs. Evil, but .. -- adrian */ /* there is still a chance that we might send data to this socket * even if it is marked as blocked (COMM_SELECT_READ handler is called * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx */ ClearSendqBlocked(client_p); send_queued_write(client_p); } if (IsServer(client_p)) { ++ServerStats.is_sv; ServerStats.is_sbs += client_p->localClient->send.bytes; ServerStats.is_sbr += client_p->localClient->recv.bytes; ServerStats.is_sti += CurrentTime - client_p->firsttime; /* XXX Does this even make any sense at all anymore? * scheduling a 'quick' reconnect could cause a pile of * nick collides under TSora protocol... -db */ /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((conf = find_conf_exact(SERVER_TYPE, client_p->name, client_p->username, client_p->host))) { /* * Reschedule a faster reconnect, if this was a automatically * connected configuration entry. (Note that if we have had * a rehash in between, the status has been changed to * CONF_ILLEGAL). But only do this if it was a "good" link. */ aconf = (struct AccessItem *)map_to_conf(conf); aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr); aconf->hold = time(NULL); aconf->hold += (aconf->hold - client_p->since > HANGONGOODLINK) ? HANGONRETRYDELAY : ConFreq(aclass); if (nextconnect > aconf->hold) nextconnect = aconf->hold; } } else if (IsClient(client_p)) { ++ServerStats.is_cl; ServerStats.is_cbs += client_p->localClient->send.bytes; ServerStats.is_cbr += client_p->localClient->recv.bytes; ServerStats.is_cti += CurrentTime - client_p->firsttime; } else ++ServerStats.is_ni; #ifdef HAVE_LIBCRYPTO if (client_p->localClient->fd.ssl) { SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN); if (!SSL_shutdown(client_p->localClient->fd.ssl)) SSL_shutdown(client_p->localClient->fd.ssl); } #endif if (client_p->localClient->fd.flags.open) fd_close(&client_p->localClient->fd); if (HasServlink(client_p)) { if (client_p->localClient->ctrlfd.flags.open) fd_close(&client_p->localClient->ctrlfd); } dbuf_clear(&client_p->localClient->buf_sendq); dbuf_clear(&client_p->localClient->buf_recvq); MyFree(client_p->localClient->passwd); detach_conf(client_p, CONF_TYPE); client_p->from = NULL; /* ...this should catch them! >:) --msa */ }