bool nofork = false;
bool unlimitcore = false;
-time_t TIME = time(NULL);
+time_t TIME = time(NULL), OLDTIME = time(NULL);
#ifdef USE_KQUEUE
-int kq;
+int kq, lkq, skq;
#endif
namespace nspace
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 std::deque<command_t> command_table;
// This table references users by file descriptor.
user_hash clientlist;
chan_hash chanlist;
-user_hash whowas;
+whowas_hash whowas;
command_table cmdlist;
file_cache MOTD;
file_cache RULES;
void ReadConfig(bool bail, userrec* user)
{
char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF];
- char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF],pfreq[MAXBUF],thold[MAXBUF];
+ char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF],pfreq[MAXBUF],thold[MAXBUF],sqmax[MAXBUF],rqmax[MAXBUF];
ConnectClass c;
std::stringstream errstr;
ConfValue("connect","flood",i,flood,&config_f);
ConfValue("connect","pingfreq",i,pfreq,&config_f);
ConfValue("connect","threshold",i,thold,&config_f);
+ ConfValue("connect","sendq",i,sqmax,&config_f);
+ ConfValue("connect","recvq",i,rqmax,&config_f);
if (Value[0])
{
strlcpy(c.host,Value,MAXBUF);
c.pingtime = 120;
c.flood = atoi(flood);
c.threshold = 5;
+ c.sendqmax = 262144; // 256k
+ c.recvqmax = 4096; // 4k
if (atoi(thold)>0)
{
c.threshold = atoi(thold);
}
+ if (atoi(sqmax)>0)
+ {
+ c.sendqmax = atoi(sqmax);
+ }
+ if (atoi(rqmax)>0)
+ {
+ c.recvqmax = atoi(rqmax);
+ }
if (atoi(timeout)>0)
{
c.registration_timeout = atoi(timeout);
}
}
-/* write formatted text to a socket, in same format as printf */
+/* 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 == FD_MAGIC_NUMBER)
+ if (sock < 0)
return;
if (!text)
{
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 ((sock != -1) && (sock != FD_MAGIC_NUMBER))
+ if (fd_ref_table[sock])
{
int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
- if (!MOD_RESULT)
- write(sock,tb,bytes > 512 ? 512 : bytes);
- if (fd_ref_table[sock])
- {
- fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
- fd_ref_table[sock]->cmds_out++;
- }
- statsSent += (bytes > 512 ? 512 : bytes);
+ 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 == FD_MAGIC_NUMBER)
+ if (sock < 0)
return;
if (!text)
{
return;
}
char textbuffer[MAXBUF],tb[MAXBUF];
+ int res;
va_list argsPtr;
va_start (argsPtr, text);
va_end(argsPtr);
int bytes = snprintf(tb,MAXBUF,":%s %s\r\n",ServerName,textbuffer);
chop(tb);
- if ((sock != -1) && (sock != FD_MAGIC_NUMBER))
- {
+ if (fd_ref_table[sock])
+ {
int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
- if (!MOD_RESULT)
- write(sock,tb,bytes > 512 ? 512 : bytes);
- if (fd_ref_table[sock])
- {
- fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
- fd_ref_table[sock]->cmds_out++;
- }
- statsSent += (bytes > 512 ? 512 : bytes);
- }
+ 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 == FD_MAGIC_NUMBER)
+ if (sock < 0)
return;
if ((!text) || (!user))
{
}
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 ((sock != -1) && (sock != FD_MAGIC_NUMBER))
- {
+ if (fd_ref_table[sock])
+ {
int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
- if (!MOD_RESULT)
- write(sock,tb,bytes > 512 ? 512 : bytes);
- if (fd_ref_table[sock])
- {
- fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
- fd_ref_table[sock]->cmds_out++;
- }
- statsSent += (bytes > 512 ? 512 : bytes);
- }
+ 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 NetSendToCommon(userrec* u, char* s)
{
char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
+ snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
+
log(DEBUG,"NetSendToCommon: '%s' '%s'",u->nick,s);
std::string msg = buffer;
void NetSendToAll(char* s)
{
char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
+ snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
log(DEBUG,"NetSendToAll: '%s'",s);
}
}
+void NetSendToAll_WithSum(char* s,char* u)
+{
+ char buffer[MAXBUF];
+ snprintf(buffer,MAXBUF,":%s %s",u,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);
+ snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
log(DEBUG,"NetSendToAllAlive: '%s'",s);
void NetSendToOne(char* target,char* s)
{
char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
+ snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
log(DEBUG,"NetSendToOne: '%s' '%s'",target,s);
void NetSendToAllExcept(const char* target,char* s)
{
char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
+ snprintf(buffer,MAXBUF,"%s %s",CreateSum().c_str(),s);
log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
}
}
+void NetSendToAllExcept_WithSum(const char* target,char* s,char* u)
+{
+ char buffer[MAXBUF];
+ snprintf(buffer,MAXBUF,":%s %s",u,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 (u->chans[f].channel)
{
- u->chans[f].channel->DecUserCounter();
u->chans[f].channel->DelUser((char*)u);
}
}
strcpy(scratch,"");
strcpy(sparam,"");
- if (chan->noexternal)
+ if (chan->binarymodes & CM_NOEXTERNAL)
{
strlcat(scratch,"n",MAXMODES);
}
- if (chan->topiclock)
+ if (chan->binarymodes & CM_TOPICLOCK)
{
strlcat(scratch,"t",MAXMODES);
}
{
strlcat(scratch,"l",MAXMODES);
}
- if (chan->inviteonly)
+ if (chan->binarymodes & CM_INVITEONLY)
{
strlcat(scratch,"i",MAXMODES);
}
- if (chan->moderated)
+ if (chan->binarymodes & CM_MODERATED)
{
strlcat(scratch,"m",MAXMODES);
}
- if (chan->secret)
+ if (chan->binarymodes & CM_SECRET)
{
strlcat(scratch,"s",MAXMODES);
}
- if (chan->c_private)
+ if (chan->binarymodes & CM_PRIVATE)
{
strlcat(scratch,"p",MAXMODES);
}
chanlist[cname] = new chanrec();
strlcpy(chanlist[cname]->name, cname,CHANMAX);
- chanlist[cname]->topiclock = 1;
- chanlist[cname]->noexternal = 1;
+ chanlist[cname]->binarymodes = CM_TOPICLOCK | CM_NOEXTERNAL;
chanlist[cname]->created = TIME;
strcpy(chanlist[cname]->topic, "");
strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
FOREACH_RESULT(OnCheckInvite(user, Ptr));
if (MOD_RESULT == 0)
{
- if (Ptr->inviteonly)
+ if (Ptr->binarymodes & CM_INVITEONLY)
{
log(DEBUG,"add_channel: channel is +i");
if (user->IsInvited(Ptr->name))
user->chans[index].uc_modes = 0;
}
user->chans[index].channel = Ptr;
- Ptr->IncUserCounter();
Ptr->AddUser((char*)user);
WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
}
}
- Ptr->DecUserCounter();
Ptr->DelUser((char*)user);
/* if there are no users left on the channel */
}
}
- Ptr->DecUserCounter();
Ptr->DelUser((char*)user);
/* if there are no users left on the channel */
log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
if (user->fd > -1)
fd_ref_table[user->fd] = NULL;
- delete user;
clientlist.erase(iter);
}
+ delete user;
}
void kill_link_silent(userrec *user,const char* r)
log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
if (user->fd > -1)
fd_ref_table[user->fd] = NULL;
- delete user;
clientlist.erase(iter);
}
+ delete user;
}
log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
- clientlist[New] = new userrec();
- clientlist[New] = oldnick->second;
+ userrec* olduser = oldnick->second;
+ clientlist[New] = olduser;
clientlist.erase(oldnick);
log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
/* adds or updates an entry in the whowas list */
void AddWhoWas(userrec* u)
{
- user_hash::iterator iter = whowas.find(u->nick);
- userrec *a = new userrec();
+ whowas_hash::iterator iter = whowas.find(u->nick);
+ WhoWasUser *a = new WhoWasUser();
strlcpy(a->nick,u->nick,NICKMAX);
- strlcpy(a->ident,u->ident,64);
- strlcpy(a->dhost,u->dhost,256);
- strlcpy(a->host,u->host,256);
+ strlcpy(a->ident,u->ident,15);
+ strlcpy(a->dhost,u->dhost,160);
+ strlcpy(a->host,u->host,160);
strlcpy(a->fullname,u->fullname,128);
strlcpy(a->server,u->server,256);
a->signon = u->signon;
if (iter == whowas.end())
{
- if (whowas.size() == WHOWAS_MAX)
+ if (whowas.size() >= WHOWAS_MAX)
{
- for (user_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
+ for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
{
// 3600 seconds in an hour ;)
if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
{
+ // delete the old one
if (i->second) delete i->second;
+ // replace with new one
i->second = a;
log(DEBUG,"added WHOWAS entry, purged an old record");
return;
}
}
+ // no space left and user doesnt exist. Don't leave ram in use!
+ log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
+ delete a;
}
else
{
// issue in earlier alphas/betas
if (iter != clientlist.end())
{
+ userrec* goner = iter->second;
+ delete goner;
clientlist.erase(iter);
}
strncpy(clientlist[tempnick]->host, host,160);
strncpy(clientlist[tempnick]->dhost, host,160);
strncpy(clientlist[tempnick]->server, ServerName,256);
- strncpy(clientlist[tempnick]->ident, "unknown",12);
+ strncpy(clientlist[tempnick]->ident, "unknown",15);
clientlist[tempnick]->registered = 0;
clientlist[tempnick]->signon = TIME+dns_timeout;
clientlist[tempnick]->lastping = 1;
clientlist[tempnick]->port = port;
- strncpy(clientlist[tempnick]->ip,ip,32);
+ strncpy(clientlist[tempnick]->ip,ip,16);
// set the registration timeout for this user
unsigned long class_regtimeout = 90;
int class_flood = 0;
long class_threshold = 5;
+ long class_sqmax = 262144; // 256kb
+ long class_rqmax = 4096; // 4k
for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
{
class_flood = i->flood;
clientlist[tempnick]->pingmax = i->pingtime;
class_threshold = i->threshold;
+ class_sqmax = i->sendqmax;
+ class_rqmax = i->recvqmax;
break;
}
}
clientlist[tempnick]->timeout = TIME+class_regtimeout;
clientlist[tempnick]->flood = class_flood;
clientlist[tempnick]->threshold = class_threshold;
+ clientlist[tempnick]->sendqmax = class_sqmax;
+ clientlist[tempnick]->recvqmax = class_rqmax;
for (int i = 0; i < MAXCHANS; i++)
{
// irc server at once (or the irc server otherwise initiating this many connections, files etc)
// which for the time being is a physical impossibility (even the largest networks dont have more
// than about 10,000 users on ONE server!)
- if (socket > 65535)
+ if (socket > 65534)
{
kill_link(clientlist[tempnick],"Server is full");
return;
#ifdef USE_KQUEUE
struct kevent ke;
- memset(&ke,0,sizeof(struct kevent));
log(DEBUG,"kqueue: Add user to events, kq=%d socket=%d",kq,socket);
EV_SET(&ke, socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
int i = kevent(kq, &ke, 1, 0, 0, NULL);
snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick);
WholeMOTD = WholeMOTD + buf;
// only one write operation
- send(user->fd,WholeMOTD.c_str(),WholeMOTD.length(),0);
+ user->AddWriteBuf(WholeMOTD);
statsSent += WholeMOTD.length();
}
// 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
WritePID(PID);
/* setup select call */
+#ifndef USE_KQUEUE
FD_ZERO(&selectFds);
+#endif
log(DEBUG,"InspIRCd: startup: zero selects");
log(VERBOSE,"InspIRCd: startup: portCount = %lu", (unsigned long)portCount);
// BUGFIX: We cannot initialize this before forking, as the kqueue data is not inherited by child processes!
#ifdef USE_KQUEUE
kq = kqueue();
- if (kq == -1)
+ lkq = kqueue();
+ skq = kqueue();
+ if ((kq == -1) || (lkq == -1) || (skq == -1))
{
log(DEFAULT,"main: kqueue() failed!");
printf("ERROR: could not initialise kqueue event system. Shutting down.\n");
Exit(ERROR);
}
#endif
+
+
+#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);
+ 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");
+ }
+ }
+ for (int t = 0; t != SERVERportCount; t++)
+ {
+ struct kevent ke;
+ 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);
+ 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");
+ }
+ }
+ }
+
+
+#else
+ log(DEFAULT,"Using standard select socket engine.");
+#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
fd_set serverfds;
timeval tvs;
tvs.tv_usec = 10000L;
tval.tv_usec = 10000L;
tval.tv_sec = 0;
int total_in_this_set = 0;
- int v = 0;
+ int i = 0, v = 0, j = 0, cycle_iter = 0;
bool expire_run = false;
/* main loop, this never returns */
#ifdef _POSIX_PRIORITY_SCHEDULING
sched_yield();
#endif
- // poll dns queue
- dns_poll();
+#ifndef USE_KQUEUE
FD_ZERO(&sfd);
+#endif
// we only read time() once per iteration rather than tons of times!
+ OLDTIME = TIME;
TIME = time(NULL);
+ dns_poll();
+
// *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue
// them in a list, then reap the list every second or so.
if (((TIME % 5) == 0) && (!expire_run))
// fix by brain - this must be below any manipulation of the hashmap by modules
user_hash::iterator count2 = clientlist.begin();
+#ifdef USE_KQUEUE
+ ts.tv_sec = 0;
+ ts.tv_nsec = 30000L;
+ i = kevent(skq, NULL, 0, &ke, 1, &ts);
+ if (i > 0)
+ {
+ log(DEBUG,"kqueue: Listening server socket event, i=%d, ke.ident=%d",i,ke.ident);
+ for (int x = 0; x != SERVERportCount; x++)
+ {
+ if ((me[x]) && (ke.ident == me[x]->fd))
+ {
+
+#else
FD_ZERO(&serverfds);
-
for (int x = 0; x != SERVERportCount; x++)
{
if (me[x])
FD_SET(me[x]->fd, &serverfds);
}
-
- // serverFds timevals went here
-
tvs.tv_usec = 30000L;
tvs.tv_sec = 0;
int servresult = select(32767, &serverfds, NULL, NULL, &tvs);
{
if ((me[x]) && (FD_ISSET (me[x]->fd, &serverfds)))
{
+#endif
char remotehost[MAXBUF],resolved[MAXBUF];
length = sizeof (client);
incomingSockfd = accept (me[x]->fd, (sockaddr *) &client, &length);
for (int x = 0; x < SERVERportCount; x++)
{
std::deque<std::string> msgs;
+ std::deque<std::string> sums;
msgs.clear();
- if ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host)))
+ sums.clear();
+ if ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host, sums)))
{
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])
{
{
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]);
+ handle_link_packet(tcp_msg, tcp_host, me[x], tcp_sum);
}
goto label;
}
while (count2 != clientlist.end())
{
+#ifndef USE_KQUEUE
FD_ZERO(&sfd);
+#endif
total_in_this_set = 0;
// we don't check the state of remote users.
if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
{
+ curr->FlushWriteBuf();
+ if (curr->GetWriteError() != "")
+ {
+ log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
+ kill_link(curr,curr->GetWriteError().c_str());
+ goto label;
+ }
+
FD_SET (curr->fd, &sfd);
// registration timeout -- didnt send USER/NICK/HOST in the time specified in
endingiter = count2;
count2 = xcount; // roll back to where we were
#else
- dns_poll();
// 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.
// TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue.
- while (count2 != clientlist.end())
+ cycle_iter++;
+ if (cycle_iter > 10) while (count2 != clientlist.end())
{
+ cycle_iter = 0;
if (count2 != clientlist.end())
{
curr = count2->second;
// we don't check the state of remote users.
if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
{
+
+ curr->FlushWriteBuf();
+ if (curr->GetWriteError() != "")
+ {
+ log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
+ kill_link(curr,curr->GetWriteError().c_str());
+ goto label;
+ }
+
// registration timeout -- didnt send USER/NICK/HOST in the time specified in
// their connection class.
if ((TIME > curr->timeout) && (curr->registered != 7))
v = 0;
#ifdef USE_KQUEUE
- struct kevent ke;
- int fd_to_process = 0;
- struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 1000L;
// for now, we only read 1 event. We could read soooo many more :)
sched_yield();
#endif
+#ifndef USE_KQUEUE
// set up select call
for (count = 0; count < boundPortCount; count++)
{
/* select is reporting a waiting socket. Poll them all to find out which */
if (selectResult > 0)
{
- char target[MAXBUF], resolved[MAXBUF];
- for (count = 0; count < boundPortCount; count++)
+ for (count = 0; count < boundPortCount; count++)
{
if (FD_ISSET (openSockfd[count], &selectFds))
{
+#else
+ 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);
+ // 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)
+ // compared to the number of clients (possibly over 2000)
+ for (count = 0; count < boundPortCount; count++)
+ {
+ if (ke_list[j].ident == openSockfd[count])
+ {
+#endif
+ char target[MAXBUF], resolved[MAXBUF];
length = sizeof (client);
incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
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;
+ //goto label;
}
}
}