/** Disassociate configuration from the client. * @param cptr Client to operate on. * @param aconf ConfItem to detach. */ static void detach_conf(struct Client* cptr, struct ConfItem* aconf) { struct SLink** lp; struct SLink* tmp; assert(0 != aconf); assert(0 != cptr); assert(0 < aconf->clients); lp = &(cli_confs(cptr)); while (*lp) { if ((*lp)->value.aconf == aconf) { if (aconf->conn_class && (aconf->status & CONF_CLIENT_MASK) && ConfLinks(aconf) > 0) --ConfLinks(aconf); assert(0 < aconf->clients); if (0 == --aconf->clients && IsIllegal(aconf)) free_conf(aconf); tmp = *lp; *lp = tmp->next; free_link(tmp); return; } lp = &((*lp)->next); } }
/** Associate a specific configuration entry to a *local* client (this * is the one which used in accepting the connection). Note, that this * automatically changes the attachment if there was an old one... * @param cptr Client to attach \a aconf to * @param aconf ConfItem to attach * @return Authorization check result. */ enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf) { struct SLink *lp; if (is_attached(aconf, cptr)) return ACR_ALREADY_AUTHORIZED; if (IsIllegal(aconf)) return ACR_NO_AUTHORIZATION; if ((aconf->status & (CONF_OPERATOR | CONF_CLIENT)) && ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0) return ACR_TOO_MANY_IN_CLASS; /* Use this for printing error message */ lp = make_link(); lp->next = cli_confs(cptr); lp->value.aconf = aconf; cli_confs(cptr) = lp; ++aconf->clients; if (aconf->status & CONF_CLIENT_MASK) ConfLinks(aconf)++; return ACR_OK; }
/** Look for any connections that we should try to initiate. * Reschedules itself to run again at the appropriate time. * @param[in] ev Timer event (ignored). */ static void try_connections(struct Event* ev) { struct ConfItem* aconf; struct ConfItem** pconf; time_t next; struct Jupe* ajupe; int hold; int done; assert(ET_EXPIRE == ev_type(ev)); assert(0 != ev_timer(ev)); Debug((DEBUG_NOTICE, "Connection check at : %s", myctime(CurrentTime))); next = CurrentTime + feature_int(FEAT_CONNECTFREQUENCY); done = 0; for (aconf = GlobalConfList; aconf; aconf = aconf->next) { /* Only consider server items with non-zero port and non-zero * connect times that are not actively juped. */ if (!(aconf->status & CONF_SERVER) || aconf->address.port == 0 || !(aconf->flags & CONF_AUTOCONNECT) || ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe))) continue; /* Do we need to postpone this connection further? */ hold = aconf->hold > CurrentTime; /* Update next possible connection check time. */ if (hold && next > aconf->hold) next = aconf->hold; /* Do not try to connect if its use is still on hold until future, * we have already initiated a connection this try_connections(), * too many links in its connection class, it is already linked, * or if connect rules forbid a link now. */ if (hold || done || (ConfLinks(aconf) > ConfMaxLinks(aconf)) || FindServer(aconf->name) || conf_eval_crule(aconf->name, CRULE_MASK)) continue; /* Ensure it is at the end of the list for future checks. */ if (aconf->next) { /* Find aconf's location in the list and splice it out. */ for (pconf = &GlobalConfList; *pconf; pconf = &(*pconf)->next) if (*pconf == aconf) *pconf = aconf->next; /* Reinsert it at the end of the list (where pconf is now). */ *pconf = aconf; aconf->next = 0; } /* Activate the connection itself. */ if (connect_server(aconf, 0)) sendto_opmask_butone(0, SNO_OLDSNO, "Connection to %s activated.", aconf->name); /* And stop looking for further candidates. */ done = 1; } Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next))); timer_add(&connect_timer, try_connections, 0, TT_ABSOLUTE, next); }