static void feature_notify_excepts(void) { char imaxlist[BUFSIZE] = ""; char cmodebuf[BUFSIZE] = ""; if (feature_bool(FEAT_EXCEPTS)) { add_isupport_s("EXCEPTS", "e"); add_isupport_i("MAXEXCEPTS", feature_int(FEAT_MAXEXCEPTS)); } else { del_isupport("EXCEPTS"); del_isupport("MAXEXCEPTS"); } /* "be,AkU,Ll,aCcDdiMmNnOpQRrSsTtZz" */ ircd_snprintf(0, cmodebuf, BUFSIZE, "b%s,%sk%s,Ll,aCcDdiMmNnOpQRrSsTtZz", feature_bool(FEAT_EXCEPTS) ? "e" : "", feature_bool(FEAT_OPLEVELS) ? "A" : "", feature_bool(FEAT_OPLEVELS) ? "U" : ""); add_isupport_s("CHANMODES", cmodebuf); strcat(imaxlist, "b:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXBANS))); if (feature_bool(FEAT_EXCEPTS)) { strcat(imaxlist, ",e:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXEXCEPTS))); } add_isupport_s("MAXLIST", imaxlist); }
/** 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; }
/** Set MAXBANS, self explanatory */ static void set_isupport_maxbans(void) { char imaxlist[BUFSIZE] = ""; add_isupport_i("MAXBANS", feature_int(FEAT_MAXBANS)); strcat(imaxlist, "b:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXBANS))); if (feature_bool(FEAT_EXCEPTS)) { strcat(imaxlist, ",e:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXEXCEPTS))); } add_isupport_s("MAXLIST", imaxlist); }
/* * mo_version - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; if (MyConnect(sptr) && parc > 1) { if (!(acptr = find_match_server(parv[1]))) { send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); return 0; } parv[1] = cli_name(acptr); } if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) == HUNTED_ISME) { send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), debug_serveropts()); send_supported(sptr); } return 0; }
/* * m_motd - generic message handler * * parv[0] - sender prefix * parv[1] - servername * * modified 30 mar 1995 by flux ([email protected]) * T line patch - display motd based on hostmask * modified again 7 sep 97 by Ghostwolf with code and ideas * stolen from comstud & Xorath. All motd files are read into * memory in read_motd() in s_conf.c * * Now using the motd_* family of functions defined in motd.c */ int m_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (hunt_server_cmd(sptr, CMD_MOTD, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send(sptr); }
/* * m_time - generic message handler * * parv[0] = sender prefix * parv[1] = servername */ int m_time(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (hunt_server_cmd(sptr, CMD_TIME, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) != HUNTED_ISME) return 0; send_reply(sptr, RPL_TIME, cli_name(&me), TStime(), TSoffset, date((long)0)); return 0; }
/** Handle an ADMIN message from an oper's connection. * * \a parv has the following elements: * \li \a parv[1] (optional) is the server name being interrogated. * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int mo_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) != HUNTED_ISME) return 0; return send_admin_info(sptr); }
/* * m_rules - generic message handler * * parv[0] - sender prefix * parv[1] - servername */ int m_rules(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (!feature_bool(FEAT_RULES)) return send_reply(sptr, ERR_DISABLED, "RULES"); if (hunt_server_cmd(sptr, CMD_RULES, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send_type(sptr, MOTD_RULES); }
/* * make_auth_request - allocate a new auth request */ static struct AuthRequest* make_auth_request(struct Client* client) { struct AuthRequest* auth = (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest)); assert(0 != auth); memset(auth, 0, sizeof(struct AuthRequest)); auth->flags = AM_TIMEOUT; auth->fd = -1; auth->client = client; cli_auth(client) = auth; timer_add(timer_init(&auth->timeout), auth_timeout_callback, (void*) auth, TT_RELATIVE, feature_int(FEAT_AUTH_TIMEOUT)); return auth; }
/** Create a DNS request record for the server. * @param[in] query Callback information for caller. * @return Newly allocated and linked-in reslist. */ static struct reslist * make_request(dns_callback_f callback, void *ctx) { struct reslist *request; if (!resolver_started()) restart_resolver(); request = (struct reslist *)MyMalloc(sizeof(struct reslist)); memset(request, 0, sizeof(struct reslist)); request->state = REQ_IDLE; request->sentat = CurrentTime; request->retries = feature_int(FEAT_IRCD_RES_RETRIES); request->resend = 1; request->timeout = feature_int(FEAT_IRCD_RES_TIMEOUT); memset(&request->addr, 0, sizeof(request->addr)); request->callback = callback; request->callback_ctx = ctx; add_dlink(&request->node, &request_list); return(request); }
/** Handle a STATS message from some connection. * * \a parv has the following elements: * \li \a parv[1] is the statistics selector * \li \a parv[2] (optional) is server to query * \li \a parv[3] (optional) is a mask to filter the results * * If \a parv[1] is "l" (or "links"), \a parv[3] is a mask of servers. * If \a parv[1] is "p" (or "P" or "ports"), \a parv[3] is a mask of * ports. If \a parv[1] is "k" (or "K" or "klines" or "i" or "I" or * "access"), \a parv[3] is a hostname with optional username@ prefix * (for opers, hostmasks are allowed). * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const struct StatDesc *sd; char *param; /* If we didn't find a descriptor, send them help */ if ((parc < 2) || !(sd = stats_find(parv[1]))) parv[1] = "*", sd = stats_find("*"); assert(sd != 0); /* Check whether the client can issue this command. If source is * not privileged (server or an operator), then the STAT_FLAG_OPERONLY * flag must not be set, and if the STAT_FLAG_OPERFEAT flag is set, * then the feature given by sd->sd_control must be off. * * This checks cptr rather than sptr so that a local oper may send * /stats queries to other servers. */ if (!IsPrivileged(cptr) && ((sd->sd_flags & STAT_FLAG_OPERONLY) || ((sd->sd_flags & STAT_FLAG_OPERFEAT) && feature_bool(sd->sd_control)))) return send_reply(sptr, ERR_NOPRIVILEGES); /* Check for extra parameter */ if ((sd->sd_flags & STAT_FLAG_VARPARAM) && parc > 3 && !EmptyString(parv[3])) param = parv[3]; else param = NULL; /* Ok, track down who's supposed to get this... */ if (hunt_server_cmd(sptr, CMD_STATS, cptr, feature_int(FEAT_HIS_REMOTE), param ? "%s %C :%s" : "%s :%C", 2, parc, parv) != HUNTED_ISME) return 0; /* Someone else--cool :) */ /* Check if they are a local user */ if ((sd->sd_flags & STAT_FLAG_LOCONLY) && !MyUser(sptr)) return send_reply(sptr, ERR_NOPRIVILEGES); assert(sd->sd_func != 0); /* Ok, dispatch the stats function */ (*sd->sd_func)(sptr, sd, param); /* Done sending them the stats */ return send_reply(sptr, RPL_ENDOFSTATS, parv[1]); }
/** Set EXCEPTS, MAXEXCEPTS, and CHANMODES based on if HALFOPS are enabled or not */ static void set_isupport_excepts(void) { char imaxlist[BUFSIZE] = ""; if (feature_bool(FEAT_EXCEPTS)) { add_isupport_s("EXCEPTS", "e"); add_isupport_i("MAXEXCEPTS", feature_int(FEAT_MAXEXCEPTS)); } else { del_isupport("EXCEPTS"); del_isupport("MAXEXCEPTS"); } add_isupport_s("CHANMODES", feature_bool(FEAT_EXCEPTS) ? "be,k,lL,acimnprstzCMNOQSTZ" : "b,k,lL,acimnprstzCMNOQSTZ"); strcat(imaxlist, "b:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXBANS))); if (feature_bool(FEAT_EXCEPTS)) { strcat(imaxlist, ",e:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXEXCEPTS))); } add_isupport_s("MAXLIST", imaxlist); }
/** Allocate a new DBufBuffer. * If #dbufFreeList != NULL, use the head of that list; otherwise, * allocate a new buffer. * @return Newly allocated buffer list. */ static struct DBufBuffer *dbuf_alloc(void) { struct DBufBuffer* db = dbufFreeList; if (db) { dbufFreeList = db->next; ++DBufUsedCount; } else if (DBufAllocCount * DBUF_SIZE < feature_int(FEAT_BUFFERPOOL)) { db = (struct DBufBuffer*) MyMalloc(sizeof(struct DBufBuffer)); assert(0 != db); ++DBufAllocCount; ++DBufUsedCount; } return db; }
/** 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) { struct Client* cptr = 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 */ 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 - feature_int(FEAT_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; }
/* * mo_version - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; if (MyConnect(sptr) && parc > 1) { if (!(acptr = find_match_server(parv[1]))) { send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); return 0; } parv[1] = cli_name(acptr); } if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) == HUNTED_ISME) { send_reply(sptr, RPL_VERSION, version, cvs_version, debugmode, cli_name(&me), debug_serveropts()); #ifdef USE_SSL #ifdef DEBUGMODE sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Headers: %s", sptr, OPENSSL_VERSION_TEXT); #endif sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Library: %s", sptr, SSLeay_version(SSLEAY_VERSION)); #endif #ifdef USE_GEOIP sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :GeoIP %s", sptr, geoip_version()); #endif #ifdef USE_MMDB sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :MaxMindDB %s", sptr, geoip_libmmdb_version()); #endif send_supported(sptr); } return 0; }
/** Find the shortest non-zero ping time attached to a client. * If all attached ping times are zero, return the value for * FEAT_PINGFREQUENCY. * @param[in] acptr Client to find ping time for. * @return Ping time in seconds. */ int client_get_ping(const struct Client* acptr) { int ping = 0; struct ConfItem* aconf; struct SLink* link; assert(cli_verify(acptr)); for (link = cli_confs(acptr); link; link = link->next) { aconf = link->value.aconf; if (aconf->status & (CONF_CLIENT | CONF_SERVER)) { int tmp = get_conf_ping(aconf); if (0 < tmp && (ping > tmp || !ping)) ping = tmp; } } if (0 == ping) ping = feature_int(FEAT_PINGFREQUENCY); Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping)); return ping; }
/* * m_nick - message handler for local clients * parv[0] = sender prefix * parv[1] = nickname */ int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr; char nick[NICKLEN + 2]; char* arg; char* s; const char* client_name; assert(0 != cptr); assert(cptr == sptr); if (IsServerPort(cptr)) return exit_client(cptr, cptr, &me, "Use a different port"); /* * parv[0] will be empty for clients connecting for the first time */ client_name = (*(cli_name(sptr))) ? cli_name(sptr) : "*"; if (parc < 2) { send_reply(sptr, ERR_NONICKNAMEGIVEN); return 0; } /* * Don't let them send make us send back a really long string of * garbage */ arg = parv[1]; if (strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0'; if ((s = strchr(arg, '~'))) *s = '\0'; strcpy(nick, arg); /* * If do_nick_name() returns a null name then reject it. */ if (0 == do_nick_name(nick)) { send_reply(sptr, ERR_ERRONEUSNICKNAME, arg); return 0; } /* * Check if this is a LOCAL user trying to use a reserved (Juped) * nick, if so tell him that it's a nick in use... */ if (isNickJuped(nick)) { send_reply(sptr, ERR_NICKNAMEINUSE, nick); return 0; /* NICK message ignored */ } if (!(acptr = FindClient(nick))) { /* * No collisions, all clear... */ return set_nick_name(cptr, sptr, nick, parc, parv); } if (IsServer(acptr)) { send_reply(sptr, ERR_NICKNAMEINUSE, nick); return 0; /* NICK message ignored */ } /* * If acptr == sptr, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch) */ if (acptr == sptr) { /* * If acptr == sptr, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch) */ if (0 != strcmp(cli_name(acptr), nick)) { /* * Allows change of case in his/her nick */ return set_nick_name(cptr, sptr, nick, parc, parv); } /* * This is just ':old NICK old' type thing. * Just forget the whole thing here. There is * no point forwarding it to anywhere, * especially since servers prior to this * version would treat it as nick collision. */ return 0; } /* * Note: From this point forward it can be assumed that * acptr != sptr (point to different client structures). */ assert(acptr != sptr); /* * If the older one is "non-person", the new entry is just * allowed to overwrite it. Just silently drop non-person, * and proceed with the nick. This should take care of the * "dormant nick" way of generating collisions... * * XXX - hmmm can this happen after one is registered? * * Yes, client 1 connects to IRC and registers, client 2 connects and * sends "NICK foo" but doesn't send anything more. client 1 now does * /nick foo, they should succeed and client 2 gets disconnected with * the message below. */ if (IsUnknown(acptr) && MyConnect(acptr)) { ServerStats->is_ref++; IPcheck_connect_fail(acptr); exit_client(cptr, acptr, &me, "Overridden by other sign on"); return set_nick_name(cptr, sptr, nick, parc, parv); } /* * NICK is coming from local client connection. Just * send error reply and ignore the command. */ send_reply(sptr, ERR_NICKNAMEINUSE, nick); return 0; /* NICK message ignored */ }
/* * ms_svsnick - server message handler * parv[0] = sender prefix * parv[1] = Target numeric * parv[2] = New nickname */ int ms_svsnick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr = NULL; struct Client* acptr2 = NULL; char nick[NICKLEN + 2]; char* arg; if (parc < 3) return need_more_params(sptr, "SVSNICK"); if (!(acptr = findNUser(parv[1]))) return 0; /* Ignore SVSNICK for a user that has quit */ if (ircd_strcmp(cli_name(acptr), parv[2]) == 0) return 0; /* Nick already set to what SVSNICK wants, ignoring... */ /* * Basic sanity checks */ /* * Don't let them make us send back a really long string of * garbage */ arg = parv[2]; if (strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0'; strcpy(nick, arg); /* * If do_nick_name() returns a null name then reject it. */ if (0 == do_nick_name(nick)) return 0; /* * Check if this is a LOCAL user trying to use a reserved (Juped) * nick, if so tell him that it's a nick in use... */ if (isNickJuped(nick)) return 0; /* NICK message ignored */ if (feature_bool(FEAT_OPER_SINGLELETTERNICK) && !IsAnOper(acptr) && nick[1] == '\0') return 0; /* * Set acptr2 to the client pointer of any user with nick's name. * If the user is the same as the person being svsnick'ed, let it * through as it is probably a change in the nickname's case. */ if ((acptr2 = FindClient(nick))) { /* * If acptr == acptr2, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch), so we let it through :) */ if (acptr != acptr2) { /* Nick collision occured, kill user with specific reason */ ++ServerStats->is_kill; /* ??? - Why do we use cptr here? */ SetFlag(cptr, FLAG_KILLED); exit_client(cptr, acptr2, &me, "Killed (Nickname Enforcement)"); } } set_nick_name(acptr, acptr, nick, parc, parv, 1); sendcmdto_serv_butone(sptr, CMD_SVSNICK, cptr, "%s %s", parv[1], nick); return 0; }
/** Set WATCH if they are enabled. */ static void set_isupport_watchs(void) { add_isupport_i("WATCH", feature_int(FEAT_MAXWATCHS)); }
vector<double> ConsensusMapNormalizerAlgorithmThreshold::computeCorrelation(const ConsensusMap& map, const double& ratio_threshold, const String& acc_filter, const String& desc_filter) { Size number_of_features = map.size(); Size number_of_maps = map.getFileDescriptions().size(); vector<vector<double> > feature_int(number_of_maps); //get map with most features, resize feature_int UInt map_with_most_features_idx = 0; ConsensusMap::FileDescriptions::const_iterator map_with_most_features = map.getFileDescriptions().find(0); for (UInt i = 0; i < number_of_maps; i++) { feature_int[i].resize(number_of_features); ConsensusMap::FileDescriptions::const_iterator it = map.getFileDescriptions().find(i); if (it->second.size > map_with_most_features->second.size) { map_with_most_features = it; map_with_most_features_idx = i; } } //fill feature_int with intensities Size pass_counter = 0; ConsensusMap::ConstIterator cf_it; UInt idx = 0; for (cf_it = map.begin(); cf_it != map.end(); ++cf_it, ++idx) { if (!ConsensusMapNormalizerAlgorithmMedian::passesFilters_(cf_it, map, acc_filter, desc_filter)) { continue; } ++pass_counter; ConsensusFeature::HandleSetType::const_iterator f_it; for (f_it = cf_it->getFeatures().begin(); f_it != cf_it->getFeatures().end(); ++f_it) { feature_int[f_it->getMapIndex()][idx] = f_it->getIntensity(); } } LOG_INFO << endl << "Using " << pass_counter << "/" << map.size() << " consensus features for computing normalization coefficients" << endl << endl; //determine ratio vector<double> ratio_vector(number_of_maps); for (UInt j = 0; j < number_of_maps; j++) { vector<double> ratios; for (UInt k = 0; k < number_of_features; ++k) { if (feature_int[map_with_most_features_idx][k] != 0.0 && feature_int[j][k] != 0.0) { double ratio = feature_int[map_with_most_features_idx][k] / feature_int[j][k]; if (ratio > ratio_threshold && ratio < 1 / ratio_threshold) { ratios.push_back(ratio); } } } if (ratios.empty()) { LOG_WARN << endl << "Not enough features passing filters. Cannot compute normalization coefficients for all maps. Result will be unnormalized." << endl << endl; return vector<double>(number_of_maps, 1.0); } ratio_vector[j] = Math::mean(ratios.begin(), ratios.end()); } return ratio_vector; }
/** Set CHANNELLEN, self explanatory */ static void set_isupport_channellen(void) { /* uint */ add_isupport_i("CHANNELLEN", feature_int(FEAT_CHANNELLEN)); }
void do_join(struct Client *cptr, struct Client *sptr, struct JoinBuf *join, struct JoinBuf *create, char *chan, char *key, int level) { struct Channel *chptr; struct Gline *gline; /* BADCHANed channel */ if ((gline = gline_find(chan, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, chan); return; } /* Bouncy +L joins */ if (level > feature_int(FEAT_MAX_BOUNCE)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Couldn't join %s ! - Redirection (+L) setting was too bouncy", sptr, chan); return; } if (!(chptr = FindChannel(chan))) { if (((chan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(chan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, chan); return; } if (feature_bool(FEAT_CHANNEL_CREATE_IRCOPONLY) && !IsAnOper(sptr) && !IsChannelService(sptr)) { send_reply(sptr, ERR_NOSUCHCHANNEL, chan); return; } if (!(chptr = get_channel(sptr, chan, CGT_CREATE))) return; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); return; } joinbuf_join(create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { return; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { return; } else { int flags = CHFL_DEOPPED; int err = 0; int excepted = 0; int exceptkli = 0; struct Ban *ban = NULL; if (*chptr->mode.redir && (*chptr->mode.redir != '\0')) { if (chptr->users >= chptr->mode.limit) { if (IsNoLink(sptr)) send_reply(sptr, ERR_LINKCHAN, chptr->chname, chptr->mode.redir); else if (!IsChannelName(chptr->mode.redir) || !strIsIrcCh(chptr->mode.redir)) send_reply(sptr, ERR_NOSUCHCHANNEL, chptr->mode.redir); else { send_reply(sptr, ERR_LINKSET, chptr->chname, chptr->chname, chptr->mode.redir); do_join(cptr, sptr, join, create, chptr->mode.redir, key, level+1); } return; } } if (find_ban(sptr, chptr->exceptlist, EBAN_EXCEPTLIST, 0)) { if (feature_bool(FEAT_CHMODE_e_CHMODEEXCEPTION)) exceptkli = 1; excepted = 1; } /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (feature_bool(FEAT_CHMODE_Z_STRICT) && (chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr)) err = ERR_SSLONLYCHAN; else if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.exmode & EXMODE_PERSIST)) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsXtraOp(sptr)) { /* XtraOp bypasses all other checks. */ } else if ((chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr)) err = ERR_SSLONLYCHAN; else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)) && !exceptkli) err = ERR_BADCHANNELKEY; else if (*chptr->mode.key && feature_bool(FEAT_FLEXIBLEKEYS) && (key && !strcmp(key, chptr->mode.key))) { /* Assume key checked by previous condition was found to be correct and allow join because FEAT_FLEXIBLEKEYS was enabled */ } else if ((chptr->mode.mode & MODE_INVITEONLY) && !exceptkli) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) && !exceptkli) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if ((chptr->mode.exmode & EXMODE_ADMINONLY) && !IsAdmin(sptr)) err = ERR_ADMINONLYCHAN; else if ((chptr->mode.exmode & EXMODE_OPERONLY) && !IsAnOper(sptr)) err = ERR_OPERONLYCHAN; else if ((ban = find_ban(sptr, chptr->banlist, EBAN_NONE, 0)) && !excepted) err = ERR_BANNEDFROMCHAN; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); return; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; case ERR_ADMINONLYCHAN: err = 'a'; break; case ERR_OPERONLYCHAN: err = 'O'; break; case ERR_SSLONLYCHAN: err = 'Z'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } return; } joinbuf_join(join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ }
/** Handle a CONNECT message from an operator. * * \a parv has the following elements: * \li \a parv[1] is the server that should initiate the connection * \li \a parv[2] is the port number to connect on (zero for the default) * \li \a parv[3] is the server to connect to * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int mo_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { unsigned short port; unsigned short tmpport; const char* rule; struct ConfItem* aconf; struct Client* acptr; struct Jupe* ajupe; assert(0 != cptr); assert(cptr == sptr); assert(IsAnOper(sptr)); if (parc < 2) return need_more_params(sptr, "CONNECT"); if (parc > 3) { /* * if parc > 3, we are trying to connect two remote * servers to each other */ if (IsLocOp(sptr)) { /* * Only allow LocOps to make local CONNECTS --SRB */ return send_reply(cptr, ERR_NOPRIVILEGES); } else { struct Client* acptr2; struct Client* acptr3; if (!(acptr3 = find_match_server(parv[3]))) { return send_reply(sptr, ERR_NOSUCHSERVER, parv[3]); } /* * Look for closest matching server * needed for "/connect blah 4400 *"? */ for (acptr2 = acptr3; acptr2 != &me; acptr2 = cli_serv(acptr2)->up) { if (!match(parv[3], cli_name(acptr2))) acptr3 = acptr2; } parv[3] = cli_name(acptr3); if (hunt_server_cmd(sptr, CMD_CONNECT, cptr, 1, "%s %s :%C", 3, parc, parv) != HUNTED_ISME) return 0; } } /* * need to find the conf entry first so we can use the server name from * the conf entry instead of parv[1] to find out if the server is already * present below. --Bleep */ if (0 == (aconf = conf_find_server(parv[1]))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Host %s not listed " "in ircd.conf", sptr, parv[1]); return 0; } /* * use aconf->name to look up the server, see above */ if ((acptr = FindServer(aconf->name))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s already " "exists from %s", sptr, parv[1], cli_name(cli_from(acptr))); return 0; } /* * Evaluate connection rules... If no rules found, allow the * connect. Otherwise stop with the first true rule (ie: rules * are ored together. Oper connects are effected only by D * lines (CRULEALL) not d lines (CRULEAUTO). */ if ((rule = conf_eval_crule(aconf->name, CRULE_ALL))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Disallowed by rule: %s", sptr, rule); return 0; } /* * Check to see if the server is juped; if it is, disallow the connect */ if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s is juped: %s", sptr, JupeServer(ajupe), JupeReason(ajupe)); return 0; } /* * Get port number from user, if given. If not specified, * use the default from configuration structure. If missing * from there, then use the precompiled default. */ port = aconf->address.port; if (parc > 2) { assert(0 != parv[2]); if (0 == (port = atoi(parv[2]))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Invalid port number", sptr); return 0; } } if (0 == port && 0 == (port = feature_int(FEAT_SERVER_PORT))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: missing port number", sptr); return 0; } tmpport = aconf->address.port; aconf->address.port = port; if (connect_server(aconf, sptr)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connecting to %s.", sptr, aconf->name); } else { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connection to %s failed", sptr, aconf->name); } aconf->address.port = tmpport; return 0; }
/** Set MAXCHANNNELS, self explanatory */ static void set_isupport_maxchannels(void) { /* uint */ add_isupport_i("MAXCHANNELS", feature_int(FEAT_MAXCHANNELSPERUSER)); }
/** Set MAXSILES (maximum silences). */ static void set_isupport_maxsiles(void) { add_isupport_i("SILENCE", feature_int(FEAT_MAXSILES)); }
/** Handle a JOIN message from a client connection. * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr; struct JoinBuf join; struct JoinBuf create; struct Gline *gline; char *p = 0; char *chanlist; char *name; char *keys; if (parc < 2 || *parv[1] == '\0') return need_more_params(sptr, "JOIN"); joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime()); chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */ keys = parv[2]; /* remember where keys are */ for (name = ircd_strtok(&p, chanlist, ","); name; name = ircd_strtok(&p, 0, ",")) { char *key = 0; /* If we have any more keys, take the first for this channel. */ if (!BadPtr(keys) && (keys = strchr(key = keys, ','))) *keys++ = '\0'; /* Empty keys are the same as no keys. */ if (key && !key[0]) key = 0; if (!IsChannelName(name) || !strIsIrcCh(name)) { /* bad channel name */ send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (cli_user(sptr)->joined >= feature_int(FEAT_MAXCHANNELSPERUSER) && !HasPriv(sptr, PRIV_CHAN_LIMIT)) { send_reply(sptr, ERR_TOOMANYCHANNELS, name); break; /* no point processing the other channels */ } /* BADCHANed channel */ if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, name); continue; } if (!(chptr = FindChannel(name))) { if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (!(chptr = get_channel(sptr, name, CGT_CREATE))) continue; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); continue; } joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { continue; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { continue; } else { int flags = CHFL_DEOPPED; int err = 0; /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0]) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (chptr->mode.mode & MODE_INVITEONLY) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit)) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if (find_ban(sptr, chptr->banlist)) err = ERR_BANNEDFROMCHAN; else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key))) err = ERR_BADCHANNELKEY; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); continue; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } continue; } joinbuf_join(&join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ } joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */ joinbuf_flush(&create); return 0; }
/** Set MAXBANS, self explanatory */ static void set_isupport_maxbans(void) { add_isupport_i("MAXBANS", feature_int(FEAT_MAXBANS)); }
/** Create a new Z-line and add it to global lists. * \a ipmask must be an IP mask to create an IP-based ban. * * @param[in] cptr Client that sent us the Z-line. * @param[in] sptr Client that originated the Z-line. * @param[in] ipmask Text mask for the Z-line. * @param[in] reason Reason for Z-line. * @param[in] expire Expiration time of Z-line. * @param[in] lastmod Last modification time of Z-line. * @param[in] lifetime Lifetime of Z-line. * @param[in] flags Bitwise combination of ZLINE_* flags. * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal. */ int zline_add(struct Client *cptr, struct Client *sptr, char *ipmask, char *reason, time_t expire, time_t lastmod, time_t lifetime, unsigned int flags) { struct Zline *azline; char imask[HOSTLEN + 2]; char *mask; int tmp; assert(0 != ipmask); assert(0 != reason); assert(((flags & (ZLINE_GLOBAL | ZLINE_LOCAL)) == ZLINE_GLOBAL) || ((flags & (ZLINE_GLOBAL | ZLINE_LOCAL)) == ZLINE_LOCAL)); Debug((DEBUG_DEBUG, "zline_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu " "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), ipmask, reason, expire, lastmod, lifetime, flags)); mask = ipmask; if (sizeof(imask) < ircd_snprintf(0, imask, sizeof(imask), "%s", mask)) return send_reply(sptr, ERR_LONGMASK); else if (MyUser(sptr) || (IsUser(sptr) && flags & ZLINE_LOCAL)) { switch (zline_checkmask(mask)) { case CHECK_OVERRIDABLE: /* oper overrided restriction */ if (flags & ZLINE_OPERFORCE) break; /*FALLTHROUGH*/ case CHECK_REJECTED: return send_reply(sptr, ERR_MASKTOOWIDE, imask); break; } if ((tmp = count_users(imask, flags)) >= feature_int(FEAT_ZLINEMAXUSERCOUNT) && !(flags & ZLINE_OPERFORCE)) return send_reply(sptr, ERR_TOOMANYUSERS, tmp); } if (!check_if_ipmask(ipmask)) return send_reply(sptr, ERR_INVALIDMASK); /* * You cannot set a negative (or zero) expire time, nor can you set an * expiration time for greater than ZLINE_MAX_EXPIRE. */ if (!(flags & ZLINE_FORCE) && (expire <= TStime() || expire > TStime() + ZLINE_MAX_EXPIRE)) { if (!IsServer(sptr) && MyConnect(sptr)) send_reply(sptr, ERR_BADEXPIRE, expire); return 0; } else if (expire <= TStime()) { /* This expired Z-line was forced to be added, so mark it inactive. */ flags &= ~ZLINE_ACTIVE; } if (!lifetime) /* no lifetime set, use expiration time */ lifetime = expire; /* lifetime is already an absolute timestamp */ /* Inform ops... */ sendto_opmask_butone(0, ircd_strncmp(reason, "AUTO", 4) ? SNO_GLINE : SNO_AUTO, "%s adding %s%s ZLINE for %s, expiring at " "%Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), (flags & ZLINE_ACTIVE) ? "" : "deactivated ", (flags & ZLINE_LOCAL) ? "local" : "global", mask, expire, reason); /* and log it */ log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, "%#C adding %s ZLINE for %s, expiring at %Tu: %s", sptr, flags & ZLINE_LOCAL ? "local" : "global", mask, expire, reason); /* make the zline */ azline = make_zline(mask, reason, expire, lastmod, lifetime, flags); /* since we've disabled overlapped Z-line checking, azline should * never be NULL... */ assert(azline); zline_propagate(cptr, sptr, azline); return do_zline(cptr, sptr, azline); /* knock off users if necessary */ }
/** Run engine event loop. * @param[in] gen Lists of generators of various types. */ static void engine_loop(struct Generators* gen) { struct kevent *events; int events_count; struct Socket* sock; struct timespec wait; int nevs; int i; int errcode; size_t codesize; if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20) events_count = 20; events = (struct kevent *)MyMalloc(sizeof(struct kevent) * events_count); while (running) { if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != events_count) { events = (struct kevent *)MyRealloc(events, sizeof(struct kevent) * i); events_count = i; } /* set up the sleep time */ wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1; wait.tv_nsec = 0; Debug((DEBUG_INFO, "kqueue: delay: %Tu (%Tu) %Tu", timer_next(gen), CurrentTime, wait.tv_sec)); /* check for active events */ nevs = kevent(kqueue_id, 0, 0, events, events_count, wait.tv_sec < 0 ? 0 : &wait); CurrentTime = time(0); /* set current time... */ if (nevs < 0) { if (errno != EINTR) { /* ignore kevent interrupts */ /* Log the kqueue error */ log_write(LS_SOCKET, L_ERROR, 0, "kevent() error: %m"); if (!errors++) timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC, ERROR_EXPIRE_TIME); else if (errors > KQUEUE_ERROR_THRESHOLD) /* too many errors... */ exit_schedule(1, 0, 0, "too many kevent errors"); } /* old code did a sleep(1) here; with usage these days, * that may be too expensive */ continue; } for (i = 0; i < nevs; i++) { if (events[i].filter == EVFILT_SIGNAL) { /* it's a signal; deal appropriately */ event_generate(ET_SIGNAL, events[i].udata, events[i].ident); continue; /* skip socket processing loop */ } assert(events[i].filter == EVFILT_READ || events[i].filter == EVFILT_WRITE); sock = sockList[events[i].ident]; if (!sock) /* slots may become empty while processing events */ continue; assert(s_fd(sock) == events[i].ident); gen_ref_inc(sock); /* can't have it going away on us */ Debug((DEBUG_ENGINE, "kqueue: Checking socket %p (fd %d) state %s, " "events %s", sock, s_fd(sock), state_to_name(s_state(sock)), sock_flags(s_events(sock)))); if (s_state(sock) != SS_NOTSOCK) { errcode = 0; /* check for errors on socket */ codesize = sizeof(errcode); if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; /* work around Solaris implementation */ if (errcode) { /* an error occurred; generate an event */ Debug((DEBUG_ENGINE, "kqueue: Error %d on fd %d, socket %p", errcode, s_fd(sock), sock)); event_generate(ET_ERROR, sock, errcode); gen_ref_dec(sock); /* careful not to leak reference counts */ continue; } } switch (s_state(sock)) { case SS_CONNECTING: if (events[i].filter == EVFILT_WRITE) { /* connection completed */ Debug((DEBUG_ENGINE, "kqueue: Connection completed")); event_generate(ET_CONNECT, sock, 0); } break; case SS_LISTENING: if (events[i].filter == EVFILT_READ) { /* connect. to be accept. */ Debug((DEBUG_ENGINE, "kqueue: Ready for accept")); event_generate(ET_ACCEPT, sock, 0); } break; case SS_NOTSOCK: /* doing nothing socket-specific */ case SS_CONNECTED: if (events[i].filter == EVFILT_READ) { /* data on socket */ Debug((DEBUG_ENGINE, "kqueue: EOF or data to be read")); event_generate(events[i].flags & EV_EOF ? ET_EOF : ET_READ, sock, 0); } if (events[i].filter == EVFILT_WRITE) { /* socket writable */ Debug((DEBUG_ENGINE, "kqueue: Data can be written")); event_generate(ET_WRITE, sock, 0); } break; case SS_DATAGRAM: case SS_CONNECTDG: if (events[i].filter == EVFILT_READ) { /* socket readable */ Debug((DEBUG_ENGINE, "kqueue: Datagram to be read")); event_generate(ET_READ, sock, 0); } if (events[i].filter == EVFILT_WRITE) { /* socket writable */ Debug((DEBUG_ENGINE, "kqueue: Datagram can be written")); event_generate(ET_WRITE, sock, 0); } break; } gen_ref_dec(sock); /* we're done with it */ } timer_run(); /* execute any pending timers */ } }
/** Set NICKLEN, self explanatory */ static void set_isupport_nicklen(void) { /* uint */ add_isupport_i("NICKLEN", feature_int(FEAT_NICKLEN)); }