#ifdef USE_EPOLL
#include <sys/epoll.h>
-#define EP_DELAY 100
+#define EP_DELAY 50
#endif
#include <time.h>
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;
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])
NetSendToAll(buffer);
}
+ user->FlushWriteBuf();
+
FOREACH_MOD OnUserDisconnect(user);
if (user->fd > -1)
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);
- }
+ // 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);
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;
}
{
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, 32, 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)
{
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, 32, 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)
{
user_hash::iterator count2 = clientlist.begin();
#ifdef USE_EPOLL
- i = epoll_wait(sep, event, 1, EP_DELAY*2);
-#ifdef _POSIX_PRIORITY_SCHEDULING
- sched_yield();
-#endif
+ 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);
}
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;
- std::deque<std::string> sums;
- msgs.clear();
sums.clear();
- if ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host, sums)))
+ msgs.clear();
+ 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_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;
}
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], tcp_sum);
+ if (me[x])
+ handle_link_packet(tcp_msg, tcp_host, me[x], tcp_sum);
}
- goto label;
+ sums.clear(); // we're done, clear the list for the next operation
+ msgs.clear();
}
}
if (count2->second)
curr = count2->second;
+ if ((long)curr == -1)
+ goto label;
+
if ((curr) && (curr->fd != 0))
{
#ifdef _POSIX_PRIORITY_SCHEDULING
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))
{
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))
{
userrec* cu = fd_ref_table[ke.ident];
#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
{
#endif
#ifdef USE_EPOLL
-#ifdef _POSIX_PRIORITY_SCHEDULING
- sched_yield();
-#endif
- i = epoll_wait(lep, event, 32, EP_DELAY*2);
-#ifdef _POSIX_PRIORITY_SCHEDULING
- sched_yield();
-#endif
+ 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);
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;
}
}
}