From: peavey Date: Mon, 5 Feb 2007 20:08:51 +0000 (+0000) Subject: Move quitting of clients to a central Cull List, and do quitting outside userrec... X-Git-Tag: v2.0.23~5892 X-Git-Url: https://git.netwichtig.de/gitweb/?a=commitdiff_plain;ds=sidebyside;h=9a52a667163a6abc5b83fd268b55c9062b55131f;p=user%2Fhenk%2Fcode%2Finspircd.git Move quitting of clients to a central Cull List, and do quitting outside userrec and in main loop. git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@6497 e03df62e-2008-0410-955e-edbf42e46eb7 --- diff --git a/include/cull_list.h b/include/cull_list.h index 678329bc2..64e6b3bdb 100644 --- a/include/cull_list.h +++ b/include/cull_list.h @@ -33,29 +33,29 @@ class CullItem : public classbase { private: /** Holds a pointer to the user, - * must be valid and can be a local or remote user. - */ - userrec* user; + * must be valid and can be a local or remote user. + */ + userrec* user; /** Holds the quit reason to use for this user. - */ + */ std::string reason; public: /** Constrcutor. - * Initializes the CullItem with a user pointer - * and their quit reason - * @param u The user to add - * @param r The quit reason of the added user - */ - CullItem(userrec* u, std::string &r); + * Initializes the CullItem with a user pointer + * and their quit reason + * @param u The user to add + * @param r The quit reason of the added user + */ + CullItem(userrec* u, std::string &r); CullItem(userrec* u, const char* r); ~CullItem(); /** Returns a pointer to the user - */ - userrec* GetUser(); + */ + userrec* GetUser(); /** Returns the user's quit reason - */ + */ std::string& GetReason(); }; @@ -75,50 +75,45 @@ class CullItem : public classbase class CullList : public classbase { private: - /** Creator of this CullList - */ - InspIRCd* ServerInstance; - /** Holds a list of users being quit. - * See the information for CullItem for - * more information. - */ - std::vector list; - /** A list of users who have already been - * placed on the list, as a map for fast - * reference. When deleting an item, the - * time_t value stored here must match - * the one of the actual userrec, otherwise - * we don't delete it (its a different user) - */ - std::map exempt; - - /** Check if a user pointer is valid - * (e.g. it exists in the user hash) - */ - bool IsValid(userrec* user); + /** Creator of this CullList + */ + InspIRCd* ServerInstance; + + /** Holds a list of users already added for quick lookup + */ + std::map exempt; + + /** Holds a list of users being quit. + * See the information for CullItem for + * more information. + */ + std::vector list; + public: - /** Constructor. - * Clears the CullList::list and CullList::exempt - * items. - * @param Instance Creator of this CullList object - */ - CullList(InspIRCd* Instance); - /** Adds a user to the cull list for later - * removal via QUIT. - * @param user The user to add - * @param reason The quit reason of the user being added - */ - void AddItem(userrec* user, std::string &reason); - void AddItem(userrec* user, const char* reason); - /** Applies the cull list, quitting all the users - * on the list with their quit reasons all at once. - * This is a very fast operation compared to - * iterating the user list and comparing each one, - * especially if there are multiple comparisons - * to be done, or recursion. - * @returns The number of users removed from IRC. - */ - int Apply(); + /** Constructor. + * Clears the CullList::list and CullList::exempt + * items. + * @param Instance Creator of this CullList object + */ + CullList(InspIRCd* Instance); + + /** Adds a user to the cull list for later + * removal via QUIT. + * @param user The user to add + * @param reason The quit reason of the user being added + */ + void AddItem(userrec* user, std::string &reason); + void AddItem(userrec* user, const char* reason); + + /** Applies the cull list, quitting all the users + * on the list with their quit reasons all at once. + * This is a very fast operation compared to + * iterating the user list and comparing each one, + * especially if there are multiple comparisons + * to be done, or recursion. + * @returns The number of users removed from IRC. + */ + int Apply(); }; #endif diff --git a/include/inspircd.h b/include/inspircd.h index a1184a92a..60a29d5f4 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -25,6 +25,7 @@ #include "socketengine.h" #include "command_parse.h" #include "snomasks.h" +#include "cull_list.h" /** Returned by some functions to indicate failure. */ @@ -47,7 +48,7 @@ enum DebugLevel }; /** - * This define is used in place of strcmp when we + * This define is used in place of strcmp when we * want to check if a char* string contains only one * letter. Pretty fast, its just two compares and an * addition. @@ -296,7 +297,7 @@ class InspIRCd : public classbase /** Holds a string describing the last module error to occur */ char MODERR[MAXBUF]; - + /** Remove a ModuleFactory pointer * @param j Index number of the ModuleFactory to remove */ @@ -521,6 +522,10 @@ class InspIRCd : public classbase */ time_t next_call; + /** Global cull list, will be processed on next iteration + */ + CullList GlobalCulls; + /** Get the current time * Because this only calls time() once every time around the mainloop, * it is much faster than calling time() directly. @@ -629,7 +634,7 @@ class InspIRCd : public classbase * @param text The text to send */ void WriteOpers(const std::string &text); - + /** Find a nickname in the nick hash * @param nick The nickname to find * @return A pointer to the user, or NULL if the user does not exist @@ -705,7 +710,7 @@ class InspIRCd : public classbase /** Send text to all users with a specific set of modes * @param modes The modes to check against, without a +, e.g. 'og' - * @param flags one of WM_OR or WM_AND. If you specify WM_OR, any one of the + * @param flags one of WM_OR or WM_AND. If you specify WM_OR, any one of the * mode characters in the first parameter causes receipt of the message, and * if you specify WM_OR, all the modes must be present. * @param text The text format string to send @@ -1061,7 +1066,7 @@ class InspIRCd : public classbase bool DelELine(const std::string &hostmask); /** Return true if the given parameter is a valid nick!user\@host mask - * @param mask A nick!user\@host masak to match against + * @param mask A nick!user\@host masak to match against * @return True i the mask is valid */ bool IsValidMask(const std::string &mask); diff --git a/include/users.h b/include/users.h index bfe21f116..487bbb2ba 100644 --- a/include/users.h +++ b/include/users.h @@ -11,18 +11,17 @@ * --------------------------------------------------- */ -#ifndef __USERS_H__ -#define __USERS_H__ +#ifndef __USERS_H__ +#define __USERS_H__ #include -#include "inspircd_config.h" +#include "inspircd_config.h" #include "socket.h" #include "channels.h" #include "inspstring.h" #include "connection.h" #include "hashcomp.h" #include "dns.h" -#include "cull_list.h" enum ChanStatus { STATUS_OP = 4, @@ -307,13 +306,13 @@ class userrec : public connection * When complete, these objects set userrec::dns_done to true. */ void StartDNSLookup(); - + /** The users nickname. * An invalid nickname indicates an unregistered connection prior to the NICK command. * Use InspIRCd::IsNick() to validate nicknames. */ char nick[NICKMAX]; - + /** The users ident reply. * Two characters are added to the user-defined limit to compensate for the tilde etc. */ @@ -323,11 +322,11 @@ class userrec : public connection * This usually matches the value of userrec::host. */ char dhost[65]; - + /** The users full name (GECOS). */ char fullname[MAXGECOS+1]; - + /** The user's mode list. * This is NOT a null terminated string! In the 1.1 version of InspIRCd * this is an array of values in a similar way to channel modes. @@ -347,28 +346,28 @@ class userrec : public connection /** Channels this user is on, and the permissions they have there */ UserChanList chans; - + /** The server the user is connected to. */ const char* server; - + /** The user's away message. * If this string is empty, the user is not marked as away. */ char awaymsg[MAXAWAY+1]; - + /** Number of lines the user can place into the buffer * (up to the global NetBufferSize bytes) before they * are disconnected for excess flood */ int flood; - + /** Timestamp of current time + connection class timeout. * This user must send USER/NICK before this timestamp is * reached or they will be disconnected. */ time_t timeout; - + /** The oper type they logged in as, if they are an oper. * This is used to check permissions in operclasses, so that * we can say 'yay' or 'nay' to any commands they issue. @@ -474,14 +473,14 @@ class userrec : public connection * @throw Nothing at present */ userrec(InspIRCd* Instance); - + /** Returns the full displayed host of the user * This member function returns the hostname of the user as seen by other users * on the server, in nick!ident&at;host form. * @return The full masked host of the user */ virtual char* GetFullHost(); - + /** Returns the full real host of the user * This member function returns the hostname of the user as seen by other users * on the server, in nick!ident&at;host form. If any form of hostname cloaking is in operation, @@ -536,25 +535,25 @@ class userrec : public connection * @param value On or off setting of the mode */ void SetMode(unsigned char m, bool value); - + /** Returns true if a user is invited to a channel. * @param channel A channel name to look up * @return True if the user is invited to the given channel */ virtual bool IsInvited(const irc::string &channel); - + /** Adds a channel to a users invite list (invites them to a channel) * @param channel A channel name to add */ virtual void InviteTo(const 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. * @param channel The channel to remove the invite to */ virtual void RemoveInvite(const 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. @@ -679,13 +678,8 @@ class userrec : public connection /** Use this method to fully connect a user. * This will send the message of the day, check G/K/E lines, etc. - * @param Goners If the user is disconnected by this method call, the - * value of 'this' will be pushed onto this CullList. This is used by - * the core to connect many users in rapid succession without invalidating - * iterators. - * @param Goners a CullList to use for failed connections */ - void FullConnect(CullList* Goners); + void FullConnect(); /** Change this users hash key to a new string. * You should not call this function directly. It is used by the core diff --git a/src/cull_list.cpp b/src/cull_list.cpp index b19054b0d..2a022449f 100644 --- a/src/cull_list.cpp +++ b/src/cull_list.cpp @@ -15,24 +15,6 @@ #include "users.h" #include "cull_list.h" -/* - * In current implementation of CullList, this isn't used. It did odd things with a lot of sockets. - */ -bool CullList::IsValid(userrec* user) -{ - time_t esignon = 0; - std::map::iterator es = exempt.find(user); - if (es != exempt.end()) - esignon = es->second; - - for (user_hash::iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++) - { - if (user == u->second) - return (u->second->signon == esignon); - } - return false; -} - CullItem::CullItem(userrec* u, std::string &r) { this->user = u; @@ -67,21 +49,17 @@ CullList::CullList(InspIRCd* Instance) : ServerInstance(Instance) void CullList::AddItem(userrec* user, std::string &reason) { - if (exempt.find(user) == exempt.end()) - { - CullItem item(user,reason); - list.push_back(item); - exempt[user] = user->signon; - } + AddItem(user, reason.c_str()); } + void CullList::AddItem(userrec* user, const char* reason) { if (exempt.find(user) == exempt.end()) { CullItem item(user,reason); list.push_back(item); - exempt[user] = user->signon; + exempt[user] = user; } } @@ -92,8 +70,78 @@ int CullList::Apply() { std::vector::iterator a = list.begin(); - userrec::QuitUser(ServerInstance, a->GetUser(), a->GetReason().c_str()); + user_hash::iterator iter = ServerInstance->clientlist->find(a->GetUser()->nick); + std::map::iterator exemptiter = exempt.find(a->GetUser()); + std::string reason = a->GetReason(); + + if (reason.length() > MAXQUIT - 1) + reason.resize(MAXQUIT - 1); + + if (a->GetUser()->registered != REG_ALL) + if (ServerInstance->unregistered_count) + ServerInstance->unregistered_count--; + + if (IS_LOCAL(a->GetUser())) + { + a->GetUser()->Write("ERROR :Closing link (%s@%s) [%s]",a->GetUser()->ident,a->GetUser()->host,reason.c_str()); + if ((!a->GetUser()->sendq.empty()) && (!(*a->GetUser()->GetWriteError()))) + a->GetUser()->FlushWriteBuf(); + } + + if (a->GetUser()->registered == REG_ALL) + { + a->GetUser()->PurgeEmptyChannels(); + a->GetUser()->WriteCommonExcept("QUIT :%s",reason.c_str()); + FOREACH_MOD_I(ServerInstance,I_OnUserQuit,OnUserQuit(a->GetUser(),reason)); + } + + FOREACH_MOD_I(ServerInstance,I_OnUserDisconnect,OnUserDisconnect(a->GetUser())); + + if (IS_LOCAL(a->GetUser())) + { + if (ServerInstance->Config->GetIOHook(a->GetUser()->GetPort())) + { + try + { + ServerInstance->Config->GetIOHook(a->GetUser()->GetPort())->OnRawSocketClose(a->GetUser()->GetFd()); + } + catch (CoreException& modexcept) + { + ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); + } + } + + ServerInstance->SE->DelFd(a->GetUser()); + a->GetUser()->CloseSocket(); + } + + /* + * this must come before the ServerInstance->SNO->WriteToSnoMaskso that it doesnt try to fill their buffer with anything + * if they were an oper with +sn +qQ. + */ + if (a->GetUser()->registered == REG_ALL) + { + if (IS_LOCAL(a->GetUser())) + ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s!%s@%s [%s]",a->GetUser()->nick,a->GetUser()->ident,a->GetUser()->host,reason.c_str()); + else + ServerInstance->SNO->WriteToSnoMask('Q',"Client exiting on server %s: %s!%s@%s [%s]",a->GetUser()->server,a->GetUser()->nick,a->GetUser()->ident,a->GetUser()->host,reason.c_str()); + a->GetUser()->AddToWhoWas(); + } + + if (iter != ServerInstance->clientlist->end()) + { + if (IS_LOCAL(a->GetUser())) + { + std::vector::iterator x = find(ServerInstance->local_users.begin(),ServerInstance->local_users.end(),a->GetUser()); + if (x != ServerInstance->local_users.end()) + ServerInstance->local_users.erase(x); + } + ServerInstance->clientlist->erase(iter); + DELETE(a->GetUser()); + } + list.erase(list.begin()); + exempt.erase(exemptiter); } return n; } diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 93ce426a7..8f9bb4589 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -48,9 +48,9 @@ void InspIRCd::AddServerName(const std::string &servername) const char* InspIRCd::FindServerNamePtr(const std::string &servername) { servernamelist::iterator iter = find(servernames.begin(), servernames.end(), servername); - + if(iter == servernames.end()) - { + { AddServerName(servername); iter = --servernames.end(); } @@ -248,7 +248,7 @@ void InspIRCd::WritePID(const std::string &filename) /* Leaves us with just the path */ fname = confpath.substr(0, pos) + std::string("/") + fname; } - } + } std::ofstream outfile(fname.c_str()); if (outfile.is_open()) { @@ -269,7 +269,7 @@ std::string InspIRCd::GetRevision() } InspIRCd::InspIRCd(int argc, char** argv) - : ModCount(-1), duration_m(60), duration_h(60*60), duration_d(60*60*24), duration_w(60*60*24*7), duration_y(60*60*24*365) + : ModCount(-1), duration_m(60), duration_h(60*60), duration_d(60*60*24), duration_w(60*60*24*7), duration_y(60*60*24*365), GlobalCulls(this) { int found_ports = 0; FailedPortList pl; @@ -353,7 +353,7 @@ InspIRCd::InspIRCd(int argc, char** argv) Config->Read(true, NULL); this->CheckRoot(); this->Modes = new ModeParser(this); - this->AddServerName(Config->ServerName); + this->AddServerName(Config->ServerName); CheckDie(); InitializeDisabledCommands(Config->DisabledCommands, this); stats->BoundPortCount = BindPorts(true, found_ports, pl); @@ -392,7 +392,7 @@ InspIRCd::InspIRCd(int argc, char** argv) printf("\nERROR: I couldn't bind any ports! Are you sure you didn't start InspIRCd twice?\n"); Exit(EXIT_STATUS_BIND); } - + if (stats->BoundPortCount != (unsigned int)found_ports) { printf("\nWARNING: Not all your client ports could be bound --\nstarting anyway with %ld of %d client ports bound.\n\n", stats->BoundPortCount, found_ports); @@ -843,10 +843,14 @@ void InspIRCd::DoOneIteration(bool process_module_sockets) * file descriptors. The socket engine has everything's * descriptors in its list... dns, modules, users, * servers... so its nice and easy, just one call. - * This will cause any read or write events to be + * This will cause any read or write events to be * dispatched to their handlers. */ SE->DispatchEvents(); + + /* if any users was quit, take them out */ + GlobalCulls.Apply(); + } bool InspIRCd::IsIdent(const char* n) diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index 6fd7785e4..c4abde509 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -88,7 +88,7 @@ InspSocket::InspSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool } return; } - } + } } else { diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 04153dc3c..cb88fdf70 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -42,7 +42,7 @@ bool isin(int port, const std::vector &portlist) for(unsigned int i = 0; i < portlist.size(); i++) if(portlist[i] == port) return true; - + return false; } @@ -61,41 +61,35 @@ public: class ModuleSSLGnuTLS : public Module { - + ConfigReader* Conf; char* dummy; - - CullList* culllist; - + std::vector listenports; - + int inbufsize; issl_session sessions[MAX_DESCRIPTORS]; - + gnutls_certificate_credentials x509_cred; gnutls_dh_params dh_params; - + std::string keyfile; std::string certfile; std::string cafile; std::string crlfile; int dh_bits; - + public: - + ModuleSSLGnuTLS(InspIRCd* Me) : Module::Module(Me) { - - - culllist = new CullList(ServerInstance); - ServerInstance->PublishInterface("InspSocketHook", this); - + // Not rehashable...because I cba to reduce all the sizes of existing buffers. inbufsize = ServerInstance->Config->NetBufferSize; - + gnutls_global_init(); // This must be called once in the program if(gnutls_certificate_allocate_credentials(&x509_cred) != 0) @@ -107,25 +101,25 @@ class ModuleSSLGnuTLS : public Module // Needs the flag as it ignores a plain /rehash OnRehash(NULL,"ssl"); - + // Void return, guess we assume success gnutls_certificate_set_dh_params(x509_cred, dh_params); } - + virtual void OnRehash(userrec* user, const std::string ¶m) { if(param != "ssl") return; - + Conf = new ConfigReader(ServerInstance); - + for(unsigned int i = 0; i < listenports.size(); i++) { ServerInstance->Config->DelIOHook(listenports[i]); } - + listenports.clear(); - + for(int i = 0; i < Conf->Enumerate("bind"); i++) { // For each tag @@ -152,46 +146,46 @@ class ModuleSSLGnuTLS : public Module } } } - + std::string confdir(CONFIG_FILE); // +1 so we the path ends with a / confdir = confdir.substr(0, confdir.find_last_of('/') + 1); - + cafile = Conf->ReadValue("gnutls", "cafile", 0); crlfile = Conf->ReadValue("gnutls", "crlfile", 0); certfile = Conf->ReadValue("gnutls", "certfile", 0); keyfile = Conf->ReadValue("gnutls", "keyfile", 0); dh_bits = Conf->ReadInteger("gnutls", "dhbits", 0, false); - + // Set all the default values needed. if(cafile == "") cafile = "ca.pem"; - + if(crlfile == "") crlfile = "crl.pem"; - + if(certfile == "") certfile = "cert.pem"; - + if(keyfile == "") keyfile = "key.pem"; - + if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096)) dh_bits = 1024; - - // Prepend relative paths with the path to the config directory. + + // Prepend relative paths with the path to the config directory. if(cafile[0] != '/') cafile = confdir + cafile; - + if(crlfile[0] != '/') crlfile = confdir + crlfile; - + if(certfile[0] != '/') certfile = confdir + certfile; - + if(keyfile[0] != '/') keyfile = confdir + keyfile; - + int ret; if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) @@ -203,45 +197,44 @@ class ModuleSSLGnuTLS : public Module // Guessing on the return value of this, manual doesn't say :| if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 certificate and key files '%s' and '%s': %s", certfile.c_str(), keyfile.c_str(), gnutls_strerror(ret)); - + // This may be on a large (once a day or week) timer eventually. GenerateDHParams(); - + DELETE(Conf); } - + void GenerateDHParams() { // Generate Diffie Hellman parameters - for use with DHE // kx algorithms. These should be discarded and regenerated // once a day, once a week or once a month. Depending on the // security requirements. - + int ret; if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0) ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret)); } - + virtual ~ModuleSSLGnuTLS() { gnutls_dh_params_deinit(dh_params); gnutls_certificate_free_credentials(x509_cred); gnutls_global_deinit(); - delete culllist; } - + virtual void OnCleanup(int target_type, void* item) { if(target_type == TYPE_USER) { userrec* user = (userrec*)item; - + if(user->GetExt("ssl", dummy) && isin(user->GetPort(), listenports)) { // User is using SSL, they're a local user, and they're using one of *our* SSL ports. // Potentially there could be multiple SSL modules loaded at once on different ports. - culllist->AddItem(user, "SSL module unloading"); + ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading"); } if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports)) { @@ -252,14 +245,11 @@ class ModuleSSLGnuTLS : public Module } } } - + virtual void OnUnloadModule(Module* mod, const std::string &name) { if(mod == this) { - // We're being unloaded, kill all the users added to the cull list in OnCleanup - culllist->Apply(); - for(unsigned int i = 0; i < listenports.size(); i++) { ServerInstance->Config->DelIOHook(listenports[i]); @@ -270,7 +260,7 @@ class ModuleSSLGnuTLS : public Module } } } - + virtual Version GetVersion() { return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); @@ -327,18 +317,18 @@ class ModuleSSLGnuTLS : public Module virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport) { issl_session* session = &sessions[fd]; - + session->fd = fd; session->inbuf = new char[inbufsize]; session->inbufoffset = 0; - + gnutls_init(&session->sess, GNUTLS_SERVER); gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. gnutls_dh_set_prime_bits(session->sess, dh_bits); - + /* This is an experimental change to avoid a warning on 64bit systems about casting between integer and pointer of different sizes * This needs testing, but it's easy enough to rollback if need be * Old: gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket. @@ -346,7 +336,7 @@ class ModuleSSLGnuTLS : public Module * * With testing this seems to...not work :/ */ - + gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket. Handshake(session); @@ -387,11 +377,11 @@ class ModuleSSLGnuTLS : public Module user->Shrink("ssl_cert"); } } - + virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) { issl_session* session = &sessions[fd]; - + if (!session->sess) { readresult = 0; @@ -402,10 +392,10 @@ class ModuleSSLGnuTLS : public Module if (session->status == ISSL_HANDSHAKING_READ) { // The handshake isn't finished, try to finish it. - + if(!Handshake(session)) { - // Couldn't resume handshake. + // Couldn't resume handshake. return -1; } } @@ -413,9 +403,9 @@ class ModuleSSLGnuTLS : public Module { return -1; } - + // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN. - + if (session->status == ISSL_HANDSHAKEN) { // Is this right? Not sure if the unencrypted data is garaunteed to be the same length. @@ -444,9 +434,9 @@ class ModuleSSLGnuTLS : public Module // Read successfully 'ret' bytes into inbuf + inbufoffset // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf' // 'buffer' is 'count' long - + unsigned int length = ret + session->inbufoffset; - + if(count <= length) { memcpy(buffer, session->inbuf, count); @@ -470,10 +460,10 @@ class ModuleSSLGnuTLS : public Module } else if(session->status == ISSL_CLOSING) readresult = 0; - + return 1; } - + virtual int OnRawSocketWrite(int fd, const char* buffer, int count) { if (!count) @@ -503,9 +493,9 @@ class ModuleSSLGnuTLS : public Module int ret = 0; if(session->status == ISSL_HANDSHAKEN) - { + { ret = gnutls_record_send(session->sess, sendbuffer, count); - + if(ret == 0) CloseSession(session); else if(ret < 0) @@ -518,13 +508,13 @@ class ModuleSSLGnuTLS : public Module session->outbuf = session->outbuf.substr(ret); } } - + /* Who's smart idea was it to return 1 when we havent written anything? * This fucks the buffer up in InspSocket :p */ return ret < 1 ? 0 : ret; } - + // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection virtual void OnWhois(userrec* source, userrec* dest) { @@ -534,7 +524,7 @@ class ModuleSSLGnuTLS : public Module ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick); } } - + virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname) { // check if the linking module wants to know about OUR metadata @@ -549,7 +539,7 @@ class ModuleSSLGnuTLS : public Module } } } - + virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) { // check if its our metadata key, and its associated with a user @@ -563,17 +553,17 @@ class ModuleSSLGnuTLS : public Module } } } - + bool Handshake(issl_session* session) - { + { int ret = gnutls_handshake(session->sess); - + if (ret < 0) { if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { // Handshake needs resuming later, read() or write() would have blocked. - + if(gnutls_record_get_direction(session->sess) == 0) { // gnutls_handshake() wants to read() again. @@ -583,7 +573,7 @@ class ModuleSSLGnuTLS : public Module { // gnutls_handshake() wants to write() again. session->status = ISSL_HANDSHAKING_WRITE; - MakePollWrite(session); + MakePollWrite(session); } } else @@ -592,7 +582,7 @@ class ModuleSSLGnuTLS : public Module CloseSession(session); session->status = ISSL_CLOSING; } - + return false; } else @@ -608,10 +598,10 @@ class ModuleSSLGnuTLS : public Module // Change the seesion state session->status = ISSL_HANDSHAKEN; - + // Finish writing, if any left MakePollWrite(session); - + return true; } } @@ -635,12 +625,12 @@ class ModuleSSLGnuTLS : public Module VerifyCertificate(&sessions[user->GetFd()],user); } } - + void MakePollWrite(issl_session* session) { OnRawSocketWrite(session->fd, NULL, 0); } - + void CloseSession(issl_session* session) { if(session->sess) @@ -648,12 +638,12 @@ class ModuleSSLGnuTLS : public Module gnutls_bye(session->sess, GNUTLS_SHUT_WR); gnutls_deinit(session->sess); } - + if(session->inbuf) { delete[] session->inbuf; } - + session->outbuf.clear(); session->inbuf = NULL; session->sess = NULL; @@ -718,7 +708,7 @@ class ModuleSSLGnuTLS : public Module { certinfo->data.insert(std::make_pair("trusted",ConvToStr(1))); } - + /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. @@ -744,7 +734,7 @@ class ModuleSSLGnuTLS : public Module return; } - /* This is not a real world example, since we only check the first + /* This is not a real world example, since we only check the first * certificate in the given chain. */ @@ -792,11 +782,11 @@ class ModuleSSLGnuTLSFactory : public ModuleFactory ModuleSSLGnuTLSFactory() { } - + ~ModuleSSLGnuTLSFactory() { } - + virtual Module * CreateModule(InspIRCd* Me) { return new ModuleSSLGnuTLS(Me); diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index 9912f3669..2e26d505c 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -44,7 +44,7 @@ bool isin(int port, const std::vector &portlist) for(unsigned int i = 0; i < portlist.size(); i++) if(portlist[i] == port) return true; - + return false; } @@ -70,7 +70,7 @@ public: std::string outbuf; // Buffer for outgoing data that OpenSSL will not take. int fd; bool outbound; - + issl_session() { outbound = false; @@ -92,30 +92,28 @@ static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx) return 1; } - + class ModuleSSLOpenSSL : public Module { - + ConfigReader* Conf; - - CullList* culllist; - + std::vector listenports; - + int inbufsize; issl_session sessions[MAX_DESCRIPTORS]; - + SSL_CTX* ctx; SSL_CTX* clictx; - + char* dummy; - + std::string keyfile; std::string certfile; std::string cafile; // std::string crlfile; std::string dhfile; - + public: InspIRCd* PublicInstance; @@ -123,17 +121,15 @@ class ModuleSSLOpenSSL : public Module ModuleSSLOpenSSL(InspIRCd* Me) : Module::Module(Me), PublicInstance(Me) { - culllist = new CullList(ServerInstance); - ServerInstance->PublishInterface("InspSocketHook", this); - + // Not rehashable...because I cba to reduce all the sizes of existing buffers. inbufsize = ServerInstance->Config->NetBufferSize; - + /* Global SSL library initialization*/ SSL_library_init(); SSL_load_error_strings(); - + /* Build our SSL contexts: * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK. */ @@ -146,21 +142,21 @@ class ModuleSSLOpenSSL : public Module // Needs the flag as it ignores a plain /rehash OnRehash(NULL,"ssl"); } - + virtual void OnRehash(userrec* user, const std::string ¶m) { if (param != "ssl") return; - + Conf = new ConfigReader(ServerInstance); - + for (unsigned int i = 0; i < listenports.size(); i++) { ServerInstance->Config->DelIOHook(listenports[i]); } - + listenports.clear(); - + for (int i = 0; i < Conf->Enumerate("bind"); i++) { // For each tag @@ -187,42 +183,42 @@ class ModuleSSLOpenSSL : public Module } } } - + std::string confdir(CONFIG_FILE); // +1 so we the path ends with a / confdir = confdir.substr(0, confdir.find_last_of('/') + 1); - + cafile = Conf->ReadValue("openssl", "cafile", 0); certfile = Conf->ReadValue("openssl", "certfile", 0); keyfile = Conf->ReadValue("openssl", "keyfile", 0); dhfile = Conf->ReadValue("openssl", "dhfile", 0); - + // Set all the default values needed. if (cafile == "") cafile = "ca.pem"; - + if (certfile == "") certfile = "cert.pem"; - + if (keyfile == "") keyfile = "key.pem"; - + if (dhfile == "") dhfile = "dhparams.pem"; - - // Prepend relative paths with the path to the config directory. + + // Prepend relative paths with the path to the config directory. if (cafile[0] != '/') cafile = confdir + cafile; - + //if(crlfile[0] != '/') // crlfile = confdir + crlfile; - + if (certfile[0] != '/') certfile = confdir + certfile; - + if (keyfile[0] != '/') keyfile = confdir + keyfile; - + if (dhfile[0] != '/') dhfile = confdir + dhfile; @@ -265,7 +261,7 @@ class ModuleSSLOpenSSL : public Module ERR_print_errors_cb(error_callback, this); } } - + fclose(dhpfile); DELETE(Conf); @@ -275,20 +271,19 @@ class ModuleSSLOpenSSL : public Module { SSL_CTX_free(ctx); SSL_CTX_free(clictx); - delete culllist; } - + virtual void OnCleanup(int target_type, void* item) { if (target_type == TYPE_USER) { userrec* user = (userrec*)item; - + if (user->GetExt("ssl", dummy) && IS_LOCAL(user) && isin(user->GetPort(), listenports)) { // User is using SSL, they're a local user, and they're using one of *our* SSL ports. // Potentially there could be multiple SSL modules loaded at once on different ports. - culllist->AddItem(user, "SSL module unloading"); + ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading"); } if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports)) { @@ -299,14 +294,11 @@ class ModuleSSLOpenSSL : public Module } } } - + virtual void OnUnloadModule(Module* mod, const std::string &name) { if (mod == this) { - // We're being unloaded, kill all the users added to the cull list in OnCleanup - culllist->Apply(); - for(unsigned int i = 0; i < listenports.size(); i++) { ServerInstance->Config->DelIOHook(listenports[i]); @@ -317,7 +309,7 @@ class ModuleSSLOpenSSL : public Module } } } - + virtual Version GetVersion() { return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); @@ -375,17 +367,17 @@ class ModuleSSLOpenSSL : public Module virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport) { issl_session* session = &sessions[fd]; - + session->fd = fd; session->inbuf = new char[inbufsize]; - session->inbufoffset = 0; + session->inbufoffset = 0; session->sess = SSL_new(ctx); session->status = ISSL_NONE; session->outbound = false; - + if (session->sess == NULL) return; - + if (SSL_set_fd(session->sess, fd) == 0) { ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd); @@ -436,14 +428,14 @@ class ModuleSSLOpenSSL : public Module virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) { issl_session* session = &sessions[fd]; - + if (!session->sess) { readresult = 0; CloseSession(session); return 1; } - + if (session->status == ISSL_HANDSHAKING) { if (session->rstat == ISSL_READ || session->wstat == ISSL_READ) @@ -451,18 +443,18 @@ class ModuleSSLOpenSSL : public Module // The handshake isn't finished and it wants to read, try to finish it. if (!Handshake(session)) { - // Couldn't resume handshake. + // Couldn't resume handshake. return -1; } } else { - return -1; + return -1; } } // If we resumed the handshake then session->status will be ISSL_OPEN - + if (session->status == ISSL_OPEN) { if (session->wstat == ISSL_READ) @@ -470,11 +462,11 @@ class ModuleSSLOpenSSL : public Module if(DoWrite(session) == 0) return 0; } - + if (session->rstat == ISSL_READ) { int ret = DoRead(session); - + if (ret > 0) { if (count <= session->inbufoffset) @@ -491,12 +483,12 @@ class ModuleSSLOpenSSL : public Module { // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing. memcpy(buffer, session->inbuf, session->inbufoffset); - + readresult = session->inbufoffset; // Zero the offset, as there's nothing there.. session->inbufoffset = 0; } - + return 1; } else @@ -505,10 +497,10 @@ class ModuleSSLOpenSSL : public Module } } } - + return -1; } - + virtual int OnRawSocketWrite(int fd, const char* buffer, int count) { issl_session* session = &sessions[fd]; @@ -520,33 +512,33 @@ class ModuleSSLOpenSSL : public Module } session->outbuf.append(buffer, count); - + if (session->status == ISSL_HANDSHAKING) { // The handshake isn't finished, try to finish it. if (session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE) Handshake(session); } - + if (session->status == ISSL_OPEN) { if (session->rstat == ISSL_WRITE) DoRead(session); - + if (session->wstat == ISSL_WRITE) return DoWrite(session); } - + return 1; } - + int DoWrite(issl_session* session) { if (!session->outbuf.size()) return -1; int ret = SSL_write(session->sess, session->outbuf.data(), session->outbuf.size()); - + if (ret == 0) { CloseSession(session); @@ -555,7 +547,7 @@ class ModuleSSLOpenSSL : public Module else if (ret < 0) { int err = SSL_get_error(session->sess, ret); - + if (err == SSL_ERROR_WANT_WRITE) { session->wstat = ISSL_WRITE; @@ -578,12 +570,12 @@ class ModuleSSLOpenSSL : public Module return ret; } } - + int DoRead(issl_session* session) { // Is this right? Not sure if the unencrypted data is garaunteed to be the same length. // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet. - + int ret = SSL_read(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset); if (ret == 0) @@ -595,7 +587,7 @@ class ModuleSSLOpenSSL : public Module else if (ret < 0) { int err = SSL_get_error(session->sess, ret); - + if (err == SSL_ERROR_WANT_READ) { session->rstat = ISSL_READ; @@ -623,7 +615,7 @@ class ModuleSSLOpenSSL : public Module return ret; } } - + // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection virtual void OnWhois(userrec* source, userrec* dest) { @@ -633,7 +625,7 @@ class ModuleSSLOpenSSL : public Module ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick); } } - + virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname) { // check if the linking module wants to know about OUR metadata @@ -648,7 +640,7 @@ class ModuleSSLOpenSSL : public Module } } } - + virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) { // check if its our metadata key, and its associated with a user @@ -662,7 +654,7 @@ class ModuleSSLOpenSSL : public Module } } } - + bool Handshake(issl_session* session) { int ret; @@ -671,11 +663,11 @@ class ModuleSSLOpenSSL : public Module ret = SSL_connect(session->sess); else ret = SSL_accept(session->sess); - + if (ret < 0) { int err = SSL_get_error(session->sess, ret); - + if (err == SSL_ERROR_WANT_READ) { session->rstat = ISSL_READ; @@ -704,7 +696,7 @@ class ModuleSSLOpenSSL : public Module if (!u->GetExt("ssl", dummy)) u->Extend("ssl", "ON"); } - + session->status = ISSL_OPEN; MakePollWrite(session); @@ -739,12 +731,12 @@ class ModuleSSLOpenSSL : public Module VerifyCertificate(&sessions[user->GetFd()], user); } } - + void MakePollWrite(issl_session* session) { OnRawSocketWrite(session->fd, NULL, 0); } - + void CloseSession(issl_session* session) { if (session->sess) @@ -752,12 +744,12 @@ class ModuleSSLOpenSSL : public Module SSL_shutdown(session->sess); SSL_free(session->sess); } - + if (session->inbuf) { delete[] session->inbuf; } - + session->outbuf.clear(); session->inbuf = NULL; session->sess = NULL; @@ -829,11 +821,11 @@ class ModuleSSLOpenSSLFactory : public ModuleFactory ModuleSSLOpenSSLFactory() { } - + ~ModuleSSLOpenSSLFactory() { } - + virtual Module * CreateModule(InspIRCd* Me) { return new ModuleSSLOpenSSL(Me); diff --git a/src/userprocess.cpp b/src/userprocess.cpp index c6a34561b..fded4a5e3 100644 --- a/src/userprocess.cpp +++ b/src/userprocess.cpp @@ -19,7 +19,6 @@ #include "socketengine.h" #include "inspircd.h" #include "command_parse.h" -#include "cull_list.h" void InspIRCd::ProcessUser(userrec* cu) { @@ -230,20 +229,18 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) return; else { - CullList GlobalGoners(this); - /* Time we actually need to call this again */ const time_t DUMMY_VALUE = 32768; next_call = TIME + DUMMY_VALUE; - + /* XXX: IT IS NOT SAFE TO USE AN ITERATOR HERE. DON'T EVEN THINK ABOUT IT. */ for (unsigned long count2 = 0; count2 != this->local_users.size(); count2++) { if (count2 >= this->local_users.size()) break; - + userrec* curr = this->local_users[count2]; - + if (curr) { /* @@ -252,7 +249,7 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) */ if ((TIME > curr->timeout) && (curr->registered != REG_ALL)) { - GlobalGoners.AddItem(curr,"Registration timeout"); + GlobalCulls.AddItem(curr,"Registration timeout"); continue; } else @@ -260,7 +257,7 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) if ((curr->registered != REG_ALL) && (next_call > (time_t)curr->timeout)) next_call = curr->timeout; } - + /* * user has signed on with USER/NICK/PASS, and dns has completed, all the modules * say this user is ok to proceed, fully connect them. @@ -270,7 +267,7 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) { curr->dns_done = true; this->stats->statsDnsBad++; - curr->FullConnect(&GlobalGoners); + curr->FullConnect(); continue; } else @@ -278,10 +275,10 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) if ((curr->registered == REG_NICKUSER) && (ready) && (next_call > curr->signon)) next_call = curr->signon; } - + if ((curr->dns_done) && (curr->registered == REG_NICKUSER) && (ready)) { - curr->FullConnect(&GlobalGoners); + curr->FullConnect(); continue; } else @@ -289,7 +286,7 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) if ((curr->registered == REG_NICKUSER) && (ready) && (next_call > curr->signon + this->Config->dns_timeout)) next_call = curr->signon + this->Config->dns_timeout; } - + // It's time to PING this user. Send them a ping. if ((TIME > curr->nping) && (curr->registered == REG_ALL)) { @@ -298,8 +295,8 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) { /* Everybody loves boobies. */ time_t time = this->Time(false) - (curr->nping - curr->pingmax); - std::string boobies = "Ping timeout: " + ConvToStr(time) + " second" + (time > 1 ? "s" : ""); - GlobalGoners.AddItem(curr, boobies); + std::string boobies = "Ping timeout: " + ConvToStr(time) + " second" + (time > 1 ? "s" : ""); + GlobalCulls.AddItem(curr, boobies); curr->lastping = 1; curr->nping = TIME+curr->pingmax; continue; @@ -315,7 +312,7 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) } } } - + /* If theres nothing to do, trigger in the next second, something might come up */ time_t delta = next_call - TIME; if (delta == DUMMY_VALUE) @@ -323,9 +320,5 @@ void InspIRCd::DoBackgroundUserStuff(time_t TIME) next_call = TIME + 1; delta = 1; } - - /* Remove all the queued users who are due to be quit, free memory used. */ - GlobalGoners.Apply(); } } - diff --git a/src/users.cpp b/src/users.cpp index d923cdb26..b42eb5e00 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -19,7 +19,6 @@ #include "socketengine.h" #include "wildcard.h" #include "xline.h" -#include "cull_list.h" #include "commands/cmd_whowas.h" static unsigned long already_sent[MAX_DESCRIPTORS] = {0}; @@ -37,7 +36,7 @@ bool InitTypes(ServerConfig* conf, const char* tag) delete[] n->second; } } - + conf->opertypes.clear(); return true; } @@ -52,7 +51,7 @@ bool InitClasses(ServerConfig* conf, const char* tag) delete[] n->second; } } - + conf->operclass.clear(); return true; } @@ -61,7 +60,7 @@ bool DoType(ServerConfig* conf, const char* tag, char** entries, ValueList &valu { const char* TypeName = values[0].GetString(); const char* Classes = values[1].GetString(); - + conf->opertypes[TypeName] = strdup(Classes); return true; } @@ -70,7 +69,7 @@ bool DoClass(ServerConfig* conf, const char* tag, char** entries, ValueList &val { const char* ClassName = values[0].GetString(); const char* CommandList = values[1].GetString(); - + conf->operclass[ClassName] = strdup(CommandList); return true; } @@ -333,7 +332,7 @@ userrec::~userrec() ServerInstance->local_clones.erase(x); } } - + clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString()); if (y != ServerInstance->global_clones.end()) { @@ -402,7 +401,7 @@ void userrec::CloseSocket() shutdown(this->fd,2); close(this->fd); } - + char* userrec::GetFullHost() { if (this->cached_fullhost) @@ -509,7 +508,7 @@ bool userrec::HasPermission(const std::string &command) char* mycmd; char* savept; char* savept2; - + /* * users on remote servers can completely bypass all permissions based checks. * This prevents desyncs when one server has different type/class tags to another. @@ -519,7 +518,7 @@ bool userrec::HasPermission(const std::string &command) */ if (!IS_LOCAL(this)) return true; - + // are they even an oper at all? if (*this->oper) { @@ -566,7 +565,7 @@ bool userrec::AddBuffer(std::string a) try { std::string::size_type i = a.rfind('\r'); - + while (i != std::string::npos) { a.erase(i, 1); @@ -575,14 +574,14 @@ bool userrec::AddBuffer(std::string a) if (a.length()) recvq.append(a); - + if (recvq.length() > (unsigned)this->recvqmax) { this->SetWriteError("RecvQ exceeded"); ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax); return false; } - + return true; } @@ -609,14 +608,14 @@ std::string userrec::GetBuffer() { if (!recvq.length()) return ""; - + /* Strip any leading \r or \n off the string. * Usually there are only one or two of these, * so its is computationally cheap to do. */ while ((*recvq.begin() == '\r') || (*recvq.begin() == '\n')) recvq.erase(recvq.begin()); - + for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++) { /* Find the first complete line, return it as the @@ -643,7 +642,7 @@ void userrec::AddWriteBuf(const std::string &data) { if (*this->GetWriteError()) return; - + if (sendq.length() + data.length() > (unsigned)this->sendqmax) { /* @@ -656,7 +655,7 @@ void userrec::AddWriteBuf(const std::string &data) return; } - try + try { if (data.length() > 512) sendq.append(data.substr(0,510)).append("\r\n"); @@ -786,74 +785,7 @@ void userrec::UnOper() void userrec::QuitUser(InspIRCd* Instance, userrec *user, const std::string &quitreason) { - user_hash::iterator iter = Instance->clientlist->find(user->nick); - std::string reason = quitreason; - - if (reason.length() > MAXQUIT - 1) - reason.resize(MAXQUIT - 1); - - if (user->registered != REG_ALL) - if (Instance->unregistered_count) - Instance->unregistered_count--; - - if (IS_LOCAL(user)) - { - user->Write("ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason.c_str()); - if ((!user->sendq.empty()) && (!(*user->GetWriteError()))) - user->FlushWriteBuf(); - } - - if (user->registered == REG_ALL) - { - user->PurgeEmptyChannels(); - user->WriteCommonExcept("QUIT :%s",reason.c_str()); - FOREACH_MOD_I(Instance,I_OnUserQuit,OnUserQuit(user,reason)); - } - - FOREACH_MOD_I(Instance,I_OnUserDisconnect,OnUserDisconnect(user)); - - if (IS_LOCAL(user)) - { - if (Instance->Config->GetIOHook(user->GetPort())) - { - try - { - Instance->Config->GetIOHook(user->GetPort())->OnRawSocketClose(user->fd); - } - catch (CoreException& modexcept) - { - Instance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); - } - } - - Instance->SE->DelFd(user); - user->CloseSocket(); - } - - /* - * this must come before the ServerInstance->SNO->WriteToSnoMaskso that it doesnt try to fill their buffer with anything - * if they were an oper with +sn +qQ. - */ - if (user->registered == REG_ALL) - { - if (IS_LOCAL(user)) - Instance->SNO->WriteToSnoMask('q',"Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason.c_str()); - else - Instance->SNO->WriteToSnoMask('Q',"Client exiting on server %s: %s!%s@%s [%s]",user->server,user->nick,user->ident,user->host,reason.c_str()); - user->AddToWhoWas(); - } - - if (iter != Instance->clientlist->end()) - { - if (IS_LOCAL(user)) - { - std::vector::iterator x = find(Instance->local_users.begin(),Instance->local_users.end(),user); - if (x != Instance->local_users.end()) - Instance->local_users.erase(x); - } - Instance->clientlist->erase(iter); - DELETE(user); - } + Instance->GlobalCulls.AddItem(user, quitreason.c_str()); } @@ -1006,7 +938,7 @@ unsigned long userrec::LocalCloneCount() return 0; } -void userrec::FullConnect(CullList* Goners) +void userrec::FullConnect() { ServerInstance->stats->statsConnects++; this->idle_lastmsg = ServerInstance->Time(); @@ -1015,25 +947,25 @@ void userrec::FullConnect(CullList* Goners) if ((!a) || (a->GetType() == CC_DENY)) { - Goners->AddItem(this,"Unauthorised connection"); + ServerInstance->GlobalCulls.AddItem(this,"Unauthorised connection"); return; } if ((!a->GetPass().empty()) && (!this->haspassed)) { - Goners->AddItem(this,"Invalid password"); + ServerInstance->GlobalCulls.AddItem(this,"Invalid password"); return; } - + if (this->LocalCloneCount() > a->GetMaxLocal()) { - Goners->AddItem(this, "No more connections allowed from your host via this connect class (local)"); + ServerInstance->GlobalCulls.AddItem(this, "No more connections allowed from your host via this connect class (local)"); ServerInstance->WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString()); return; } else if (this->GlobalCloneCount() > a->GetMaxGlobal()) { - Goners->AddItem(this, "No more connections allowed from your host via this connect class (global)"); + ServerInstance->GlobalCulls.AddItem(this, "No more connections allowed from your host via this connect class (global)"); ServerInstance->WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s",a->GetMaxGlobal(), this->GetIPString()); return; } @@ -1041,22 +973,22 @@ void userrec::FullConnect(CullList* Goners) if (!this->exempt) { GLine* r = ServerInstance->XLines->matches_gline(this); - + if (r) { char reason[MAXBUF]; snprintf(reason,MAXBUF,"G-Lined: %s",r->reason); - Goners->AddItem(this, reason); + ServerInstance->GlobalCulls.AddItem(this, reason); return; } - + KLine* n = ServerInstance->XLines->matches_kline(this); - + if (n) { char reason[MAXBUF]; snprintf(reason,MAXBUF,"K-Lined: %s",n->reason); - Goners->AddItem(this, reason); + ServerInstance->GlobalCulls.AddItem(this, reason); return; } @@ -1140,7 +1072,7 @@ bool userrec::ForceNickChange(const char* newnick) int MOD_RESULT = 0; this->InvalidateCache(); - + FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick)); if (MOD_RESULT) @@ -1148,7 +1080,7 @@ bool userrec::ForceNickChange(const char* newnick) ServerInstance->stats->statsCollisions++; return false; } - + if (ServerInstance->XLines->matches_qline(newnick)) { ServerInstance->stats->statsCollisions++; @@ -1251,7 +1183,7 @@ const char* userrec::GetIPString() case AF_INET6: { static char temp[1024]; - + sockaddr_in6* sin = (sockaddr_in6*)this->ip; inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf)); /* IP addresses starting with a : on irc are a Bad Thing (tm) */ @@ -1292,7 +1224,7 @@ const char* userrec::GetIPString(char* buf) case AF_INET6: { static char temp[1024]; - + sockaddr_in6* sin = (sockaddr_in6*)this->ip; inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf)); /* IP addresses starting with a : on irc are a Bad Thing (tm) */ @@ -1408,7 +1340,7 @@ void userrec::WriteFrom(userrec *user, const std::string &text) char tb[MAXBUF]; snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str()); - + this->Write(std::string(tb)); } @@ -1469,16 +1401,16 @@ void userrec::WriteCommon(const std::string &text) { bool sent_to_at_least_one = false; char tb[MAXBUF]; - + if (this->registered != REG_ALL) return; - + uniq_id++; /* We dont want to be doing this n times, just once */ snprintf(tb,MAXBUF,":%s %s",this->GetFullHost(),text.c_str()); std::string out = tb; - + for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++) { CUList* ulist = v->first->GetUsers(); @@ -1492,7 +1424,7 @@ void userrec::WriteCommon(const std::string &text) } } } - + /* * if the user was not in any channels, no users will receive the text. Make sure the user * receives their OWN message for WriteCommon @@ -1637,16 +1569,16 @@ void userrec::WriteWallOps(const std::string &text) } void userrec::WriteWallOps(const char* text, ...) -{ +{ char textbuffer[MAXBUF]; va_list argsPtr; va_start(argsPtr, text); vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - + va_end(argsPtr); + this->WriteWallOps(std::string(textbuffer)); -} +} /* return 0 or 1 depending if users u and u2 share one or more common channels * (used by QUIT, NICK etc which arent channel specific notices) @@ -1815,17 +1747,17 @@ void userrec::SplitChanList(userrec* dest, const std::string &cl) prefix << this->nick << " " << dest->nick << " :"; line = prefix.str(); int namelen = strlen(ServerInstance->Config->ServerName) + 6; - + for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1) { length = (pos == std::string::npos) ? cl.length() : pos; - + if (line.length() + namelen + length - start > 510) { ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str()); line = prefix.str(); } - + if(pos == std::string::npos) { line.append(cl.substr(start, length - start)); @@ -1836,7 +1768,7 @@ void userrec::SplitChanList(userrec* dest, const std::string &cl) line.append(cl.substr(start, length - start + 1)); } } - + if (line.length()) { ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str()); diff --git a/src/xline.cpp b/src/xline.cpp index b7f32c321..1996925de 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -16,7 +16,6 @@ #include "modules.h" #include "wildcard.h" #include "xline.h" -#include "cull_list.h" /* Version two, now with optimized expiry! * @@ -27,7 +26,7 @@ * items, and the other list holds permanent items (ones which will expire). * Items which are on the permanent list are NEVER checked at all by the * expire_lines() function. - * (2) The temporary xline lists are always kept in strict numerical order, keyed by + * (2) The temporary xline lists are always kept in strict numerical order, keyed by * current time + duration. This means that the line which is due to expire the * soonest is always pointed at by vector::begin(), so a simple while loop can * very efficiently, very quickly and above all SAFELY pick off the first few @@ -69,7 +68,7 @@ bool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &val { const char* reason = values[0].GetString(); const char* ipmask = values[1].GetString(); - + conf->GetInstance()->XLines->add_zline(0,"",reason,ipmask); return true; } @@ -78,7 +77,7 @@ bool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &val { const char* reason = values[0].GetString(); const char* nick = values[1].GetString(); - + conf->GetInstance()->XLines->add_qline(0,"",reason,nick); return true; } @@ -87,7 +86,7 @@ bool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &val { const char* reason = values[0].GetString(); const char* host = values[1].GetString(); - + conf->GetInstance()->XLines->add_kline(0,"",reason,host); return true; } @@ -96,7 +95,7 @@ bool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &val { const char* reason = values[0].GetString(); const char* host = values[1].GetString(); - + conf->GetInstance()->XLines->add_eline(0,"",reason,host); return true; } @@ -129,9 +128,9 @@ bool XLineManager::add_gline(long duration, const char* source,const char* reaso IdentHostPair ih = IdentSplit(hostmask); bool ret = del_gline(hostmask); - + GLine* item = new GLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str()); - + if (duration) { glines.push_back(item); @@ -141,7 +140,7 @@ bool XLineManager::add_gline(long duration, const char* source,const char* reaso { pglines.push_back(item); } - + return !ret; } @@ -414,7 +413,7 @@ GLine* XLineManager::matches_gline(userrec* user, bool permonly) } ELine* XLineManager::matches_exception(userrec* user, bool permonly) -{ +{ if ((elines.empty()) && (pelines.empty())) return NULL; char host2[MAXBUF]; @@ -465,7 +464,7 @@ void XLineManager::gline_set_creation_time(const char* host, time_t create_time) return; } } - return ; + return ; } void XLineManager::eline_set_creation_time(const char* host, time_t create_time) @@ -479,7 +478,7 @@ void XLineManager::eline_set_creation_time(const char* host, time_t create_time) return; } } - for (std::vector::iterator i = pelines.begin(); i != pelines.end(); i++) + for (std::vector::iterator i = pelines.begin(); i != pelines.end(); i++) { if (!strcasecmp(host,(*i)->hostmask)) { @@ -654,7 +653,7 @@ void XLineManager::expire_lines() ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",(*i)->nick,(*i)->source,(*i)->duration); qlines.erase(i); } - + } // applies lines, removing clients and changing nicks etc as applicable @@ -671,7 +670,6 @@ void XLineManager::apply_lines(const int What) if ((!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size())) return; - CullList* Goners = new CullList(ServerInstance); XLine* check = NULL; for (std::vector::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++) { @@ -686,7 +684,7 @@ void XLineManager::apply_lines(const int What) if ((check = matches_gline(u,true))) { snprintf(reason,MAXBUF,"G-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } @@ -695,7 +693,7 @@ void XLineManager::apply_lines(const int What) if ((check = matches_kline(u,true))) { snprintf(reason,MAXBUF,"K-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } @@ -704,7 +702,7 @@ void XLineManager::apply_lines(const int What) if ((check = matches_qline(u->nick,true))) { snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } @@ -713,13 +711,10 @@ void XLineManager::apply_lines(const int What) if ((check = matches_zline(u->GetIPString(),true))) { snprintf(reason,MAXBUF,"Z-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } } - - Goners->Apply(); - DELETE(Goners); } else { @@ -728,8 +723,7 @@ void XLineManager::apply_lines(const int What) if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()) && (!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size())) return; - - CullList* Goners = new CullList(ServerInstance); + XLine* check = NULL; for (std::vector::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++) { @@ -746,7 +740,7 @@ void XLineManager::apply_lines(const int What) if ((check = matches_gline(u))) { snprintf(reason,MAXBUF,"G-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } if ((What & APPLY_KLINES) && (klines.size() || pklines.size())) @@ -754,7 +748,7 @@ void XLineManager::apply_lines(const int What) if ((check = matches_kline(u))) { snprintf(reason,MAXBUF,"K-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } if ((What & APPLY_QLINES) && (qlines.size() || pqlines.size())) @@ -762,7 +756,7 @@ void XLineManager::apply_lines(const int What) if ((check = matches_qline(u->nick))) { snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } if ((What & APPLY_ZLINES) && (zlines.size() || pzlines.size())) @@ -770,13 +764,10 @@ void XLineManager::apply_lines(const int What) if ((check = matches_zline(u->GetIPString()))) { snprintf(reason,MAXBUF,"Z-Lined: %s",check->reason); - Goners->AddItem(u,reason); + ServerInstance->GlobalCulls.AddItem(u,reason); } } } - - Goners->Apply(); - DELETE(Goners); } }