From 0c55e6d24b32f2cc4e2b8106f2f4032e3197c211 Mon Sep 17 00:00:00 2001 From: brain Date: Thu, 15 Dec 2005 13:44:17 +0000 Subject: Moved a ton of user related functions from inspircd.cpp to users.cpp git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@2468 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/commands.h | 1 + include/inspircd.h | 9 -- include/users.h | 17 ++- src/commands.cpp | 4 + src/inspircd.cpp | 400 ------------------------------------------------ src/users.cpp | 436 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 432 insertions(+), 435 deletions(-) diff --git a/include/commands.h b/include/commands.h index 6690d16c0..f05e9dac0 100644 --- a/include/commands.h +++ b/include/commands.h @@ -82,6 +82,7 @@ void handle_server(char **parameters, int pcnt, userrec *user); void handle_loadmodule(char **parameters, int pcnt, userrec *user); void handle_unloadmodule(char **parameters, int pcnt, userrec *user); void handle_commands(char **parameters, int pcnt, userrec *user); +void handle_version(char **parameters, int pcnt, userrec *user); /** Functions for u:lined servers */ diff --git a/include/inspircd.h b/include/inspircd.h index e9d3b10ed..fa8f1e886 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -115,23 +115,14 @@ class InspIRCd /* prototypes */ void force_nickchange(userrec* user,const char* newnick); -void kill_link(userrec *user,const char* r); -void kill_link_silent(userrec *user,const char* r); void call_handler(const char* commandname,char **parameters, int pcnt, userrec *user); bool is_valid_cmd(const char* commandname, int pcnt, userrec * user); int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins); -void AddWhoWas(userrec* u); -void ConnectUser(userrec *user); userrec* ReHashNick(char* Old, char* New); -/* optimization tricks to save us walking the user hash */ -void AddOper(userrec* user); -void DeleteOper(userrec* user); -void handle_version(char **parameters, int pcnt, userrec *user); /* userrec optimization stuff */ void AddServerName(std::string servername); const char* FindServerNamePtr(std::string servername); void* dns_task(void* arg); void process_buffer(const char* cmdbuf,userrec *user); -void FullConnectUser(userrec* user); #endif diff --git a/include/users.h b/include/users.h index dbe1215ea..6e5aba1a2 100644 --- a/include/users.h +++ b/include/users.h @@ -236,23 +236,23 @@ class userrec : public connection /** Returns true if a user is invited to a channel. */ - virtual bool IsInvited(char* channel); + virtual bool IsInvited(irc::string &channel); /** Adds a channel to a users invite list (invites them to a channel) */ - virtual void InviteTo(char* channel); + virtual void InviteTo(irc::string &channel); /** Removes a channel from a users invite list. * This member function is called on successfully joining an invite only channel * to which the user has previously been invited, to clear the invitation. */ - virtual void RemoveInvite(char* channel); + virtual void RemoveInvite(irc::string &channel); /** Returns true or false for if a user can execute a privilaged oper command. * This is done by looking up their oper type from userrec::oper, then referencing * this to their oper classes and checking the commands they can execute. */ - bool HasPermission(char* command); + bool HasPermission(std::string &command); /** Calls read() to read some data for this user using their fd. */ @@ -341,4 +341,13 @@ class WhoWasUser time_t signon; }; +void AddOper(userrec* user); +void DeleteOper(userrec* user); +void kill_link(userrec *user,const char* r); +void kill_link_silent(userrec *user,const char* r); +void AddWhoWas(userrec* u); +void AddClient(int socket, char* host, int port, bool iscached, char* ip); +void FullConnectUser(userrec* user); +void ConnectUser(userrec *user); + #endif diff --git a/src/commands.cpp b/src/commands.cpp index 8cfc4d77b..eb9d12f4e 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -2047,4 +2047,8 @@ void handle_qline(char **parameters, int pcnt, userrec *user) } } +void handle_version(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str()); +} diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 0a1eb14e6..f409fcc18 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -97,16 +97,8 @@ whowas_hash whowas; command_table cmdlist; servernamelist servernames; int BoundPortCount = 0; -std::vector all_opers; char lowermap[255]; - -void AddOper(userrec* user) -{ - log(DEBUG,"Oper added to optimization list"); - all_opers.push_back(user); -} - void AddServerName(std::string servername) { log(DEBUG,"Adding server name: %s",servername.c_str()); @@ -129,19 +121,6 @@ const char* FindServerNamePtr(std::string servername) return FindServerNamePtr(servername); } -void DeleteOper(userrec* user) -{ - for (std::vector::iterator a = all_opers.begin(); a < all_opers.end(); a++) - { - if (*a == user) - { - log(DEBUG,"Oper removed from optimization list"); - all_opers.erase(a); - return; - } - } -} - std::string InspIRCd::GetRevision() { /* w00t got me to replace a bunch of strtok_r @@ -324,107 +303,6 @@ int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start -void kill_link(userrec *user,const char* r) -{ - user_hash::iterator iter = clientlist.find(user->nick); - - char reason[MAXBUF]; - - strncpy(reason,r,MAXBUF); - - if (strlen(reason)>MAXQUIT) - { - reason[MAXQUIT-1] = '\0'; - } - - log(DEBUG,"kill_link: %s '%s'",user->nick,reason); - Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); - log(DEBUG,"closing fd %lu",(unsigned long)user->fd); - - if (user->registered == 7) { - FOREACH_MOD OnUserQuit(user,reason); - WriteCommonExcept(user,"QUIT :%s",reason); - } - - user->FlushWriteBuf(); - - FOREACH_MOD OnUserDisconnect(user); - - if (user->fd > -1) - { - FOREACH_MOD OnRawSocketClose(user->fd); - SE->DelFd(user->fd); - user->CloseSocket(); - } - - // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything - // if they were an oper with +s. - if (user->registered == 7) { - purge_empty_chans(user); - // fix by brain: only show local quits because we only show local connects (it just makes SENSE) - if (user->fd > -1) - WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason); - AddWhoWas(user); - } - - if (iter != clientlist.end()) - { - log(DEBUG,"deleting user hash value %lu",(unsigned long)user); - if (user->fd > -1) - fd_ref_table[user->fd] = NULL; - clientlist.erase(iter); - } - delete user; -} - -void kill_link_silent(userrec *user,const char* r) -{ - user_hash::iterator iter = clientlist.find(user->nick); - - char reason[MAXBUF]; - - strncpy(reason,r,MAXBUF); - - if (strlen(reason)>MAXQUIT) - { - reason[MAXQUIT-1] = '\0'; - } - - log(DEBUG,"kill_link: %s '%s'",user->nick,reason); - Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); - log(DEBUG,"closing fd %lu",(unsigned long)user->fd); - - user->FlushWriteBuf(); - - if (user->registered == 7) { - FOREACH_MOD OnUserQuit(user,reason); - WriteCommonExcept(user,"QUIT :%s",reason); - } - - FOREACH_MOD OnUserDisconnect(user); - - if (user->fd > -1) - { - FOREACH_MOD OnRawSocketClose(user->fd); - SE->DelFd(user->fd); - user->CloseSocket(); - } - - if (user->registered == 7) { - purge_empty_chans(user); - } - - if (iter != clientlist.end()) - { - log(DEBUG,"deleting user hash value %lu",(unsigned long)user); - if (user->fd > -1) - fd_ref_table[user->fd] = NULL; - clientlist.erase(iter); - } - delete user; -} - - InspIRCd::InspIRCd(int argc, char** argv) { Start(); @@ -536,59 +414,6 @@ userrec* ReHashNick(char* Old, char* New) return clientlist[New]; } -/* adds or updates an entry in the whowas list */ -void AddWhoWas(userrec* u) -{ - whowas_hash::iterator iter = whowas.find(u->nick); - WhoWasUser *a = new WhoWasUser(); - strlcpy(a->nick,u->nick,NICKMAX); - strlcpy(a->ident,u->ident,IDENTMAX); - strlcpy(a->dhost,u->dhost,160); - strlcpy(a->host,u->host,160); - strlcpy(a->fullname,u->fullname,MAXGECOS); - strlcpy(a->server,u->server,256); - a->signon = u->signon; - - /* MAX_WHOWAS: max number of /WHOWAS items - * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and - * can be replaced by a newer one - */ - - if (iter == whowas.end()) - { - if (whowas.size() >= (unsigned)WHOWAS_MAX) - { - for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++) - { - // 3600 seconds in an hour ;) - if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600))) - { - // delete the old one - if (i->second) delete i->second; - // replace with new one - i->second = a; - log(DEBUG,"added WHOWAS entry, purged an old record"); - return; - } - } - // no space left and user doesnt exist. Don't leave ram in use! - log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram"); - delete a; - } - else - { - log(DEBUG,"added fresh WHOWAS entry"); - whowas[a->nick] = a; - } - } - else - { - log(DEBUG,"updated WHOWAS entry"); - if (iter->second) delete iter->second; - iter->second = a; - } -} - #ifdef THREADED_DNS void* dns_task(void* arg) { @@ -635,226 +460,6 @@ void* dns_task(void* arg) } #endif -/* add a client connection to the sockets list */ -void AddClient(int socket, char* host, int port, bool iscached, char* ip) -{ - string tempnick; - char tn2[MAXBUF]; - user_hash::iterator iter; - - tempnick = ConvToStr(socket) + "-unknown"; - sprintf(tn2,"%lu-unknown",(unsigned long)socket); - - iter = clientlist.find(tempnick); - - // fix by brain. - // as these nicknames are 'RFC impossible', we can be sure nobody is going to be - // using one as a registered connection. As theyre per fd, we can also safely assume - // that we wont have collisions. Therefore, if the nick exists in the list, its only - // used by a dead socket, erase the iterator so that the new client may reclaim it. - // this was probably the cause of 'server ignores me when i hammer it with reconnects' - // issue in earlier alphas/betas - if (iter != clientlist.end()) - { - userrec* goner = iter->second; - delete goner; - clientlist.erase(iter); - } - - /* - * It is OK to access the value here this way since we know - * it exists, we just created it above. - * - * At NO other time should you access a value in a map or a - * hash_map this way. - */ - clientlist[tempnick] = new userrec(); - - NonBlocking(socket); - log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip); - - clientlist[tempnick]->fd = socket; - strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX); - strlcpy(clientlist[tempnick]->host, host,160); - strlcpy(clientlist[tempnick]->dhost, host,160); - clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName); - strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX); - clientlist[tempnick]->registered = 0; - clientlist[tempnick]->signon = TIME + Config->dns_timeout; - clientlist[tempnick]->lastping = 1; - clientlist[tempnick]->port = port; - strlcpy(clientlist[tempnick]->ip,ip,16); - - // set the registration timeout for this user - unsigned long class_regtimeout = 90; - int class_flood = 0; - long class_threshold = 5; - long class_sqmax = 262144; // 256kb - long class_rqmax = 4096; // 4k - - for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++) - { - if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW)) - { - class_regtimeout = (unsigned long)i->registration_timeout; - class_flood = i->flood; - clientlist[tempnick]->pingmax = i->pingtime; - class_threshold = i->threshold; - class_sqmax = i->sendqmax; - class_rqmax = i->recvqmax; - break; - } - } - - clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout; - clientlist[tempnick]->timeout = TIME+class_regtimeout; - clientlist[tempnick]->flood = class_flood; - clientlist[tempnick]->threshold = class_threshold; - clientlist[tempnick]->sendqmax = class_sqmax; - clientlist[tempnick]->recvqmax = class_rqmax; - - ucrec a; - a.channel = NULL; - a.uc_modes = 0; - for (int i = 0; i < MAXCHANS; i++) - clientlist[tempnick]->chans.push_back(a); - - if (clientlist.size() > Config->SoftLimit) - { - kill_link(clientlist[tempnick],"No more connections allowed"); - return; - } - - if (clientlist.size() >= MAXCLIENTS) - { - kill_link(clientlist[tempnick],"No more connections allowed"); - return; - } - - // this is done as a safety check to keep the file descriptors within range of fd_ref_table. - // its a pretty big but for the moment valid assumption: - // file descriptors are handed out starting at 0, and are recycled as theyre freed. - // therefore if there is ever an fd over 65535, 65536 clients must be connected to the - // irc server at once (or the irc server otherwise initiating this many connections, files etc) - // which for the time being is a physical impossibility (even the largest networks dont have more - // than about 10,000 users on ONE server!) - if ((unsigned)socket > 65534) - { - kill_link(clientlist[tempnick],"Server is full"); - return; - } - - - char* e = matches_exception(ip); - if (!e) - { - char* r = matches_zline(ip); - if (r) - { - char reason[MAXBUF]; - snprintf(reason,MAXBUF,"Z-Lined: %s",r); - kill_link(clientlist[tempnick],reason); - return; - } - } - fd_ref_table[socket] = clientlist[tempnick]; - SE->AddFd(socket,true,X_ESTAB_CLIENT); -} - -/* shows the message of the day, and any other on-logon stuff */ -void FullConnectUser(userrec* user) -{ - stats->statsConnects++; - user->idle_lastmsg = TIME; - log(DEBUG,"ConnectUser: %s",user->nick); - - if ((strcmp(Passwd(user),"")) && (!user->haspassed)) - { - kill_link(user,"Invalid password"); - return; - } - if (IsDenied(user)) - { - kill_link(user,"Unauthorised connection"); - return; - } - - char match_against[MAXBUF]; - snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host); - char* e = matches_exception(match_against); - if (!e) - { - char* r = matches_gline(match_against); - if (r) - { - char reason[MAXBUF]; - snprintf(reason,MAXBUF,"G-Lined: %s",r); - kill_link_silent(user,reason); - return; - } - r = matches_kline(user->host); - if (r) - { - char reason[MAXBUF]; - snprintf(reason,MAXBUF,"K-Lined: %s",r); - kill_link_silent(user,reason); - return; - } - } - - - WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network); - WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host); - WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION); - WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__); - WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION); - // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it... - std::stringstream v; - v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS; - v << " MAXBANS=60 NICKLEN=" << NICKMAX; - v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK="; - v << Config->Network; - std::string data005 = v.str(); - FOREACH_MOD On005Numeric(data005); - // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line... - // so i'd better split it :) - std::stringstream out(data005); - std::string token = ""; - std::string line5 = ""; - int token_counter = 0; - while (!out.eof()) - { - out >> token; - line5 = line5 + token + " "; - token_counter++; - if ((token_counter >= 13) || (out.eof() == true)) - { - WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str()); - line5 = ""; - token_counter = 0; - } - } - ShowMOTD(user); - - // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out - // onto the network and produce 'fake direction' - FOREACH_MOD OnUserConnect(user); - FOREACH_MOD OnGlobalConnect(user); - user->registered = 7; - WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip); -} - - -/* shows the message of the day, and any other on-logon stuff */ -void ConnectUser(userrec *user) -{ - // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on - if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user))) - { - FullConnectUser(user); - } -} - std::string InspIRCd::GetVersionString() { char versiondata[MAXBUF]; @@ -867,11 +472,6 @@ std::string InspIRCd::GetVersionString() return versiondata; } -void handle_version(char **parameters, int pcnt, userrec *user) -{ - WriteServ(user->fd,"351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str()); -} - bool is_valid_cmd(const char* commandname, int pcnt, userrec * user) { diff --git a/src/users.cpp b/src/users.cpp index 35279cee6..06c34955e 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -32,6 +32,7 @@ using namespace std; extern ServerConfig* Config; extern time_t TIME; +std::vector all_opers; userrec::userrec() { @@ -93,12 +94,14 @@ char* userrec::GetFullRealHost() return fresult; } -bool userrec::IsInvited(char* channel) +bool userrec::IsInvited(irc::string &channel) { for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) { - if (i->channel) { - if (!strcasecmp(i->channel,channel)) + if (i->channel) + { + irc::string compare = i->channel; + if (compare == channel) { return true; } @@ -112,36 +115,34 @@ InvitedList* userrec::GetInviteList() return &invites; } -void userrec::InviteTo(char* channel) +void userrec::InviteTo(irc::string &channel) { Invited i; - strlcpy(i.channel,channel,CHANMAX); + i.channel = channel; invites.push_back(i); } -void userrec::RemoveInvite(char* channel) +void userrec::RemoveInvite(std::string &channel) { log(DEBUG,"Removing invites"); - if (channel) + if (invites.size()) { - if (invites.size()) + for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) { - for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) - { - if (i->channel) + if (i->channel) + { + irc::string compare = i->channel; + if (compare == channel) { - if (!strcasecmp(i->channel,channel)) - { - invites.erase(i); - return; - } - } - } - } - } + invites.erase(i); + return; + } + } + } + } } -bool userrec::HasPermission(char* command) +bool userrec::HasPermission(std::string &command) { char TypeName[MAXBUF],Classes[MAXBUF],ClassName[MAXBUF],CommandList[MAXBUF]; char* mycmd; @@ -178,7 +179,7 @@ bool userrec::HasPermission(char* command) mycmd = strtok_r(CommandList," ",&savept2); while (mycmd) { - if ((!strcasecmp(mycmd,command)) || (*mycmd == '*')) + if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*')) { return true; } @@ -301,3 +302,394 @@ std::string userrec::GetWriteError() { return this->WriteError; } + +void AddOper(userrec* user) +{ + log(DEBUG,"Oper added to optimization list"); + all_opers.push_back(user); +} + +void DeleteOper(userrec* user) +{ + for (std::vector::iterator a = all_opers.begin(); a < all_opers.end(); a++) + { + if (*a == user) + { + log(DEBUG,"Oper removed from optimization list"); + all_opers.erase(a); + return; + } + } +} + +void kill_link(userrec *user,const char* r) +{ + user_hash::iterator iter = clientlist.find(user->nick); + + char reason[MAXBUF]; + + strncpy(reason,r,MAXBUF); + + if (strlen(reason)>MAXQUIT) + { + reason[MAXQUIT-1] = '\0'; + } + + log(DEBUG,"kill_link: %s '%s'",user->nick,reason); + Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); + log(DEBUG,"closing fd %lu",(unsigned long)user->fd); + + if (user->registered == 7) { + FOREACH_MOD OnUserQuit(user,reason); + WriteCommonExcept(user,"QUIT :%s",reason); + } + + user->FlushWriteBuf(); + + FOREACH_MOD OnUserDisconnect(user); + + if (user->fd > -1) + { + FOREACH_MOD OnRawSocketClose(user->fd); + SE->DelFd(user->fd); + user->CloseSocket(); + } + + // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything + // if they were an oper with +s. + if (user->registered == 7) { + purge_empty_chans(user); + // fix by brain: only show local quits because we only show local connects (it just makes SENSE) + if (user->fd > -1) + WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason); + AddWhoWas(user); + } + + if (iter != clientlist.end()) + { + log(DEBUG,"deleting user hash value %lu",(unsigned long)user); + if (user->fd > -1) + fd_ref_table[user->fd] = NULL; + clientlist.erase(iter); + } + delete user; +} + +void kill_link_silent(userrec *user,const char* r) +{ + user_hash::iterator iter = clientlist.find(user->nick); + + char reason[MAXBUF]; + + strncpy(reason,r,MAXBUF); + + if (strlen(reason)>MAXQUIT) + { + reason[MAXQUIT-1] = '\0'; + } + + log(DEBUG,"kill_link: %s '%s'",user->nick,reason); + Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); + log(DEBUG,"closing fd %lu",(unsigned long)user->fd); + + user->FlushWriteBuf(); + + if (user->registered == 7) { + FOREACH_MOD OnUserQuit(user,reason); + WriteCommonExcept(user,"QUIT :%s",reason); + } + + FOREACH_MOD OnUserDisconnect(user); + + if (user->fd > -1) + { + FOREACH_MOD OnRawSocketClose(user->fd); + SE->DelFd(user->fd); + user->CloseSocket(); + } + + if (user->registered == 7) { + purge_empty_chans(user); + } + + if (iter != clientlist.end()) + { + log(DEBUG,"deleting user hash value %lu",(unsigned long)user); + if (user->fd > -1) + fd_ref_table[user->fd] = NULL; + clientlist.erase(iter); + } + delete user; +} + + +/* adds or updates an entry in the whowas list */ +void AddWhoWas(userrec* u) +{ + whowas_hash::iterator iter = whowas.find(u->nick); + WhoWasUser *a = new WhoWasUser(); + strlcpy(a->nick,u->nick,NICKMAX); + strlcpy(a->ident,u->ident,IDENTMAX); + strlcpy(a->dhost,u->dhost,160); + strlcpy(a->host,u->host,160); + strlcpy(a->fullname,u->fullname,MAXGECOS); + strlcpy(a->server,u->server,256); + a->signon = u->signon; + + /* MAX_WHOWAS: max number of /WHOWAS items + * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and + * can be replaced by a newer one + */ + + if (iter == whowas.end()) + { + if (whowas.size() >= (unsigned)WHOWAS_MAX) + { + for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++) + { + // 3600 seconds in an hour ;) + if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600))) + { + // delete the old one + if (i->second) delete i->second; + // replace with new one + i->second = a; + log(DEBUG,"added WHOWAS entry, purged an old record"); + return; + } + } + // no space left and user doesnt exist. Don't leave ram in use! + log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram"); + delete a; + } + else + { + log(DEBUG,"added fresh WHOWAS entry"); + whowas[a->nick] = a; + } + } + else + { + log(DEBUG,"updated WHOWAS entry"); + if (iter->second) delete iter->second; + iter->second = a; + } +} + +/* add a client connection to the sockets list */ +void AddClient(int socket, char* host, int port, bool iscached, char* ip) +{ + string tempnick; + char tn2[MAXBUF]; + user_hash::iterator iter; + + tempnick = ConvToStr(socket) + "-unknown"; + sprintf(tn2,"%lu-unknown",(unsigned long)socket); + + iter = clientlist.find(tempnick); + + // fix by brain. + // as these nicknames are 'RFC impossible', we can be sure nobody is going to be + // using one as a registered connection. As theyre per fd, we can also safely assume + // that we wont have collisions. Therefore, if the nick exists in the list, its only + // used by a dead socket, erase the iterator so that the new client may reclaim it. + // this was probably the cause of 'server ignores me when i hammer it with reconnects' + // issue in earlier alphas/betas + if (iter != clientlist.end()) + { + userrec* goner = iter->second; + delete goner; + clientlist.erase(iter); + } + + /* + * It is OK to access the value here this way since we know + * it exists, we just created it above. + * + * At NO other time should you access a value in a map or a + * hash_map this way. + */ + clientlist[tempnick] = new userrec(); + + NonBlocking(socket); + log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip); + + clientlist[tempnick]->fd = socket; + strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX); + strlcpy(clientlist[tempnick]->host, host,160); + strlcpy(clientlist[tempnick]->dhost, host,160); + clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName); + strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX); + clientlist[tempnick]->registered = 0; + clientlist[tempnick]->signon = TIME + Config->dns_timeout; + clientlist[tempnick]->lastping = 1; + clientlist[tempnick]->port = port; + strlcpy(clientlist[tempnick]->ip,ip,16); + + // set the registration timeout for this user + unsigned long class_regtimeout = 90; + int class_flood = 0; + long class_threshold = 5; + long class_sqmax = 262144; // 256kb + long class_rqmax = 4096; // 4k + + for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++) + { + if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW)) + { + class_regtimeout = (unsigned long)i->registration_timeout; + class_flood = i->flood; + clientlist[tempnick]->pingmax = i->pingtime; + class_threshold = i->threshold; + class_sqmax = i->sendqmax; + class_rqmax = i->recvqmax; + break; + } + } + + clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout; + clientlist[tempnick]->timeout = TIME+class_regtimeout; + clientlist[tempnick]->flood = class_flood; + clientlist[tempnick]->threshold = class_threshold; + clientlist[tempnick]->sendqmax = class_sqmax; + clientlist[tempnick]->recvqmax = class_rqmax; + + ucrec a; + a.channel = NULL; + a.uc_modes = 0; + for (int i = 0; i < MAXCHANS; i++) + clientlist[tempnick]->chans.push_back(a); + + if (clientlist.size() > Config->SoftLimit) + { + kill_link(clientlist[tempnick],"No more connections allowed"); + return; + } + + if (clientlist.size() >= MAXCLIENTS) + { + kill_link(clientlist[tempnick],"No more connections allowed"); + return; + } + + // this is done as a safety check to keep the file descriptors within range of fd_ref_table. + // its a pretty big but for the moment valid assumption: + // file descriptors are handed out starting at 0, and are recycled as theyre freed. + // therefore if there is ever an fd over 65535, 65536 clients must be connected to the + // irc server at once (or the irc server otherwise initiating this many connections, files etc) + // which for the time being is a physical impossibility (even the largest networks dont have more + // than about 10,000 users on ONE server!) + if ((unsigned)socket > 65534) + { + kill_link(clientlist[tempnick],"Server is full"); + return; + } + char* e = matches_exception(ip); + if (!e) + { + char* r = matches_zline(ip); + if (r) + { + char reason[MAXBUF]; + snprintf(reason,MAXBUF,"Z-Lined: %s",r); + kill_link(clientlist[tempnick],reason); + return; + } + } + fd_ref_table[socket] = clientlist[tempnick]; + SE->AddFd(socket,true,X_ESTAB_CLIENT); +} + +void FullConnectUser(userrec* user) +{ + stats->statsConnects++; + user->idle_lastmsg = TIME; + log(DEBUG,"ConnectUser: %s",user->nick); + + if ((strcmp(Passwd(user),"")) && (!user->haspassed)) + { + kill_link(user,"Invalid password"); + return; + } + if (IsDenied(user)) + { + kill_link(user,"Unauthorised connection"); + return; + } + + char match_against[MAXBUF]; + snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host); + char* e = matches_exception(match_against); + if (!e) + { + char* r = matches_gline(match_against); + if (r) + { + char reason[MAXBUF]; + snprintf(reason,MAXBUF,"G-Lined: %s",r); + kill_link_silent(user,reason); + return; + } + r = matches_kline(user->host); + if (r) + { + char reason[MAXBUF]; + snprintf(reason,MAXBUF,"K-Lined: %s",r); + kill_link_silent(user,reason); + return; + } + } + + + WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network); + WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host); + WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION); + WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__); + WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION); + // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it... + std::stringstream v; + v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS; + v << " MAXBANS=60 NICKLEN=" << NICKMAX; + v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK="; + v << Config->Network; + std::string data005 = v.str(); + FOREACH_MOD On005Numeric(data005); + // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line... + // so i'd better split it :) + std::stringstream out(data005); + std::string token = ""; + std::string line5 = ""; + int token_counter = 0; + while (!out.eof()) + { + out >> token; + line5 = line5 + token + " "; + token_counter++; + if ((token_counter >= 13) || (out.eof() == true)) + { + WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str()); + line5 = ""; + token_counter = 0; + } + } + ShowMOTD(user); + + // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out + // onto the network and produce 'fake direction' + FOREACH_MOD OnUserConnect(user); + FOREACH_MOD OnGlobalConnect(user); + user->registered = 7; + WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip); +} + + +/* shows the message of the day, and any other on-logon stuff */ +void ConnectUser(userrec *user) +{ + // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on + if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user))) + { + FullConnectUser(user); + } +} + -- cgit v1.2.3