#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
+
#ifdef USE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif
-#include <cstdio>
+
+#ifdef USE_EPOLL
+#include <sys/epoll.h>
+#define EP_DELAY 50
+#endif
+
#include <time.h>
#include <string>
#ifdef GCC3
#include <map>
#include <sstream>
#include <vector>
-#include <errno.h>
#include <deque>
-#include <errno.h>
-#include <unistd.h>
#include <sched.h>
#include "connection.h"
#include "users.h"
#include "xline.h"
#include "inspstring.h"
#include "dnsqueue.h"
-
-#ifdef GCC3
-#define nspace __gnu_cxx
-#else
-#define nspace std
-#endif
+#include "helperfuncs.h"
+#include "hashcomp.h"
int LogLevel = DEFAULT;
char ServerName[MAXBUF];
int WHOWAS_MAX = 100; // default 100 people maximum in the WHOWAS list
int DieDelay = 5;
time_t startup_time = time(NULL);
-int NetBufferSize = 10240; // NetBufferSize used as the buffer size for all read() ops
+int NetBufferSize = 10240; // NetBufferSize used as the buffer size for all read() ops
+int MaxConn = SOMAXCONN; // size of accept() backlog (128 by default on *BSD)
extern int MaxWhoResults;
time_t nb_start = 0;
int dns_timeout = 5;
int kq, lkq, skq;
#endif
-namespace nspace
-{
-#ifdef GCC34
- template<> struct hash<in_addr>
-#else
- template<> struct nspace::hash<in_addr>
+#ifdef USE_EPOLL
+int ep, lep, sep;
#endif
- {
- size_t operator()(const struct in_addr &a) const
- {
- size_t q;
- memcpy(&q,&a,sizeof(size_t));
- return q;
- }
- };
-#ifdef GCC34
- template<> struct hash<string>
-#else
- template<> struct nspace::hash<string>
-#endif
- {
- size_t operator()(const string &s) const
- {
- char a[MAXBUF];
- static struct hash<const char *> strhash;
- strlcpy(a,s.c_str(),MAXBUF);
- strlower(a);
- return strhash(a);
- }
- };
-}
-
-
-struct StrHashComp
-{
-
- bool operator()(const string& s1, const string& s2) const
- {
- char a[MAXBUF],b[MAXBUF];
- strlcpy(a,s1.c_str(),MAXBUF);
- strlcpy(b,s2.c_str(),MAXBUF);
- strlower(a);
- strlower(b);
- return (strcasecmp(a,b) == 0);
- }
-
-};
-
-struct InAddr_HashComp
-{
- bool operator()(const in_addr &s1, const in_addr &s2) const
- {
- size_t q;
- size_t p;
-
- memcpy(&q,&s1,sizeof(size_t));
- memcpy(&p,&s2,sizeof(size_t));
-
- return (q == p);
- }
-
-};
-
-
-typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
-typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
-typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
-typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, StrHashComp> whowas_hash;
+typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
+typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
+typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, irc::InAddr_HashComp> address_cache;
+typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, irc::StrHashComp> whowas_hash;
typedef std::deque<command_t> command_table;
+typedef std::map<std::string,time_t> autoconnects;
// This table references users by file descriptor.
// its an array to make it VERY fast, as all lookups are referenced
chan_hash chanlist;
whowas_hash whowas;
command_table cmdlist;
+autoconnects autoconns;
file_cache MOTD;
file_cache RULES;
address_cache IP;
std::vector<userrec*> all_opers;
-static char already_sent[65536];
-
char lowermap[255];
void AddOper(userrec* user)
}
}
-long GetRevision()
+std::string GetRevision()
{
char Revision[] = "$Revision$";
char *s1 = Revision;
s1 = savept;
v2 = strtok_r(s1," ",&savept);
s1 = savept;
- return (long)(atof(v2)*10000);
+ return std::string(v2);
}
return AdminNick;
}
-void log(int level,char *text, ...)
-{
- char textbuffer[MAXBUF];
- va_list argsPtr;
- time_t rawtime;
- struct tm * timeinfo;
- if (level < LogLevel)
- return;
-
- time(&rawtime);
- timeinfo = localtime (&rawtime);
-
- if (log_file)
- {
- char b[MAXBUF];
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
- strlcpy(b,asctime(timeinfo),MAXBUF);
- b[24] = ':'; // we know this is the end of the time string
- fprintf(log_file,"%s %s\n",b,textbuffer);
- if (nofork)
- {
- // nofork enabled? display it on terminal too
- printf("%s %s\n",b,textbuffer);
- }
- }
-}
-
-void readfile(file_cache &F, const char* fname)
-{
- FILE* file;
- char linebuf[MAXBUF];
-
- log(DEBUG,"readfile: loading %s",fname);
- F.clear();
- file = fopen(fname,"r");
- if (file)
- {
- while (!feof(file))
- {
- fgets(linebuf,sizeof(linebuf),file);
- linebuf[strlen(linebuf)-1]='\0';
- if (linebuf[0] == 0)
- {
- strcpy(linebuf," ");
- }
- if (!feof(file))
- {
- F.push_back(linebuf);
- }
- }
- fclose(file);
- }
- else
- {
- log(DEBUG,"readfile: failed to load file: %s",fname);
- }
- log(DEBUG,"readfile: loaded %s, %lu lines",fname,(unsigned long)F.size());
-}
-
void ReadConfig(bool bail, userrec* user)
{
- char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF];
+ char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF],MCON[MAXBUF];
char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF],pfreq[MAXBUF],thold[MAXBUF],sqmax[MAXBUF],rqmax[MAXBUF];
ConnectClass c;
std::stringstream errstr;
ConfValue("dns","timeout",0,DNT,&config_f);
ConfValue("options","moduledir",0,ModPath,&config_f);
ConfValue("disabled","commands",0,DisabledCommands,&config_f);
+ ConfValue("options","somaxconn",0,MCON,&config_f);
+ MaxConn = atoi(MCON);
+ if (MaxConn > SOMAXCONN)
+ log(DEFAULT,"WARNING: <options:somaxconn> value may be higher than the system-defined SOMAXCONN value!");
NetBufferSize = atoi(NB);
MaxWhoResults = atoi(MW);
dns_timeout = atoi(DNT);
if (!dns_timeout)
dns_timeout = 5;
+ if (!MaxConn)
+ MaxConn = SOMAXCONN;
if (!DNSServer[0])
strlcpy(DNSServer,"127.0.0.1",MAXBUF);
if (!ModPath[0])
}
}
- log(DEFAULT,"Reading K lines,Q lines and Z lines from config...");
- read_xline_defaults();
- log(DEFAULT,"Applying K lines, Q lines and Z lines...");
- apply_lines();
- log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
- if (!bail)
- {
- log(DEFAULT,"Adding and removing modules due to rehash...");
-
- std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
-
- // store the old module names
- for (std::vector<std::string>::iterator t = module_names.begin(); t != module_names.end(); t++)
- {
- old_module_names.push_back(*t);
- }
-
- // get the new module names
- for (int count2 = 0; count2 < ConfValueEnum("module",&config_f); count2++)
- {
- ConfValue("module","name",count2,Value,&config_f);
- new_module_names.push_back(Value);
- }
-
- // now create a list of new modules that are due to be loaded
- // and a seperate list of modules which are due to be unloaded
- for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
- {
- bool added = true;
- for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
- {
- if (*old == *_new)
- added = false;
- }
- if (added)
- added_modules.push_back(*_new);
- }
- for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
- {
- bool removed = true;
- for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
- {
- if (*newm == *oldm)
- removed = false;
- }
- if (removed)
- removed_modules.push_back(*oldm);
- }
- // now we have added_modules, a vector of modules to be loaded, and removed_modules, a vector of modules
- // to be removed.
- int rem = 0, add = 0;
- if (!removed_modules.empty())
- for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
- {
- if (UnloadModule(removing->c_str()))
- {
- WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());
- WriteServ(user->fd,"973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
- rem++;
- }
- else
- {
- WriteServ(user->fd,"972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ModuleError());
- }
- }
- if (!added_modules.empty())
- for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
- {
- if (LoadModule(adding->c_str()))
- {
- WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());
- WriteServ(user->fd,"975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
- add++;
- }
- else
- {
- WriteServ(user->fd,"974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ModuleError());
- }
- }
- log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
- }
-}
-
-/* write formatted text to a socket, in same format as printf
- * New in 1.0 Beta 5 - Nothing is written directly to a users fd any more.
- * Instead, data builds up in the users sendq and each time around the mainloop
- * this data is flushed to the user's socket (see userrec::FlushWriteBuf).
- */
-
-void Write(int sock,char *text, ...)
-{
- if (sock < 0)
- return;
- if (!text)
- {
- log(DEFAULT,"*** BUG *** Write was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF];
- va_list argsPtr;
- char tb[MAXBUF];
- int res;
-
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
- int bytes = snprintf(tb,MAXBUF,"%s\r\n",textbuffer);
- chop(tb);
- if (fd_ref_table[sock])
- {
- int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
- fd_ref_table[sock]->AddWriteBuf(tb);
- statsSent += bytes;
- }
- else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
-}
-
-/* write a server formatted numeric response to a single socket */
-
-void WriteServ(int sock, char* text, ...)
-{
- if (sock < 0)
- return;
- if (!text)
- {
- log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF],tb[MAXBUF];
- int res;
- va_list argsPtr;
- va_start (argsPtr, text);
-
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
- int bytes = snprintf(tb,MAXBUF,":%s %s\r\n",ServerName,textbuffer);
- chop(tb);
- if (fd_ref_table[sock])
- {
- int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
- fd_ref_table[sock]->AddWriteBuf(tb);
- statsSent += bytes;
- }
- else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
-}
-
-/* write text from an originating user to originating user */
-
-void WriteFrom(int sock, userrec *user,char* text, ...)
-{
- if (sock < 0)
- return;
- if ((!text) || (!user))
- {
- log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF],tb[MAXBUF];
- va_list argsPtr;
- int res;
- va_start (argsPtr, text);
-
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
- int bytes = snprintf(tb,MAXBUF,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
- chop(tb);
- if (fd_ref_table[sock])
- {
- int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
- fd_ref_table[sock]->AddWriteBuf(tb);
- statsSent += bytes;
- }
- else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
-}
-
-/* write text to an destination user from a source user (e.g. user privmsg) */
-
-void WriteTo(userrec *source, userrec *dest,char *data, ...)
-{
- if ((!dest) || (!data))
- {
- log(DEFAULT,"*** BUG *** WriteTo was given an invalid parameter");
- return;
- }
- if (dest->fd == FD_MAGIC_NUMBER)
- return;
- char textbuffer[MAXBUF],tb[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, data);
- vsnprintf(textbuffer, MAXBUF, data, argsPtr);
- va_end(argsPtr);
- chop(tb);
-
- // if no source given send it from the server.
- if (!source)
- {
- WriteServ(dest->fd,":%s %s",ServerName,textbuffer);
- }
- else
- {
- WriteFrom(dest->fd,source,"%s",textbuffer);
- }
-}
-
-/* write formatted text from a source user to all users on a channel
- * including the sender (NOT for privmsg, notice etc!) */
-
-void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...)
-{
- if ((!Ptr) || (!user) || (!text))
- {
- log(DEFAULT,"*** BUG *** WriteChannel was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- std::vector<char*> *ulist = Ptr->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if (otheruser->fd != FD_MAGIC_NUMBER)
- WriteTo(user,otheruser,"%s",textbuffer);
- }
-}
-
-/* write formatted text from a source user to all users on a channel
- * including the sender (NOT for privmsg, notice etc!) doesnt send to
- * users on remote servers */
-
-void WriteChannelLocal(chanrec* Ptr, userrec* user, char* text, ...)
-{
- if ((!Ptr) || (!text))
- {
- log(DEFAULT,"*** BUG *** WriteChannel was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- std::vector<char*> *ulist = Ptr->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if ((otheruser->fd != FD_MAGIC_NUMBER) && (otheruser->fd != -1) && (otheruser != user))
- {
- if (!user)
- {
- WriteServ(otheruser->fd,"%s",textbuffer);
- }
- else
- {
- WriteTo(user,otheruser,"%s",textbuffer);
- }
- }
- }
-}
-
-
-void WriteChannelWithServ(char* ServName, chanrec* Ptr, char* text, ...)
-{
- if ((!Ptr) || (!text))
- {
- log(DEFAULT,"*** BUG *** WriteChannelWithServ was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
-
- std::vector<char*> *ulist = Ptr->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if (otheruser->fd != FD_MAGIC_NUMBER)
- WriteServ(otheruser->fd,"%s",textbuffer);
- }
-}
-
-
-/* write formatted text from a source user to all users on a channel except
- * for the sender (for privmsg etc) */
-
-void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...)
-{
- if ((!Ptr) || (!user) || (!text))
- {
- log(DEFAULT,"*** BUG *** ChanExceptSender was given an invalid parameter");
- return;
- }
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- std::vector<char*> *ulist = Ptr->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if ((otheruser->fd != FD_MAGIC_NUMBER) && (user != otheruser))
- WriteFrom(otheruser->fd,user,"%s",textbuffer);
- }
-}
-
-
-std::string GetServerDescription(char* servername)
-{
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),servername))
- {
- return me[j]->connectors[k].GetDescription();
- }
- }
- }
- return ServerDesc; // not a remote server that can be found, it must be me.
- }
-}
-
-
-/* write a formatted string to all users who share at least one common
- * channel, including the source user e.g. for use in NICK */
-
-void WriteCommon(userrec *u, char* text, ...)
-{
- if (!u)
- {
- log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
- return;
- }
-
- if (u->registered != 7) {
- log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- // FIX: Stops a message going to the same person more than once
- bzero(&already_sent,65536);
-
- bool sent_to_at_least_one = false;
-
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
- {
- std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if ((otheruser->fd > 0) && (!already_sent[otheruser->fd]))
- {
- already_sent[otheruser->fd] = 1;
- WriteFrom(otheruser->fd,u,"%s",textbuffer);
- sent_to_at_least_one = true;
- }
- }
- }
- }
- // if the user was not in any channels, no users will receive the text. Make sure the user
- // receives their OWN message for WriteCommon
- if (!sent_to_at_least_one)
- {
- WriteFrom(u->fd,u,"%s",textbuffer);
- }
-}
-
-/* write a formatted string to all users who share at least one common
- * channel, NOT including the source user e.g. for use in QUIT */
-
-void WriteCommonExcept(userrec *u, char* text, ...)
-{
- if (!u)
- {
- log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
- return;
- }
-
- if (u->registered != 7) {
- log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- bzero(&already_sent,65536);
-
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
- {
- std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if (u != otheruser)
- {
- if ((otheruser->fd > 0) && (!already_sent[otheruser->fd]))
- {
- already_sent[otheruser->fd] = 1;
- WriteFrom(otheruser->fd,u,"%s",textbuffer);
- }
- }
- }
- }
- }
-}
-
-void WriteOpers(char* text, ...)
-{
- if (!text)
- {
- log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
- {
- userrec* a = *i;
- if ((a) && (a->fd != FD_MAGIC_NUMBER))
- {
- if (strchr(a->modes,'s'))
- {
- // send server notices to all with +s
- WriteServ(a->fd,"NOTICE %s :%s",a->nick,textbuffer);
- }
- }
- }
-}
-
-void NoticeAllOpers(userrec *source, bool local_only, char* text, ...)
-{
- if ((!text) || (!source))
- {
- log(DEFAULT,"*** BUG *** NoticeAllOpers was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
- {
- userrec* a = *i;
- if ((a) && (a->fd != FD_MAGIC_NUMBER))
- {
- if (strchr(a->modes,'s'))
- {
- // send server notices to all with +s
- WriteServ(a->fd,"NOTICE %s :*** Notice From %s: %s",a->nick,source->nick,textbuffer);
- }
- }
- }
-
- if (!local_only)
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"V %s @* :%s",source->nick,textbuffer);
- NetSendToAll(buffer);
- }
-}
-
-// returns TRUE of any users on channel C occupy server 'servername'.
-
-bool ChanAnyOnThisServer(chanrec *c,char* servername)
-{
- log(DEBUG,"ChanAnyOnThisServer");
-
- std::vector<char*> *ulist = c->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* user = (userrec*)o;
- if (!strcasecmp(user->server,servername))
- return true;
- }
- return false;
-}
-
-// returns true if user 'u' shares any common channels with any users on server 'servername'
-
-bool CommonOnThisServer(userrec* u,const char* servername)
-{
- log(DEBUG,"ChanAnyOnThisServer");
-
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
- {
- std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* user = (userrec*)o;
- if (!strcasecmp(user->server,servername))
- return true;
- }
- }
- }
- return false;
-}
-
-
-void NetSendToCommon(userrec* u, char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToCommon: '%s' '%s'",u->nick,s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (CommonOnThisServer(u,me[j]->connectors[k].GetServerName().c_str()))
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-
-void NetSendToAll(char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToAll: '%s'",s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
-}
-
-void NetSendToAllAlive(char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToAllAlive: '%s'",s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (me[j]->connectors[k].GetState() != STATE_DISCONNECTED)
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- else
- {
- log(DEBUG,"%s is dead, not sending to it.",me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-
-void NetSendToOne(char* target,char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToOne: '%s' '%s'",target,s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-void NetSendToAllExcept(const char* target,char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-
-void WriteMode(const char* modes, int flags, const char* text, ...)
-{
- if ((!text) || (!modes) || (!flags))
- {
- log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
- int modelen = strlen(modes);
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
- {
- bool send_to_user = false;
-
- if (flags == WM_AND)
- {
- send_to_user = true;
- for (int n = 0; n < modelen; n++)
- {
- if (!hasumode(i->second,modes[n]))
- {
- send_to_user = false;
- break;
- }
- }
- }
- else if (flags == WM_OR)
- {
- send_to_user = false;
- for (int n = 0; n < modelen; n++)
- {
- if (hasumode(i->second,modes[n]))
- {
- send_to_user = true;
- break;
- }
- }
- }
-
- if (send_to_user)
- {
- WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
- }
- }
- }
-}
-
-
-void NoticeAll(userrec *source, bool local_only, char* text, ...)
-{
- if ((!text) || (!source))
- {
- log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
- {
- WriteFrom(i->second->fd,source,"NOTICE $* :%s",textbuffer);
- }
- }
+ log(DEFAULT,"Reading K lines,Q lines and Z lines from config...");
+ read_xline_defaults();
+ log(DEFAULT,"Applying K lines, Q lines and Z lines...");
+ apply_lines();
- if (!local_only)
+ autoconns.clear();
+ for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"V %s * :%s",source->nick,textbuffer);
- NetSendToAll(buffer);
+ char Link_ServerName[MAXBUF],Link_AConn[MAXBUF];
+ ConfValue("link","name",i,Link_ServerName,&config_f);
+ ConfValue("link","autoconnect",i,Link_AConn,&config_f);
+ if (strcmp(Link_AConn,""))
+ {
+ autoconns[std::string(Link_ServerName)] = atoi(Link_AConn) + time(NULL);
+ }
}
-}
-
-void WriteWallOps(userrec *source, bool local_only, char* text, ...)
-{
- if ((!text) || (!source))
- {
- log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
- {
- if (strchr(i->second->modes,'w'))
- {
- WriteTo(source,i->second,"WALLOPS :%s",textbuffer);
- }
- }
- }
-
- if (!local_only)
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"@ %s :%s",source->nick,textbuffer);
- NetSendToAll(buffer);
- }
-}
-
-/* convert a string to lowercase. Note following special circumstances
- * taken from RFC 1459. Many "official" server branches still hold to this
- * rule so i will too;
- *
- * Because of IRC's scandanavian origin, the characters {}| are
- * considered to be the lower case equivalents of the characters []\,
- * respectively. This is a critical issue when determining the
- * equivalence of two nicknames.
- */
-
-void strlower(char *n)
-{
- if (n)
- {
- for (char* t = n; *t; t++)
- *t = lowermap[*t];
- }
-}
-
-
-
-/* Find a user record by nickname and return a pointer to it */
-
-userrec* Find(std::string nick)
-{
- user_hash::iterator iter = clientlist.find(nick);
-
- if (iter == clientlist.end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
-
-/* find a channel record by channel name and return a pointer to it */
-chanrec* FindChan(const char* chan)
-{
- if (!chan)
+ log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
+ if (!bail)
{
- log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
- return NULL;
- }
-
- chan_hash::iterator iter = chanlist.find(chan);
-
- if (iter == chanlist.end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
+ log(DEFAULT,"Adding and removing modules due to rehash...");
+ std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
-long GetMaxBans(char* name)
-{
- char CM[MAXBUF];
- for (int count = 0; count < ConfValueEnum("banlist",&config_f); count++)
- {
- ConfValue("banlist","chan",count,CM,&config_f);
- if (match(name,CM))
+ // store the old module names
+ for (std::vector<std::string>::iterator t = module_names.begin(); t != module_names.end(); t++)
{
- ConfValue("banlist","limit",count,CM,&config_f);
- return atoi(CM);
+ old_module_names.push_back(*t);
}
- }
- return 64;
-}
-
-void purge_empty_chans(userrec* u)
-{
-
- int go_again = 1, purge = 0;
-
- // firstly decrement the count on each channel
- for (int f = 0; f < MAXCHANS; f++)
- {
- if (u->chans[f].channel)
+ // get the new module names
+ for (int count2 = 0; count2 < ConfValueEnum("module",&config_f); count2++)
{
- u->chans[f].channel->DelUser((char*)u);
+ ConfValue("module","name",count2,Value,&config_f);
+ new_module_names.push_back(Value);
}
- }
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
+ // now create a list of new modules that are due to be loaded
+ // and a seperate list of modules which are due to be unloaded
+ for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
{
- if (!usercount(u->chans[i].channel))
- {
- chan_hash::iterator i2 = chanlist.find(u->chans[i].channel->name);
- /* kill the record */
- if (i2 != chanlist.end())
- {
- log(DEBUG,"del_channel: destroyed: %s",i2->second->name);
- if (i2->second)
- delete i2->second;
- chanlist.erase(i2);
- go_again = 1;
- purge++;
- u->chans[i].channel = NULL;
- }
- }
- else
+ bool added = true;
+ for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
{
- log(DEBUG,"skipped purge for %s",u->chans[i].channel->name);
+ if (*old == *_new)
+ added = false;
}
+ if (added)
+ added_modules.push_back(*_new);
}
- }
- log(DEBUG,"completed channel purge, killed %lu",(unsigned long)purge);
-
- DeleteOper(u);
-}
-
-
-char scratch[MAXBUF];
-char sparam[MAXBUF];
-
-char* chanmodes(chanrec *chan)
-{
- if (!chan)
- {
- log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
- strcpy(scratch,"");
- return scratch;
- }
-
- strcpy(scratch,"");
- strcpy(sparam,"");
- if (chan->binarymodes & CM_NOEXTERNAL)
- {
- strlcat(scratch,"n",MAXMODES);
- }
- if (chan->binarymodes & CM_TOPICLOCK)
- {
- strlcat(scratch,"t",MAXMODES);
- }
- if (chan->key[0])
- {
- strlcat(scratch,"k",MAXMODES);
- }
- if (chan->limit)
- {
- strlcat(scratch,"l",MAXMODES);
- }
- if (chan->binarymodes & CM_INVITEONLY)
- {
- strlcat(scratch,"i",MAXMODES);
- }
- if (chan->binarymodes & CM_MODERATED)
- {
- strlcat(scratch,"m",MAXMODES);
- }
- if (chan->binarymodes & CM_SECRET)
- {
- strlcat(scratch,"s",MAXMODES);
- }
- if (chan->binarymodes & CM_PRIVATE)
- {
- strlcat(scratch,"p",MAXMODES);
- }
- if (chan->key[0])
- {
- strlcat(sparam," ",MAXBUF);
- strlcat(sparam,chan->key,MAXBUF);
- }
- if (chan->limit)
- {
- char foo[24];
- sprintf(foo," %lu",(unsigned long)chan->limit);
- strlcat(sparam,foo,MAXBUF);
- }
- if (*chan->custom_modes)
- {
- strlcat(scratch,chan->custom_modes,MAXMODES);
- for (int z = 0; chan->custom_modes[z] != 0; z++)
+ for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
{
- std::string extparam = chan->GetModeParameter(chan->custom_modes[z]);
- if (extparam != "")
+ bool removed = true;
+ for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
{
- strlcat(sparam," ",MAXBUF);
- strlcat(sparam,extparam.c_str(),MAXBUF);
+ if (*newm == *oldm)
+ removed = false;
}
+ if (removed)
+ removed_modules.push_back(*oldm);
}
- }
- log(DEBUG,"chanmodes: %s %s%s",chan->name,scratch,sparam);
- strlcat(scratch,sparam,MAXMODES);
- return scratch;
-}
-
-
-/* compile a userlist of a channel into a string, each nick seperated by
- * spaces and op, voice etc status shown as @ and + */
-
-void userlist(userrec *user,chanrec *c)
-{
- if ((!c) || (!user))
- {
- log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
- return;
- }
-
- snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
-
- std::vector<char*> *ulist = c->GetUsers();
- for (int i = 0; i < ulist->size(); i++)
- {
- char* o = (*ulist)[i];
- userrec* otheruser = (userrec*)o;
- if ((!has_channel(user,c)) && (strchr(otheruser->modes,'i')))
- {
- /* user is +i, and source not on the channel, does not show
- * nick in NAMES list */
- continue;
- }
- strlcat(list,cmode(otheruser,c),MAXBUF);
- strlcat(list,otheruser->nick,MAXBUF);
- strlcat(list," ",MAXBUF);
- if (strlen(list)>(480-NICKMAX))
+ // now we have added_modules, a vector of modules to be loaded, and removed_modules, a vector of modules
+ // to be removed.
+ int rem = 0, add = 0;
+ if (!removed_modules.empty())
+ for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
{
- /* list overflowed into
- * multiple numerics */
- WriteServ(user->fd,"%s",list);
- snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
+ if (UnloadModule(removing->c_str()))
+ {
+ WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());
+ WriteServ(user->fd,"973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
+ rem++;
+ }
+ else
+ {
+ WriteServ(user->fd,"972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ModuleError());
+ }
}
- }
- /* if whats left in the list isnt empty, send it */
- if (list[strlen(list)-1] != ':')
- {
- WriteServ(user->fd,"%s",list);
- }
-}
-
-/* return a count of the users on a specific channel accounting for
- * invisible users who won't increase the count. e.g. for /LIST */
-
-int usercount_i(chanrec *c)
-{
- int count = 0;
-
- if (!c)
- {
- log(DEFAULT,"*** BUG *** usercount_i was given an invalid parameter");
- return 0;
- }
-
- strcpy(list,"");
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if (i->second)
+ if (!added_modules.empty())
+ for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
{
- if (has_channel(i->second,c))
+ if (LoadModule(adding->c_str()))
{
- if (isnick(i->second->nick))
- {
- if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
- {
- /* user is +i, and source not on the channel, does not show
- * nick in NAMES list */
- continue;
- }
- count++;
- }
+ WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());
+ WriteServ(user->fd,"975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
+ add++;
+ }
+ else
+ {
+ WriteServ(user->fd,"974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ModuleError());
}
}
+ log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
}
- log(DEBUG,"usercount_i: %s %lu",c->name,(unsigned long)count);
- return count;
-}
-
-
-int usercount(chanrec *c)
-{
- if (!c)
- {
- log(DEFAULT,"*** BUG *** usercount was given an invalid parameter");
- return 0;
- }
- int count = c->GetUserCounter();
- log(DEBUG,"usercount: %s %lu",c->name,(unsigned long)count);
- return count;
}
NetSendToAll(buffer);
}
+ user->FlushWriteBuf();
+
FOREACH_MOD OnUserDisconnect(user);
if (user->fd > -1)
log(DEBUG,"kqueue: Failed to remove user from queue!");
}
#endif
- shutdown(user->fd,2);
- close(user->fd);
- }
-
- if (user->registered == 7) {
- WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
- AddWhoWas(user);
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = user->fd;
+ int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List deletion failure!");
+ }
+#endif
+ 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);
- }
+ WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
+ AddWhoWas(user);
+ }
if (iter != clientlist.end())
{
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);
WriteCommonExcept(user,"QUIT :%s",reason);
log(DEBUG,"kqueue: Failed to remove user from queue!");
}
#endif
- shutdown(user->fd,2);
- close(user->fd);
- }
-
- 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;
-}
-
-
-
-// looks up a users password for their connection class (<ALLOW>/<DENY> tags)
-
-char* Passwd(userrec *user)
-{
- for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
- {
- if (match(user->host,i->host) && (i->type == CC_ALLOW))
- {
- return i->pass;
- }
- }
- return "";
-}
-
-bool IsDenied(userrec *user)
-{
- for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
- {
- if (match(user->host,i->host) && (i->type == CC_DENY))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-/* sends out an error notice to all connected clients (not to be used
- * lightly!) */
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = user->fd;
+ int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List deletion failure!");
+ }
+#endif
+ user->CloseSocket();
+ }
-void send_error(char *s)
-{
- log(DEBUG,"send_error: %s",s);
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
+ if (user->registered == 7) {
+ purge_empty_chans(user);
+ }
+
+ if (iter != clientlist.end())
{
- if (isnick(i->second->nick))
- {
- WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
- }
- else
- {
- // fix - unregistered connections receive ERROR, not NOTICE
- Write(i->second->fd,"ERROR :%s",s);
- }
+ log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
+ if (user->fd > -1)
+ fd_ref_table[user->fd] = NULL;
+ clientlist.erase(iter);
}
-}
-
-void Error(int status)
-{
- signal (SIGALRM, SIG_IGN);
- signal (SIGPIPE, SIG_IGN);
- signal (SIGTERM, SIG_IGN);
- signal (SIGABRT, SIG_IGN);
- signal (SIGSEGV, SIG_IGN);
- signal (SIGURG, SIG_IGN);
- signal (SIGKILL, SIG_IGN);
- log(DEFAULT,"*** fell down a pothole in the road to perfection ***");
- send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
- Exit(status);
+ delete user;
}
}
fd_ref_table[socket] = clientlist[tempnick];
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ log(DEBUG,"epoll: Adduser to events, ep=%d socket=%d",ep,socket);
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = socket;
+ int i = epoll_ctl(ep, EPOLL_CTL_ADD, socket, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List insertion failure!");
+ }
+#endif
#ifdef USE_KQUEUE
struct kevent ke;
log(DEBUG,"kqueue: Add user to events, kq=%d socket=%d",kq,socket);
int i = kevent(kq, &ke, 1, 0, 0, NULL);
if (i == -1)
{
- switch (errno)
- {
- case EACCES:
- log(DEBUG,"kqueue: EACCES");
- break;
- case EFAULT:
- log(DEBUG,"kqueue: EFAULT");
- break;
- case EBADF:
- log(DEBUG,"kqueue: EBADF=%d",ke.ident);
- break;
- case EINTR:
- log(DEBUG,"kqueue: EINTR");
- break;
- case EINVAL:
- log(DEBUG,"kqueue: EINVAL");
- break;
- case ENOENT:
- log(DEBUG,"kqueue: ENOENT");
- break;
- case ENOMEM:
- log(DEBUG,"kqueue: ENOMEM");
- break;
- case ESRCH:
- log(DEBUG,"kqueue: ESRCH");
- break;
- default:
- log(DEBUG,"kqueue: UNKNOWN!");
- break;
- }
- log(DEBUG,"kqueue: Failed to add user to queue!");
+ log(DEBUG,"kqueue: List insertion failure!");
}
#endif
}
-// this function counts all users connected, wether they are registered or NOT.
-int usercnt(void)
-{
- return clientlist.size();
-}
-
-// this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
-int registered_usercount(void)
-{
- int c = 0;
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second->fd) && (isnick(i->second->nick))) c++;
- }
- return c;
-}
-
-int usercount_invisible(void)
-{
- int c = 0;
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
- }
- return c;
-}
-
-int usercount_opers(void)
-{
- int c = 0;
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
- }
- return c;
-}
-
-int usercount_unknown(void)
-{
- int c = 0;
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second->fd) && (i->second->registered != 7))
- c++;
- }
- return c;
-}
-
-long chancount(void)
-{
- return chanlist.size();
-}
-
-long count_servs(void)
-{
- int c = 0;
- for (int i = 0; i < 32; i++)
- {
- if (me[i] != NULL)
- {
- for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
- {
- if (strcasecmp(j->GetServerName().c_str(),ServerName))
- {
- c++;
- }
- }
- }
- }
- return c;
-}
-
-long servercount(void)
-{
- return count_servs()+1;
-}
-
-long local_count()
-{
- int c = 0;
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,ServerName))) c++;
- }
- return c;
-}
-
-
-void ShowMOTD(userrec *user)
-{
- char buf[65536];
- std::string WholeMOTD = "";
- if (!MOTD.size())
- {
- WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
- return;
- }
- snprintf(buf,65535,":%s 375 %s :- %s message of the day\r\n", ServerName, user->nick, ServerName);
- WholeMOTD = WholeMOTD + buf;
- for (int i = 0; i != MOTD.size(); i++)
- {
- snprintf(buf,65535,":%s 372 %s :- %s\r\n", ServerName, user->nick, MOTD[i].c_str());
- WholeMOTD = WholeMOTD + buf;
- }
- snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick);
- WholeMOTD = WholeMOTD + buf;
- // only one write operation
- user->AddWriteBuf(WholeMOTD);
- statsSent += WholeMOTD.length();
-}
-
-void ShowRULES(userrec *user)
-{
- if (!RULES.size())
- {
- WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
- return;
- }
- WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
- for (int i = 0; i != RULES.size(); i++)
- {
- WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
- }
- WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
-}
-
/* shows the message of the day, and any other on-logon stuff */
void FullConnectUser(userrec* user)
{
}
-// this returns 1 when all modules are satisfied that the user should be allowed onto the irc server
-// (until this returns true, a user will block in the waiting state, waiting to connect up to the
-// registration timeout maximum seconds)
-bool AllModulesReportReady(userrec* user)
-{
- for (int i = 0; i <= MODCOUNT; i++)
- {
- int res = modules[i]->OnCheckReady(user);
- if (!res)
- return false;
- }
- return true;
-}
-
/* shows the message of the day, and any other on-logon stuff */
void ConnectUser(userrec *user)
{
s1 = savept;
#ifdef USE_KQUEUE
char socketengine[] = "kqueue";
-#else
+#endif
+#ifdef USE_SELECT
char socketengine[] = "select";
+#endif
+#ifdef USE_EPOLL
+ char socketengine[] = "epoll";
#endif
snprintf(versiondata,MAXBUF,"%s Rev. %s %s :%s (O=%lu) [SE=%s]",VERSION,v2,ServerName,SYSTEM,(unsigned long)OPTIMISATION,socketengine);
return versiondata;
-char islast(const char* s)
-{
- char c = '`';
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
- {
- c = '|';
- }
- if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),s))
- {
- c = '`';
- }
- }
- }
- }
- return c;
-}
-
-long map_count(const char* s)
-{
- int c = 0;
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,s))) c++;
- }
- return c;
-}
-
-
void force_nickchange(userrec* user,const char* newnick)
{
char nick[MAXBUF];
}
}
-
-void createcommand(char* cmd, handlerfunc f, char flags, int minparams,char* source)
-{
- command_t comm;
- /* create the command and push it onto the table */
- strlcpy(comm.command,cmd,MAXBUF);
- strlcpy(comm.source,source,MAXBUF);
- comm.handler_function = f;
- comm.flags_needed = flags;
- comm.min_params = minparams;
- comm.use_count = 0;
- comm.total_bytes = 0;
- cmdlist.push_back(comm);
- log(DEBUG,"Added command %s (%lu parameters)",cmd,(unsigned long)minparams);
-}
-
bool removecommands(const char* source)
{
bool go_again = true;
return true;
}
-void SetupCommandTable(void)
-{
- createcommand("USER",handle_user,0,4,"<core>");
- createcommand("NICK",handle_nick,0,1,"<core>");
- createcommand("QUIT",handle_quit,0,0,"<core>");
- createcommand("VERSION",handle_version,0,0,"<core>");
- createcommand("PING",handle_ping,0,1,"<core>");
- createcommand("PONG",handle_pong,0,1,"<core>");
- createcommand("ADMIN",handle_admin,0,0,"<core>");
- createcommand("PRIVMSG",handle_privmsg,0,2,"<core>");
- createcommand("INFO",handle_info,0,0,"<core>");
- createcommand("TIME",handle_time,0,0,"<core>");
- createcommand("WHOIS",handle_whois,0,1,"<core>");
- createcommand("WALLOPS",handle_wallops,'o',1,"<core>");
- createcommand("NOTICE",handle_notice,0,2,"<core>");
- createcommand("JOIN",handle_join,0,1,"<core>");
- createcommand("NAMES",handle_names,0,0,"<core>");
- createcommand("PART",handle_part,0,1,"<core>");
- createcommand("KICK",handle_kick,0,2,"<core>");
- createcommand("MODE",handle_mode,0,1,"<core>");
- createcommand("TOPIC",handle_topic,0,1,"<core>");
- createcommand("WHO",handle_who,0,1,"<core>");
- createcommand("MOTD",handle_motd,0,0,"<core>");
- createcommand("RULES",handle_rules,0,0,"<core>");
- createcommand("OPER",handle_oper,0,2,"<core>");
- createcommand("LIST",handle_list,0,0,"<core>");
- createcommand("DIE",handle_die,'o',1,"<core>");
- createcommand("RESTART",handle_restart,'o',1,"<core>");
- createcommand("KILL",handle_kill,'o',2,"<core>");
- createcommand("REHASH",handle_rehash,'o',0,"<core>");
- createcommand("LUSERS",handle_lusers,0,0,"<core>");
- createcommand("STATS",handle_stats,0,1,"<core>");
- createcommand("USERHOST",handle_userhost,0,1,"<core>");
- createcommand("AWAY",handle_away,0,0,"<core>");
- createcommand("ISON",handle_ison,0,0,"<core>");
- createcommand("SUMMON",handle_summon,0,0,"<core>");
- createcommand("USERS",handle_users,0,0,"<core>");
- createcommand("INVITE",handle_invite,0,2,"<core>");
- createcommand("PASS",handle_pass,0,1,"<core>");
- createcommand("TRACE",handle_trace,'o',0,"<core>");
- createcommand("WHOWAS",handle_whowas,0,1,"<core>");
- createcommand("CONNECT",handle_connect,'o',1,"<core>");
- createcommand("SQUIT",handle_squit,'o',0,"<core>");
- createcommand("MODULES",handle_modules,0,0,"<core>");
- createcommand("LINKS",handle_links,0,0,"<core>");
- createcommand("MAP",handle_map,0,0,"<core>");
- createcommand("KLINE",handle_kline,'o',1,"<core>");
- createcommand("GLINE",handle_gline,'o',1,"<core>");
- createcommand("ZLINE",handle_zline,'o',1,"<core>");
- createcommand("QLINE",handle_qline,'o',1,"<core>");
- createcommand("ELINE",handle_eline,'o',1,"<core>");
- createcommand("LOADMODULE",handle_loadmodule,'o',1,"<core>");
- createcommand("UNLOADMODULE",handle_unloadmodule,'o',1,"<core>");
- createcommand("SERVER",handle_server,0,0,"<core>");
-}
void process_buffer(const char* cmdbuf,userrec *user)
{
// send start of sync marker: Y <timestamp>
// at this point the ircd receiving it starts broadcasting this netburst to all ircds
// except the ones its receiving it from.
- snprintf(data,MAXBUF,"Y %lu",(unsigned long)TIME);
+ snprintf(data,MAXBUF,"%s Y %lu",CreateSum().c_str(),(unsigned long)TIME);
serv->SendPacket(data,tcp_host);
// send users and channels
{
if (is_uline(me[j]->connectors[k].GetServerName().c_str()))
{
- snprintf(data,MAXBUF,"H %s",me[j]->connectors[k].GetServerName().c_str());
+ snprintf(data,MAXBUF,"%s H %s",CreateSum().c_str(),me[j]->connectors[k].GetServerName().c_str());
serv->SendPacket(data,tcp_host);
}
}
}
// send our version for the remote side to cache
- snprintf(data,MAXBUF,"v %s %s",ServerName,GetVersionString().c_str());
+ snprintf(data,MAXBUF,"%s v %s %s",CreateSum().c_str(),ServerName,GetVersionString().c_str());
serv->SendPacket(data,tcp_host);
// sync the users and channels, give the modules a look-in.
for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
{
- snprintf(data,MAXBUF,"N %lu %s %s %s %s +%s %s %s :%s",(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,u->second->ip,u->second->server,u->second->fullname);
+ snprintf(data,MAXBUF,"%s N %lu %s %s %s %s +%s %s %s :%s",CreateSum().c_str(),(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,u->second->ip,u->second->server,u->second->fullname);
serv->SendPacket(data,tcp_host);
if (strchr(u->second->modes,'o'))
{
- snprintf(data,MAXBUF,"| %s %s",u->second->nick,u->second->oper);
+ snprintf(data,MAXBUF,"%s | %s %s",CreateSum().c_str(),u->second->nick,u->second->oper);
serv->SendPacket(data,tcp_host);
}
for (int i = 0; i <= MODCOUNT; i++)
string_list l = modules[i]->OnUserSync(u->second);
for (int j = 0; j < l.size(); j++)
{
- strlcpy(data,l[j].c_str(),MAXBUF);
+ snprintf(data,MAXBUF,"%s %s",CreateSum().c_str(),l[j].c_str());
serv->SendPacket(data,tcp_host);
}
}
char* chl = chlist(u->second,u->second);
if (strcmp(chl,""))
{
- snprintf(data,MAXBUF,"J %s %s",u->second->nick,chl);
+ snprintf(data,MAXBUF,"%s J %s %s",CreateSum().c_str(),u->second->nick,chl);
serv->SendPacket(data,tcp_host);
}
}
string_list l = modules[i]->OnChannelSync(c->second);
for (int j = 0; j < l.size(); j++)
{
- strlcpy(data,l[j].c_str(),MAXBUF);
+ snprintf(data,MAXBUF,"%s %s",CreateSum().c_str(),l[j].c_str());
serv->SendPacket(data,tcp_host);
}
}
if (c->second->topic[0])
{
- snprintf(data,MAXBUF,"T %lu %s %s :%s",(unsigned long)c->second->topicset,c->second->setby,c->second->name,c->second->topic);
+ snprintf(data,MAXBUF,"%s T %lu %s %s :%s",CreateSum().c_str(),(unsigned long)c->second->topicset,c->second->setby,c->second->name,c->second->topic);
serv->SendPacket(data,tcp_host);
}
// send current banlist
for (BanList::iterator b = c->second->bans.begin(); b != c->second->bans.end(); b++)
{
- snprintf(data,MAXBUF,"M %s +b %s",c->second->name,b->data);
+ snprintf(data,MAXBUF,"%s M %s +b %s",CreateSum().c_str(),c->second->name,b->data);
serv->SendPacket(data,tcp_host);
}
}
// sync global zlines, glines, etc
sync_xlines(serv,tcp_host);
- snprintf(data,MAXBUF,"F %lu",(unsigned long)TIME);
+ snprintf(data,MAXBUF,"%s F %lu",CreateSum().c_str(),(unsigned long)TIME);
serv->SendPacket(data,tcp_host);
log(DEBUG,"Sent sync");
// ircd sends its serverlist after the end of sync here
return false;
}
-bool DirValid(char* dirandfile)
-{
- char work[MAXBUF];
- strlcpy(work,dirandfile,MAXBUF);
- int p = strlen(work);
- // we just want the dir
- while (strlen(work))
- {
- if (work[p] == '/')
- {
- work[p] = '\0';
- break;
- }
- work[p--] = '\0';
- }
- char buffer[MAXBUF], otherdir[MAXBUF];
- // Get the current working directory
- if( getcwd( buffer, MAXBUF ) == NULL )
- return false;
- chdir(work);
- if( getcwd( otherdir, MAXBUF ) == NULL )
- return false;
- chdir(buffer);
- if (strlen(otherdir) >= strlen(work))
- {
- otherdir[strlen(work)] = '\0';
- if (!strcmp(otherdir,work))
- {
- return true;
- }
- return false;
- }
- else return false;
-}
-
-std::string GetFullProgDir(char** argv, int argc)
-{
- char work[MAXBUF];
- strlcpy(work,argv[0],MAXBUF);
- int p = strlen(work);
- // we just want the dir
- while (strlen(work))
- {
- if (work[p] == '/')
- {
- work[p] = '\0';
- break;
- }
- work[p--] = '\0';
- }
- char buffer[MAXBUF], otherdir[MAXBUF];
- // Get the current working directory
- if( getcwd( buffer, MAXBUF ) == NULL )
- return "";
- chdir(work);
- if( getcwd( otherdir, MAXBUF ) == NULL )
- return "";
- chdir(buffer);
- return otherdir;
-}
-
bool LoadModule(const char* filename)
{
char modfile[MAXBUF];
+#ifdef STATIC_LINK
+ snprintf(modfile,MAXBUF,"%s",filename);
+#else
snprintf(modfile,MAXBUF,"%s/%s",ModPath,filename);
+#endif
std::string filename_str = filename;
+#ifndef STATIC_LINK
if (!DirValid(modfile))
{
log(DEFAULT,"Module %s is not within the modules directory.",modfile);
snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);
return false;
}
+#endif
log(DEBUG,"Loading module: %s",modfile);
+#ifndef STATIC_LINK
if (FileExists(modfile))
{
+#endif
for (int j = 0; j < module_names.size(); j++)
{
if (module_names[j] == filename_str)
snprintf(MODERR,MAXBUF,"Factory function failed!");
return false;
}
+#ifndef STATIC_LINK
}
else
{
snprintf(MODERR,MAXBUF,"Module file could not be found");
return false;
}
+#endif
MODCOUNT++;
return true;
}
+
+bool GotServer(std::string name)
+{
+ for (int j = 0; j < 32; j++)
+ {
+ if (me[j] != NULL)
+ {
+ for (int k = 0; k < me[j]->connectors.size(); k++)
+ {
+ if (name == me[j]->connectors[k].GetServerName())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
int InspIRCd(char** argv, int argc)
{
struct sockaddr_in client,server;
printf("ERROR: Could not write to logfile %s, bailing!\n\n",logpath.c_str());
Exit(ERROR);
}
+
+#ifdef IS_CYGWIN
+ printf("Logging to ircd.log...\n");
+#else
printf("Logging to %s...\n",logpath.c_str());
+#endif
log(DEFAULT,"$Id$");
if (geteuid() == 0)
}
#endif
+#ifdef USE_EPOLL
+ ep = epoll_create(MAXCLIENTS);
+ lep = epoll_create(32);
+ sep = epoll_create(128);
+ if ((ep == -1) || (lep == -1) || (sep == -1))
+ {
+ log(DEFAULT,"main: epoll_create() failed!");
+ printf("ERROR: could not initialise epoll event system. Shutting down.\n");
+ Exit(ERROR);
+ }
+#endif
+#ifdef USE_EPOLL
+ log(DEFAULT,"epoll socket engine is enabled. Filling listen list. boundPortcount=%d",boundPortCount);
+ for (count = 0; count < boundPortCount; count++)
+ {
+ struct epoll_event ev;
+ log(DEBUG,"epoll: Add listening socket to events, ep=%d socket=%d",lep,openSockfd[count]);
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = openSockfd[count];
+ int i = epoll_ctl(lep, EPOLL_CTL_ADD, openSockfd[count], &ev);
+ if (i < 0)
+ {
+ log(DEFAULT,"main: add listen ports, epoll_ctl failed!");
+ printf("ERROR: could not initialise listening sockets in epoll list. Shutting down.\n");
+ Exit(ERROR);
+ }
+
+ }
+ for (int t = 0; t != SERVERportCount; t++)
+ {
+ struct epoll_event ev;
+ log(DEBUG,"epoll: Add listening server socket to events, ep=%d socket=%d",sep,me[t]->fd);
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = me[t]->fd;
+ int i = epoll_ctl(sep, EPOLL_CTL_ADD, me[t]->fd, &ev);
+ if (i == -1)
+ {
+ log(DEFAULT,"main: add server listen ports, epoll_ctl failed!");
+ printf("ERROR: could not initialise server listening sockets in epoll list. Shutting down.\n");
+ Exit(ERROR);
+ }
+ }
+#else
#ifdef USE_KQUEUE
log(DEFAULT,"kqueue socket engine is enabled. Filling listen list.");
for (count = 0; count < boundPortCount; count++)
{
struct kevent ke;
log(DEBUG,"kqueue: Add listening socket to events, kq=%d socket=%d",lkq,openSockfd[count]);
- EV_SET(&ke, openSockfd[count], EVFILT_READ, EV_ADD, 0, 5, NULL);
+ EV_SET(&ke, openSockfd[count], EVFILT_READ, EV_ADD, 0, MaxConn, NULL);
int i = kevent(lkq, &ke, 1, 0, 0, NULL);
if (i == -1)
{
log(DEFAULT,"main: add listen ports to kqueue failed!");
printf("ERROR: could not initialise listening sockets in kqueue. Shutting down.\n");
+ Exit(ERROR);
}
}
for (int t = 0; t != SERVERportCount; t++)
if (me[t])
{
log(DEBUG,"kqueue: Add listening SERVER socket to events, kq=%d socket=%d",skq,me[t]->fd);
- EV_SET(&ke, me[t]->fd, EVFILT_READ, EV_ADD, 0, 5, NULL);
+ EV_SET(&ke, me[t]->fd, EVFILT_READ, EV_ADD, 0, MaxConn, NULL);
int i = kevent(skq, &ke, 1, 0, 0, NULL);
if (i == -1)
{
log(DEFAULT,"main: add server listen ports to kqueue failed!");
printf("ERROR: could not initialise listening server sockets in kqueue. Shutting down.\n");
+ Exit(ERROR);
}
}
}
#else
log(DEFAULT,"Using standard select socket engine.");
+#endif
#endif
WritePID(PID);
length = sizeof (client);
- char tcp_msg[MAXBUF],tcp_host[MAXBUF];
+ char tcp_msg[MAXBUF],tcp_host[MAXBUF],tcp_sum[MAXBUF];
#ifdef USE_KQUEUE
struct kevent ke;
struct kevent ke_list[33];
struct timespec ts;
+#endif
+#ifdef USE_EPOLL
+ struct epoll_event event[33];
#endif
fd_set serverfds;
timeval tvs;
#ifdef _POSIX_PRIORITY_SCHEDULING
sched_yield();
#endif
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
FD_ZERO(&sfd);
#endif
-
// we only read time() once per iteration rather than tons of times!
OLDTIME = TIME;
TIME = time(NULL);
// them in a list, then reap the list every second or so.
if (((TIME % 5) == 0) && (!expire_run))
{
+ for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
+ {
+ char Link_ServerName[MAXBUF],Link_AConn[MAXBUF];
+ ConfValue("link","name",i,Link_ServerName,&config_f);
+ ConfValue("link","autoconnect",i,Link_AConn,&config_f);
+ if ((Link_AConn[0]) && (!GotServer(Link_ServerName)))
+ {
+ autoconnects::iterator a = autoconns.find(std::string(Link_ServerName));
+ if (a != autoconns.end())
+ {
+ if (TIME > a->second)
+ {
+ ConnectServer(Link_ServerName,NULL);
+ a->second = TIME + atoi(Link_AConn);
+ }
+ }
+ }
+ }
+
expire_lines();
FOREACH_MOD OnBackgroundTimer(TIME);
expire_run = true;
// fix by brain - this must be below any manipulation of the hashmap by modules
user_hash::iterator count2 = clientlist.begin();
+#ifdef USE_EPOLL
+ i = epoll_wait(sep, event, 1, EP_DELAY);
+ if (i > 0)
+ {
+ log(DEBUG,"epoll: Listening server socket event, i=%d, event.data.fd=%d",i,event[0].data.fd);
+ for (int x = 0; x != SERVERportCount; x++)
+ {
+ if ((me[x]) && (event[0].data.fd == me[x]->fd))
+ {
+#endif
#ifdef USE_KQUEUE
ts.tv_sec = 0;
ts.tv_nsec = 30000L;
if ((me[x]) && (ke.ident == me[x]->fd))
{
-#else
+#endif
+#ifdef USE_SELECT
FD_ZERO(&serverfds);
for (int x = 0; x != SERVERportCount; x++)
{
}
tvs.tv_usec = 30000L;
tvs.tv_sec = 0;
- int servresult = select(32767, &serverfds, NULL, NULL, &tvs);
+ int servresult = select(FD_SETSIZE, &serverfds, NULL, NULL, &tvs);
if (servresult > 0)
{
for (int x = 0; x != SERVERportCount; x++)
}
}
+ std::deque<std::string> msgs;
+ std::deque<std::string> sums;
for (int x = 0; x < SERVERportCount; x++)
{
- std::deque<std::string> msgs;
+ if (me[x])
+ me[x]->FlushWriteBuffers();
+ sums.clear();
msgs.clear();
- if ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host)))
+ while ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host, sums))) // returns 0 or more lines (can be multiple lines!)
{
for (int ctr = 0; ctr < msgs.size(); ctr++)
{
strlcpy(tcp_msg,msgs[ctr].c_str(),MAXBUF);
+ strlcpy(tcp_sum,msgs[ctr].c_str(),MAXBUF);
log(DEBUG,"Processing: %s",tcp_msg);
if (!tcp_msg[0])
- {
+ {
log(DEBUG,"Invalid string from %s [route%lu]",tcp_host,(unsigned long)x);
break;
}
{
if ((tcp_msg[0] != 'Y') && (tcp_msg[0] != 'X') && (tcp_msg[0] != 'F'))
{
- NetSendToAllExcept(tcp_host,tcp_msg);
+ NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum);
}
}
else
- NetSendToAllExcept(tcp_host,tcp_msg);
+ NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum);
}
std::string msg = tcp_msg;
FOREACH_MOD OnPacketReceive(msg,tcp_host);
strlcpy(tcp_msg,msg.c_str(),MAXBUF);
- handle_link_packet(tcp_msg, tcp_host, me[x]);
+ if (me[x])
+ handle_link_packet(tcp_msg, tcp_host, me[x], tcp_sum);
+ if (!me[x]->FindHost(tcp_host))
+ {
+ log(DEBUG,"Connector gone, bailing!");
+ goto label;
+ }
}
- goto label;
+ sums.clear(); // we're done, clear the list for the next operation
+ msgs.clear();
}
}
while (count2 != clientlist.end())
{
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
FD_ZERO(&sfd);
#endif
if (count2->second)
curr = count2->second;
+ if ((long)curr == -1)
+ goto label;
+
if ((curr) && (curr->fd != 0))
{
#ifdef _POSIX_PRIORITY_SCHEDULING
//
// This should be up to 64x faster than the
// old implementation.
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
while (total_in_this_set < 1024)
{
if (count2 != clientlist.end())
{
curr = count2->second;
+ if ((long)curr == -1)
+ goto label;
+ int currfd = curr->fd;
// we don't check the state of remote users.
- if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
+ if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER))
{
curr->FlushWriteBuf();
if (curr->GetWriteError() != "")
curr->dns_done = true;
statsDnsBad++;
FullConnectUser(curr);
- goto label;
+ if (fd_ref_table[currfd] != curr) // something changed, bail pronto
+ goto label;
}
if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr))) // both NICK and USER... and DNS
{
log(DEBUG,"dns done, registered=3, and modules ready, OK");
FullConnectUser(curr);
- goto label;
+ if (fd_ref_table[currfd] != curr) // something changed, bail pronto
+ goto label;
}
if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7))
{
endingiter = count2;
count2 = xcount; // roll back to where we were
#else
- // KQUEUE: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again.
+ // KQUEUE and EPOLL: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again.
// TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue.
cycle_iter++;
- if (cycle_iter > 10) while (count2 != clientlist.end())
+ if (cycle_iter > 20) while (count2 != clientlist.end())
{
cycle_iter = 0;
if (count2 != clientlist.end())
{
curr = count2->second;
+ if ((long)curr == -1)
+ goto label;
+ int currfd = curr->fd;
// we don't check the state of remote users.
- if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
+ if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER))
{
curr->FlushWriteBuf();
{
log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick);
kill_link(curr,"Registration timeout");
- goto label;
+ goto label;
+
}
if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr)))
{
curr->dns_done = true;
statsDnsBad++;
FullConnectUser(curr);
- goto label;
+ if (fd_ref_table[currfd] != curr) // something changed, bail pronto
+ goto label;
}
if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr)))
{
log(DEBUG,"dns done, registered=3, and modules ready, OK");
FullConnectUser(curr);
- goto label;
+ if (fd_ref_table[currfd] != curr) // something changed, bail pronto
+ goto label;
}
if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7))
{
#endif
v = 0;
-
+#ifdef USE_EPOLL
+ int i = epoll_wait(ep, event, 1, 5);
+ if (i > 0)
+ {
+ log(DEBUG,"epoll_wait call: ep=%d, i=%d",ep,i);
+ // EPOLL: we asked epoll_wait for ONE fd which is ready. Do something.
+ userrec* cu = fd_ref_table[event[0].data.fd];
+#endif
#ifdef USE_KQUEUE
ts.tv_sec = 0;
ts.tv_nsec = 1000L;
log(DEBUG,"kevent call: kq=%d, i=%d",kq,i);
// KQUEUE: kevent gives us ONE fd which is ready to have something done to it. Do something to it.
userrec* cu = fd_ref_table[ke.ident];
-#else
+#endif
+#ifdef USE_SELECT
+ tval.tv_sec = 0;
tval.tv_usec = 1000L;
- selectResult2 = select(65535, &sfd, NULL, NULL, &tval);
-
+ selectResult2 = select(FD_SETSIZE, &sfd, NULL, NULL, &tval);
// now loop through all of the items in this pool if any are waiting
- if (selectResult2 > 0)
+ if ((selectResult2 > 0) && (xcount != clientlist.end()))
for (user_hash::iterator count2a = xcount; count2a != endingiter; count2a++)
{
// SELECT: we have to iterate...
+ if (count2a == clientlist.end())
+ break;
userrec* cu = count2a->second;
#endif
sched_yield();
#endif
result = EAGAIN;
+#ifdef USE_EPOLL
+ // EPOLL: We already know we have a valid FD. No checks needed.
+ if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
+#endif
#ifdef USE_KQUEUE
// KQUEUE: We already know we have a valid FD. No checks needed.
if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
-#else
+#endif
+#ifdef USE_SELECT
// SELECT: We don't know if our FD is valid.
if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1) && (FD_ISSET (cu->fd, &sfd)))
#endif
FOREACH_RESULT(OnRawSocketRead(cu->fd,data,65535,result2));
if (!MOD_RESULT)
{
- result = read(cu->fd, data, 65535);
+ result = cu->ReadData(data, 65535);
}
else result = result2;
log(DEBUG,"Read result: %d",result);
else
if (result == 0)
{
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
if (count2->second)
{
#endif
// must bail here? kill_link removes the hash, corrupting the iterator
log(DEBUG,"Bailing from client exit");
goto label;
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
}
#endif
}
sched_yield();
#endif
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
// set up select call
for (count = 0; count < boundPortCount; count++)
{
{
if (FD_ISSET (openSockfd[count], &selectFds))
{
-#else
+#endif
+#ifdef USE_KQUEUE
ts.tv_sec = 0;
ts.tv_nsec = 30000L;
i = kevent(lkq, NULL, 0, ke_list, 32, &ts);
if (i > 0) for (j = 0; j < i; j++)
{
- log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke.ident);
+ log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke_list[j].ident);
// this isnt as efficient as it could be, we could create a reference table
// to reference bound ports by fd, but this isnt a big bottleneck as the actual
// number of listening ports on the average ircd is a small number (less than 20)
{
if (ke_list[j].ident == openSockfd[count])
{
+#endif
+#ifdef USE_EPOLL
+ i = epoll_wait(lep, event, 32, EP_DELAY);
+ if (i > 0) for (j = 0; j < i; j++)
+ {
+ log(DEBUG,"epoll: Listening socket event, i=%d,events[j].data.fd=%d",i,event[j].data.fd);
+ for (count = 0; count < boundPortCount; count++)
+ {
+ if (event[j].data.fd == openSockfd[count])
+ {
#endif
char target[MAXBUF], resolved[MAXBUF];
length = sizeof (client);
AddClient(incomingSockfd, resolved, ports[count], false, inet_ntoa (client.sin_addr));
log(DEBUG,"InspIRCd: adding client on port %lu fd=%lu",(unsigned long)ports[count],(unsigned long)incomingSockfd);
}
- //goto label;
}
}
}