summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/modules.example.conf7
-rw-r--r--include/socketengine.h22
-rw-r--r--include/sockets.h1
-rw-r--r--modules/extra/m_httpd.cpp15
-rw-r--r--modules/extra/m_ssl.cpp18
-rw-r--r--modules/extra/webcpanel/pages/chanserv/access.cpp2
-rw-r--r--modules/extra/webcpanel/pages/chanserv/akick.cpp2
-rw-r--r--modules/extra/webcpanel/pages/chanserv/set.cpp2
-rw-r--r--modules/extra/webcpanel/pages/index.cpp2
-rw-r--r--modules/extra/webcpanel/pages/logout.cpp2
-rw-r--r--modules/extra/webcpanel/webcpanel.cpp2
-rw-r--r--modules/extra/webcpanel/webcpanel.h1
-rw-r--r--src/dns.cpp17
-rw-r--r--src/socket_clients.cpp4
-rw-r--r--src/socket_transport.cpp10
-rw-r--r--src/socketengines/pipeengine_pipe.cpp5
-rw-r--r--src/socketengines/socketengine_epoll.cpp120
-rw-r--r--src/socketengines/socketengine_kqueue.cpp111
-rw-r--r--src/socketengines/socketengine_poll.cpp143
-rw-r--r--src/socketengines/socketengine_select.cpp87
-rw-r--r--src/sockets.cpp9
21 files changed, 262 insertions, 320 deletions
diff --git a/data/modules.example.conf b/data/modules.example.conf
index ba12e0f1d..753f0f736 100644
--- a/data/modules.example.conf
+++ b/data/modules.example.conf
@@ -111,6 +111,8 @@ httpd
port = 8080
/* Time before connections to this server are timed out */
timeout = 30
+ /* Listen using SSL. Requires m_ssl. */
+ #ssl = yes
/* If you are using a reverse proxy that sends one of the
* extforward_headers set below, set this to its IP.
@@ -474,7 +476,7 @@ rewrite
*
* This module uses SSL to connect to the uplink server(s)
*/
-module { name = "m_ssl" }
+#module { name = "m_ssl" }
ssl
{
/*
@@ -565,6 +567,9 @@ webcpanel
/* Page title */
title = "Anope IRC Services";
+
+ /* Whether or not to use https on redirecting URLS */
+ ssl = no
}
diff --git a/include/socketengine.h b/include/socketengine.h
index 0cffec6b3..6cf49baa0 100644
--- a/include/socketengine.h
+++ b/include/socketengine.h
@@ -16,6 +16,7 @@
class CoreExport SocketEngine
{
+ static const int DefaultSize = 4; // Uplink, DNS, Signal handler, Mode stacker
public:
/* Map of sockets */
static std::map<int, Socket *> Sockets;
@@ -28,25 +29,12 @@ class CoreExport SocketEngine
*/
static void Shutdown();
- /** Add a socket to the internal list
+ /** Set a flag on a socket
* @param s The socket
+ * @param set Whether setting or unsetting
+ * @param flag The flag to set or unset
*/
- static void AddSocket(Socket *s);
-
- /** Delete a socket from the internal list
- * @param s The socket
- */
- static void DelSocket(Socket *s);
-
- /** Mark a socket as writeable
- * @param s The socket
- */
- static void MarkWritable(Socket *s);
-
- /** Unmark a socket as writeable
- * @param s The socket
- */
- static void ClearWritable(Socket *s);
+ static void Change(Socket *s, bool set, SocketFlag flag);
/** Read from sockets and do things
*/
diff --git a/include/sockets.h b/include/sockets.h
index ea59346db..7074522e0 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -110,6 +110,7 @@ class SocketException : public CoreException
enum SocketFlag
{
SF_DEAD,
+ SF_READABLE,
SF_WRITABLE,
SF_CONNECTING,
SF_CONNECTED,
diff --git a/modules/extra/m_httpd.cpp b/modules/extra/m_httpd.cpp
index 357e9fba9..4453cf826 100644
--- a/modules/extra/m_httpd.cpp
+++ b/modules/extra/m_httpd.cpp
@@ -7,6 +7,7 @@
#include "module.h"
#include "httpd.h"
+#include "ssl.h"
static Anope::string BuildDate()
{
@@ -299,9 +300,10 @@ class MyHTTPProvider : public HTTPProvider, public CallBack
class HTTPD : public Module
{
+ service_reference<SSLService> sslref;
std::map<Anope::string, HTTPProvider *> providers;
public:
- HTTPD(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED)
+ HTTPD(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED), sslref("SSLService", "ssl")
{
this->SetAuthor("Anope");
@@ -338,6 +340,7 @@ class HTTPD : public Module
Anope::string ip = config.ReadValue("httpd", "ip", "", i);
int port = config.ReadInteger("httpd", "port", "8080", i, true);
int timeout = config.ReadInteger("httpd", "timeout", "30", i, true);
+ bool ssl = config.ReadFlag("httpd", "ssl", "no", i);
Anope::string ext_ip = config.ReadValue("httpd", "extforward_ip", "", i);
Anope::string ext_header = config.ReadValue("httpd", "extforward_header", "", i);
@@ -352,12 +355,20 @@ class HTTPD : public Module
continue;
}
+ if (ssl && !sslref)
+ {
+ Log(this) << "Could not enable SSL, is m_ssl loaded?";
+ ssl = false;
+ }
+
HTTPProvider *p;
if (this->providers.count(hname) == 0)
{
try
{
p = new MyHTTPProvider(this, hname, ip, port, timeout);
+ if (ssl)
+ sslref->Init(p);
}
catch (const SocketException &ex)
{
@@ -380,6 +391,8 @@ class HTTPD : public Module
try
{
p = new MyHTTPProvider(this, hname, ip, port, timeout);
+ if (ssl)
+ sslref->Init(p);
}
catch (const SocketException &ex)
{
diff --git a/modules/extra/m_ssl.cpp b/modules/extra/m_ssl.cpp
index adae7a6fe..2f72744c7 100644
--- a/modules/extra/m_ssl.cpp
+++ b/modules/extra/m_ssl.cpp
@@ -153,6 +153,10 @@ class SSLModule : public Module
SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, SSLModule::AlwaysAccept);
SSL_CTX_set_verify(server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, SSLModule::AlwaysAccept);
+ Anope::string context_name = "Anope";
+ SSL_CTX_set_session_id_context(client_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
+ SSL_CTX_set_session_id_context(server_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
+
ModuleManager::Attach(I_OnReload, this);
ModuleManager::Attach(I_OnPreServerConnect, this);
}
@@ -275,7 +279,8 @@ SocketFlag SSLSocketIO::FinishAccept(ClientSocket *cs)
int error = SSL_get_error(IO->sslsock, ret);
if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE))
{
- SocketEngine::MarkWritable(cs);
+ SocketEngine::Change(cs, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE);
+ SocketEngine::Change(cs, error == SSL_ERROR_WANT_READ, SF_READABLE);
return SF_ACCEPTING;
}
else
@@ -290,6 +295,8 @@ SocketFlag SSLSocketIO::FinishAccept(ClientSocket *cs)
{
cs->SetFlag(SF_ACCEPTED);
cs->UnsetFlag(SF_ACCEPTING);
+ SocketEngine::Change(cs, false, SF_WRITABLE);
+ SocketEngine::Change(cs, true, SF_READABLE);
cs->OnAccept();
return SF_ACCEPTED;
}
@@ -315,7 +322,7 @@ void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int
}
else
{
- SocketEngine::MarkWritable(s);
+ SocketEngine::Change(s, true, SF_WRITABLE);
s->SetFlag(SF_CONNECTING);
return;
}
@@ -354,7 +361,8 @@ SocketFlag SSLSocketIO::FinishConnect(ConnectionSocket *s)
int error = SSL_get_error(IO->sslsock, ret);
if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE))
{
- SocketEngine::MarkWritable(s);
+ SocketEngine::Change(s, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE);
+ SocketEngine::Change(s, error == SSL_ERROR_WANT_READ, SF_READABLE);
return SF_CONNECTING;
}
else
@@ -369,6 +377,8 @@ SocketFlag SSLSocketIO::FinishConnect(ConnectionSocket *s)
{
s->UnsetFlag(SF_CONNECTING);
s->SetFlag(SF_CONNECTED);
+ SocketEngine::Change(s, false, SF_WRITABLE);
+ SocketEngine::Change(s, true, SF_READABLE);
s->OnConnect();
return SF_CONNECTED;
}
@@ -381,6 +391,8 @@ void SSLSocketIO::Destroy()
SSL_shutdown(this->sslsock);
SSL_free(this->sslsock);
}
+
+ delete this;
}
MODULE_INIT(SSLModule)
diff --git a/modules/extra/webcpanel/pages/chanserv/access.cpp b/modules/extra/webcpanel/pages/chanserv/access.cpp
index dc999c350..a1b8be97f 100644
--- a/modules/extra/webcpanel/pages/chanserv/access.cpp
+++ b/modules/extra/webcpanel/pages/chanserv/access.cpp
@@ -18,7 +18,7 @@ bool WebCPanel::ChanServ::Access::OnRequest(HTTPProvider *server, const Anope::s
if (chname.empty())
{
reply.error = HTTP_FOUND;
- reply.headers["Location"] = "http://" + message.headers["Host"] + "/chanserv/info";
+ reply.headers["Location"] = Anope::string("http") + (use_ssl ? "s" : "") + "://" + message.headers["Host"] + "/chanserv/info";
return true;
}
diff --git a/modules/extra/webcpanel/pages/chanserv/akick.cpp b/modules/extra/webcpanel/pages/chanserv/akick.cpp
index 70fa5b52e..d5351bfd9 100644
--- a/modules/extra/webcpanel/pages/chanserv/akick.cpp
+++ b/modules/extra/webcpanel/pages/chanserv/akick.cpp
@@ -18,7 +18,7 @@ bool WebCPanel::ChanServ::Akick::OnRequest(HTTPProvider *server, const Anope::st
if (chname.empty())
{
reply.error = HTTP_FOUND;
- reply.headers["Location"] = "http://" + message.headers["Host"] + "/chanserv/info";
+ reply.headers["Location"] = Anope::string("http") + (use_ssl ? "s" : "") + "://" + message.headers["Host"] + "/chanserv/info";
return true;
}
diff --git a/modules/extra/webcpanel/pages/chanserv/set.cpp b/modules/extra/webcpanel/pages/chanserv/set.cpp
index 889e8f24f..4ad551e6a 100644
--- a/modules/extra/webcpanel/pages/chanserv/set.cpp
+++ b/modules/extra/webcpanel/pages/chanserv/set.cpp
@@ -18,7 +18,7 @@ bool WebCPanel::ChanServ::Set::OnRequest(HTTPProvider *server, const Anope::stri
if (chname.empty())
{
reply.error = HTTP_FOUND;
- reply.headers["Location"] = "http://" + message.headers["Host"] + "/chanserv/info";
+ reply.headers["Location"] = Anope::string("http") + (use_ssl ? "s" : "") + "://" + message.headers["Host"] + "/chanserv/info";
return true;
}
diff --git a/modules/extra/webcpanel/pages/index.cpp b/modules/extra/webcpanel/pages/index.cpp
index 357d3ec3b..c97737c21 100644
--- a/modules/extra/webcpanel/pages/index.cpp
+++ b/modules/extra/webcpanel/pages/index.cpp
@@ -58,7 +58,7 @@ class WebpanelRequest : public IdentifyRequest
}
reply.error = HTTP_FOUND;
- reply.headers["Location"] = "http://" + message.headers["Host"] + "/nickserv/info";
+ reply.headers["Location"] = Anope::string("http") + (use_ssl ? "s" : "") + "://" + message.headers["Host"] + "/nickserv/info";
client->SendReply(&reply);
}
diff --git a/modules/extra/webcpanel/pages/logout.cpp b/modules/extra/webcpanel/pages/logout.cpp
index efa93ab4f..d62bde95f 100644
--- a/modules/extra/webcpanel/pages/logout.cpp
+++ b/modules/extra/webcpanel/pages/logout.cpp
@@ -17,7 +17,7 @@ bool WebCPanel::Logout::OnRequest(HTTPProvider *server, const Anope::string &pag
na->Shrink("webcpanel_ip");
reply.error = HTTP_FOUND;
- reply.headers["Location"] = "http://" + message.headers["Host"];
+ reply.headers["Location"] = Anope::string("http") + (use_ssl ? "s" : "") + "://" + message.headers["Host"];
return true;
}
diff --git a/modules/extra/webcpanel/webcpanel.cpp b/modules/extra/webcpanel/webcpanel.cpp
index c23b6efbf..77cf606aa 100644
--- a/modules/extra/webcpanel/webcpanel.cpp
+++ b/modules/extra/webcpanel/webcpanel.cpp
@@ -9,6 +9,7 @@
Module *me;
Anope::string provider_name, template_name, template_base, page_title;
+bool use_ssl = false;
class ModuleWebCPanel : public Module
{
@@ -53,6 +54,7 @@ class ModuleWebCPanel : public Module
template_name = reader.ReadValue("webcpanel", "template", "template", 0);
template_base = db_dir + "/modules/webcpanel/templates/" + template_name;
page_title = reader.ReadValue("webcpanel", "title", "Anope IRC Services", 0);
+ use_ssl = reader.ReadFlag("webcpanel", "ssl", "no", 0); // This is dumb, is there a better way to do this?
service_reference<HTTPProvider> provider("HTTPProvider", provider_name);
if (!provider)
diff --git a/modules/extra/webcpanel/webcpanel.h b/modules/extra/webcpanel/webcpanel.h
index 926feaf53..99cb2ec3a 100644
--- a/modules/extra/webcpanel/webcpanel.h
+++ b/modules/extra/webcpanel/webcpanel.h
@@ -14,6 +14,7 @@
extern Module *me;
extern Anope::string provider_name, template_name, template_base, page_title;
+extern bool use_ssl;
struct SubSection
{
diff --git a/src/dns.cpp b/src/dns.cpp
index f88e9adfd..29c3134f7 100644
--- a/src/dns.cpp
+++ b/src/dns.cpp
@@ -519,7 +519,7 @@ void DNSManager::TCPSocket::Client::Reply(DNSPacket *p)
{
delete packet;
packet = p;
- SocketEngine::MarkWritable(this);
+ SocketEngine::Change(this, true, SF_WRITABLE);
}
bool DNSManager::TCPSocket::Client::ProcessRead()
@@ -535,9 +535,8 @@ bool DNSManager::TCPSocket::Client::ProcessRead()
short want_len = packet_buffer[0] << 8 | packet_buffer[1];
if (length >= want_len - 2)
{
- int len = length - 2;
- length = 0;
- return DNSEngine->HandlePacket(this, packet_buffer + 2, len, NULL);
+ SocketEngine::Change(this, false, SF_READABLE);
+ return DNSEngine->HandlePacket(this, packet_buffer + 2, length - 2, NULL);
}
return true;
}
@@ -565,7 +564,7 @@ bool DNSManager::TCPSocket::Client::ProcessWrite()
packet = NULL;
}
- SocketEngine::ClearWritable(this);
+ SocketEngine::Change(this, false, SF_WRITABLE);
return true; /* Do not return false here, bind is unhappy we close the connection so soon after sending */
}
@@ -591,7 +590,7 @@ DNSManager::UDPSocket::~UDPSocket()
void DNSManager::UDPSocket::Reply(DNSPacket *p)
{
packets.push_back(p);
- SocketEngine::MarkWritable(this);
+ SocketEngine::Change(this, true, SF_WRITABLE);
}
bool DNSManager::UDPSocket::ProcessRead()
@@ -626,7 +625,7 @@ bool DNSManager::UDPSocket::ProcessWrite()
}
if (packets.empty())
- SocketEngine::ClearWritable(this);
+ SocketEngine::Change(this, false, SF_WRITABLE);
return true;
}
@@ -848,7 +847,7 @@ bool DNSManager::CheckCache(DNSRequest *request)
for (cache_map::iterator it_end = this->cache.upper_bound(request->name); it != it_end; ++it)
{
ResourceRecord &rec = it->second;
- if (rec.created + rec.ttl >= Anope::CurTime)
+ if (rec.created + static_cast<time_t>(rec.ttl) >= Anope::CurTime)
record.answers.push_back(rec);
}
@@ -873,7 +872,7 @@ void DNSManager::Tick(time_t now)
it_next = it;
++it_next;
- if (req.created + req.ttl < now)
+ if (req.created + static_cast<time_t>(req.ttl) < now)
this->cache.erase(it);
}
}
diff --git a/src/socket_clients.cpp b/src/socket_clients.cpp
index 4d3a1e3ee..44d4b873a 100644
--- a/src/socket_clients.cpp
+++ b/src/socket_clients.cpp
@@ -56,8 +56,9 @@ void ConnectionSocket::OnConnect()
{
}
-void ConnectionSocket::OnError(const Anope::string &)
+void ConnectionSocket::OnError(const Anope::string &error)
{
+ Log(LOG_DEBUG) << "Socket error: " << error;
}
ClientSocket::ClientSocket(ListenSocket *ls, const sockaddrs &addr) : LS(ls), clientaddr(addr)
@@ -97,5 +98,6 @@ void ClientSocket::OnAccept()
void ClientSocket::OnError(const Anope::string &error)
{
+ Log(LOG_DEBUG) << "Socket error: " << error;
}
diff --git a/src/socket_transport.cpp b/src/socket_transport.cpp
index 30af95226..2297da2b2 100644
--- a/src/socket_transport.cpp
+++ b/src/socket_transport.cpp
@@ -70,7 +70,7 @@ bool BufferedSocket::ProcessWrite()
return false;
this->WriteBuffer = this->WriteBuffer.substr(count);
if (this->WriteBuffer.empty())
- SocketEngine::ClearWritable(this);
+ SocketEngine::Change(this, false, SF_WRITABLE);
return true;
}
@@ -83,7 +83,7 @@ bool BufferedSocket::Read(const Anope::string &buf)
void BufferedSocket::Write(const char *buffer, size_t l)
{
this->WriteBuffer += buffer + Anope::string("\r\n");
- SocketEngine::MarkWritable(this);
+ SocketEngine::Change(this, true, SF_WRITABLE);
}
void BufferedSocket::Write(const char *message, ...)
@@ -152,7 +152,7 @@ bool BinarySocket::ProcessWrite()
{
if (this->WriteBuffer.empty())
{
- SocketEngine::ClearWritable(this);
+ SocketEngine::Change(this, false, SF_WRITABLE);
return true;
}
@@ -173,7 +173,7 @@ bool BinarySocket::ProcessWrite()
}
if (this->WriteBuffer.empty())
- SocketEngine::ClearWritable(this);
+ SocketEngine::Change(this, false, SF_WRITABLE);
return true;
}
@@ -181,7 +181,7 @@ bool BinarySocket::ProcessWrite()
void BinarySocket::Write(const char *buffer, size_t l)
{
this->WriteBuffer.push_back(new DataBlock(buffer, l));
- SocketEngine::MarkWritable(this);
+ SocketEngine::Change(this, true, SF_WRITABLE);
}
void BinarySocket::Write(const char *message, ...)
diff --git a/src/socketengines/pipeengine_pipe.cpp b/src/socketengines/pipeengine_pipe.cpp
index dbded29b4..ac3a9cb2c 100644
--- a/src/socketengines/pipeengine_pipe.cpp
+++ b/src/socketengines/pipeengine_pipe.cpp
@@ -27,12 +27,13 @@ Pipe::Pipe() : Socket(-1), WritePipe(-1)
flags = fcntl(fds[1], F_GETFL, 0);
fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
- this->~Pipe();
+ this->~Socket();
this->Sock = fds[0];
this->WritePipe = fds[1];
- SocketEngine::AddSocket(this);
+ SocketEngine::Sockets[this->Sock] = this;
+ SocketEngine::Change(this, true, SF_READABLE);
}
Pipe::~Pipe()
diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp
index 481551289..41f67ebcc 100644
--- a/src/socketengines/socketengine_epoll.cpp
+++ b/src/socketengines/socketengine_epoll.cpp
@@ -19,107 +19,66 @@
#include <ulimit.h>
#include <errno.h>
-static long max;
static int EngineHandle;
-static epoll_event *events;
+static std::vector<epoll_event> events;
void SocketEngine::Init()
{
- max = ulimit(4, 0);
-
- if (max <= 0)
- throw SocketException("Can't determine maximum number of open sockets");
-
- EngineHandle = epoll_create(max / 4);
+ EngineHandle = epoll_create(4);
if (EngineHandle == -1)
throw SocketException("Could not initialize epoll socket engine: " + Anope::LastError());
-
- events = new epoll_event[max];
- memset(events, 0, sizeof(epoll_event) * max);
+
+ events.resize(DefaultSize);
}
void SocketEngine::Shutdown()
{
- for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end;)
- {
- Socket *s = it->second;
- ++it;
- delete s;
- }
- Sockets.clear();
-
- delete [] events;
-}
-
-void SocketEngine::AddSocket(Socket *s)
-{
- epoll_event ev;
-
- memset(&ev, 0, sizeof(ev));
-
- ev.events = EPOLLIN;
- ev.data.fd = s->GetFD();
-
- if (epoll_ctl(EngineHandle, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
- throw SocketException("Unable to add fd " + stringify(ev.data.fd) + " to epoll: " + Anope::LastError());
-
- Sockets[ev.data.fd] = s;
+ while (!Sockets.empty())
+ delete Sockets.begin()->second;
}
-void SocketEngine::DelSocket(Socket *s)
+void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
{
- epoll_event ev;
-
- memset(&ev, 0, sizeof(ev));
-
- ev.data.fd = s->GetFD();
-
- if (epoll_ctl(EngineHandle, EPOLL_CTL_DEL, ev.data.fd, &ev) == -1)
- throw SocketException("Unable to remove fd " + stringify(ev.data.fd) + " from epoll: " + Anope::LastError());
-
- Sockets.erase(ev.data.fd);
-}
-
-void SocketEngine::MarkWritable(Socket *s)
-{
- if (s->HasFlag(SF_WRITABLE))
+ if (set == s->HasFlag(flag))
return;
- epoll_event ev;
+ bool before_registered = s->HasFlag(SF_READABLE) || s->HasFlag(SF_WRITABLE);
- memset(&ev, 0, sizeof(ev));
-
- ev.events = EPOLLIN | EPOLLOUT;
- ev.data.fd = s->GetFD();
-
- if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
- throw SocketException("Unable to mark fd " + stringify(ev.data.fd) + " as writable in epoll: " + Anope::LastError());
-
- s->SetFlag(SF_WRITABLE);
-}
-
-void SocketEngine::ClearWritable(Socket *s)
-{
- if (!s->HasFlag(SF_WRITABLE))
- return;
+ if (set)
+ s->SetFlag(flag);
+ else
+ s->UnsetFlag(flag);
+
+ bool now_registered = s->HasFlag(SF_READABLE) || s->HasFlag(SF_WRITABLE);
epoll_event ev;
memset(&ev, 0, sizeof(ev));
- ev.events = EPOLLIN;
+ ev.events = (s->HasFlag(SF_READABLE) ? EPOLLIN : 0) | (s->HasFlag(SF_WRITABLE) ? EPOLLOUT : 0);
ev.data.fd = s->GetFD();
- if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
- throw SocketException("Unable clear mark fd " + stringify(ev.data.fd) + " as writable in epoll: " + Anope::LastError());
-
- s->UnsetFlag(SF_WRITABLE);
+ int mod;
+ if (!before_registered && now_registered)
+ mod = EPOLL_CTL_ADD;
+ else if (before_registered && !now_registered)
+ mod = EPOLL_CTL_DEL;
+ else if (before_registered && now_registered)
+ mod = EPOLL_CTL_MOD;
+ else
+ return;
+
+ if (epoll_ctl(EngineHandle, mod, ev.data.fd, &ev) == -1)
+ throw SocketException("Unable to epoll_ctl() fd " + stringify(ev.data.fd) + " to epoll: " + Anope::LastError());
}
void SocketEngine::Process()
{
- int total = epoll_wait(EngineHandle, events, max - 1, Config->ReadTimeout * 1000);
+ if (Sockets.size() > events.size())
+ events.resize(events.size() * 2);
+
+ int total = epoll_wait(EngineHandle, &events.front(), events.size(), Config->ReadTimeout * 1000);
Anope::CurTime = time(NULL);
/* EINTR can be given if the read timeout expires */
@@ -132,28 +91,31 @@ void SocketEngine::Process()
for (int i = 0; i < total; ++i)
{
- epoll_event *ev = &events[i];
+ epoll_event &ev = events[i];
- std::map<int, Socket *>::iterator it = Sockets.find(ev->data.fd);
+ std::map<int, Socket *>::iterator it = Sockets.find(ev.data.fd);
if (it == Sockets.end())
continue;
Socket *s = it->second;
- if (ev->events & (EPOLLHUP | EPOLLERR))
+ if (ev.events & (EPOLLHUP | EPOLLERR))
{
s->ProcessError();
- s->SetFlag(SF_DEAD);
delete s;
continue;
}
if (!s->Process())
+ {
+ if (s->HasFlag(SF_DEAD))
+ delete s;
continue;
+ }
- if ((ev->events & EPOLLIN) && !s->ProcessRead())
+ if ((ev.events & EPOLLIN) && !s->ProcessRead())
s->SetFlag(SF_DEAD);
- if ((ev->events & EPOLLOUT) && !s->ProcessWrite())
+ if ((ev.events & EPOLLOUT) && !s->ProcessWrite())
s->SetFlag(SF_DEAD);
if (s->HasFlag(SF_DEAD))
diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/socketengine_kqueue.cpp
index cc5909934..549773d75 100644
--- a/src/socketengines/socketengine_kqueue.cpp
+++ b/src/socketengines/socketengine_kqueue.cpp
@@ -11,8 +11,8 @@
#include "services.h"
#include "anope.h"
-#include "socketengine.h"
#include "sockets.h"
+#include "socketengine.h"
#include "logger.h"
#include "config.h"
@@ -21,19 +21,14 @@
#include <sys/time.h>
#include <errno.h>
-static int kq_fd, max_fds;
-static struct kevent *change_events, *event_events;
-static int change_count;
+static int kq_fd;
+static std::vector<struct kevent> change_events, event_events;
+static unsigned change_count;
-static struct kevent *GetChangeEvent()
+static inline struct kevent *GetChangeEvent()
{
- if (change_count == max_fds)
- {
- timespec zero_timespec = { 0, 0 };
- for (int i = 0; i < change_count; ++i)
- kevent(kq_fd, &change_events[i], 1, NULL, 0, &zero_timespec);
- change_count = 0;
- }
+ if (change_count == change_events.size())
+ change_events.resize(change_count * 2);
return &change_events[change_count++];
}
@@ -41,78 +36,49 @@ static struct kevent *GetChangeEvent()
void SocketEngine::Init()
{
kq_fd = kqueue();
- max_fds = getdtablesize();
if (kq_fd < 0)
throw SocketException("Unable to create kqueue engine: " + Anope::LastError());
- else if (max_fds <= 0)
- throw SocketException("Can't determine maximum number of open sockets");
-
- change_events = new struct kevent[max_fds];
- event_events = new struct kevent[max_fds];
-
- change_count = 0;
+
+ change_events.resize(DefaultSize);
+ event_events.resize(DefaultSize);
}
void SocketEngine::Shutdown()
{
- for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end;)
- {
- Socket *s = it->second;
- ++it;
- delete s;
- }
- Sockets.clear();
-
- delete [] change_events;
- delete [] event_events;
-}
-
-void SocketEngine::AddSocket(Socket *s)
-{
- struct kevent *event = GetChangeEvent();
- EV_SET(event, s->GetFD(), EVFILT_READ, EV_ADD, 0, 0, NULL);
-
- Sockets[s->GetFD()] = s;
-}
-
-void SocketEngine::DelSocket(Socket *s)
-{
- struct kevent *event = GetChangeEvent();
- EV_SET(event, s->GetFD(), EVFILT_READ, EV_DELETE, 0, 0, NULL);
-
- event = GetChangeEvent();
- EV_SET(event, s->GetFD(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
-
- Sockets.erase(s->GetFD());
+ while (!Sockets.empty())
+ delete Sockets.begin()->second;
}
-void SocketEngine::MarkWritable(Socket *s)
+void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
{
- if (s->HasFlag(SF_WRITABLE))
+ if (set == s->HasFlag(flag))
return;
- struct kevent *event = GetChangeEvent();
- EV_SET(event, s->GetFD(), EVFILT_WRITE, EV_ADD, 0, 0, NULL);
-
- s->SetFlag(SF_WRITABLE);
-}
-
-void SocketEngine::ClearWritable(Socket *s)
-{
- if (!s->HasFlag(SF_WRITABLE))
+ if (set)
+ s->SetFlag(flag);
+ else
+ s->UnsetFlag(flag);
+
+ int mod;
+ if (flag == SF_READABLE)
+ mod = EVFILT_READ;
+ else if (flag == SF_WRITABLE)
+ mod = EVFILT_WRITE;
+ else
return;
struct kevent *event = GetChangeEvent();
- EV_SET(event, s->GetFD(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
-
- s->UnsetFlag(SF_WRITABLE);
+ EV_SET(event, s->GetFD(), mod, set ? EV_ADD : EV_DELETE, 0, 0, NULL);
}
void SocketEngine::Process()
{
+ if (Sockets.size() > event_events.size())
+ event_events.resize(event_events.size() * 2);
+
static timespec kq_timespec = { Config->ReadTimeout, 0 };
- int total = kevent(kq_fd, change_events, change_count, event_events, max_fds, &kq_timespec);
+ int total = kevent(kq_fd, &change_events.front(), change_count, &event_events.front(), event_events.size(), &kq_timespec);
change_count = 0;
Anope::CurTime = time(NULL);
@@ -126,29 +92,32 @@ void SocketEngine::Process()
for (int i = 0; i < total; ++i)
{
- struct kevent *event = &event_events[i];
- if (event->flags & EV_ERROR)
+ struct kevent &event = event_events[i];
+ if (event.flags & EV_ERROR)
continue;
- std::map<int, Socket *>::iterator it = Sockets.find(event->ident);
+ std::map<int, Socket *>::iterator it = Sockets.find(event.ident);
if (it == Sockets.end())
continue;
Socket *s = it->second;
- if (event->flags & EV_EOF)
+ if (event.flags & EV_EOF)
{
s->ProcessError();
- s->SetFlag(SF_DEAD);
delete s;
continue;
}
if (!s->Process())
+ {
+ if (s->HasFlag(SF_DEAD))
+ delete s;
continue;
+ }
- if (event->filter == EVFILT_READ && !s->ProcessRead())
+ if (event.filter == EVFILT_READ && !s->ProcessRead())
s->SetFlag(SF_DEAD);
- else if (event->filter == EVFILT_WRITE && !s->ProcessWrite())
+ else if (event.filter == EVFILT_WRITE && !s->ProcessWrite())
s->SetFlag(SF_DEAD);
if (s->HasFlag(SF_DEAD))
diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp
index 766fea601..6b5d57a6e 100644
--- a/src/socketengines/socketengine_poll.cpp
+++ b/src/socketengines/socketengine_poll.cpp
@@ -11,10 +11,9 @@
#include "services.h"
#include "anope.h"
-#include "socketengine.h"
#include "sockets.h"
+#include "socketengine.h"
#include "config.h"
-#include "logger.h"
#include <errno.h>
@@ -32,121 +31,96 @@
# define POLLRDHUP POLLHUP
#endif
-static long max;
-static pollfd *events;
-static int SocketCount;
-static std::map<int, int> socket_positions;
+static std::vector<pollfd> events;
+static unsigned SocketCount;
+static std::map<int, unsigned> socket_positions;
void SocketEngine::Init()
{
- SocketCount = 0;
-
- rlimit fd_limit;
- if (getrlimit(RLIMIT_NOFILE, &fd_limit) == -1)
- throw CoreException(Anope::LastError());
-
- max = fd_limit.rlim_cur;
-
- events = new pollfd[max];
+ events.resize(DefaultSize);
}
void SocketEngine::Shutdown()
{
- for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end;)
- {
- Socket *s = it->second;
- ++it;
- delete s;
- }
- Sockets.clear();
-
- delete [] events;
+ while (!Sockets.empty())
+ delete Sockets.begin()->second;
}
-void SocketEngine::AddSocket(Socket *s)
+void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
{
- if (SocketCount == max)
- throw SocketException("Unable to add fd " + stringify(s->GetFD()) + " to poll: " + Anope::LastError());
-
- pollfd *ev = &events[SocketCount];
- ev->fd = s->GetFD();
- ev->events = POLLIN;
- ev->revents = 0;
-
- Sockets[ev->fd] = s;
- socket_positions[ev->fd] = SocketCount;
+ if (set == s->HasFlag(flag))
+ return;
- ++SocketCount;
-}
+ bool before_registered = s->HasFlag(SF_READABLE) || s->HasFlag(SF_WRITABLE);
-void SocketEngine::DelSocket(Socket *s)
-{
- std::map<int, int>::iterator pos = socket_positions.find(s->GetFD());
- if (pos == socket_positions.end())
- throw SocketException("Unable to remove fd " + stringify(s->GetFD()) + " from poll");
+ if (set)
+ s->SetFlag(flag);
+ else
+ s->UnsetFlag(flag);
+
+ bool now_registered = s->HasFlag(SF_READABLE) || s->HasFlag(SF_WRITABLE);
- if (pos->second != SocketCount - 1)
+ if (!before_registered && now_registered)
{
- pollfd *ev = &events[pos->second],
- *last_ev = &events[SocketCount - 1];
+ if (SocketCount >= events.size())
+ events.resize(events.size() * 2);
- ev->fd = last_ev->fd;
- ev->events = last_ev->events;
- ev->revents = last_ev->revents;
+ pollfd &ev = events[SocketCount];
+ memset(&ev, 0, sizeof(ev));
- socket_positions[ev->fd] = pos->second;
- }
-
- Sockets.erase(s->GetFD());
- socket_positions.erase(pos);
-
- --SocketCount;
-}
+ ev.fd = s->GetFD();
+ ev.events = (s->HasFlag(SF_READABLE) ? POLLIN : 0) | (s->HasFlag(SF_WRITABLE) ? POLLOUT : 0);
-void SocketEngine::MarkWritable(Socket *s)
-{
- if (s->HasFlag(SF_WRITABLE))
- return;
-
- std::map<int, int>::iterator pos = socket_positions.find(s->GetFD());
- if (pos == socket_positions.end())
- throw SocketException("Unable to mark fd " + stringify(s->GetFD()) + " as writable in poll");
+ socket_positions[ev.fd] = SocketCount;
+ ++SocketCount;
+ }
+ else if (before_registered && !now_registered)
+ {
+ std::map<int, unsigned>::iterator pos = socket_positions.find(s->GetFD());
+ if (pos == socket_positions.end())
+ throw SocketException("Unable to remove fd " + stringify(s->GetFD()) + " from poll, it does not exist?");
- pollfd *ev = &events[pos->second];
- ev->events |= POLLOUT;
-
- s->SetFlag(SF_WRITABLE);
-}
+ if (pos->second != SocketCount - 1)
+ {
+ pollfd &ev = events[pos->second],
+ &last_ev = events[SocketCount - 1];
-void SocketEngine::ClearWritable(Socket *s)
-{
- if (!s->HasFlag(SF_WRITABLE))
- return;
+ ev = last_ev;
- std::map<int, int>::iterator pos = socket_positions.find(s->GetFD());
- if (pos == socket_positions.end())
- throw SocketException("Unable clear mark fd " + stringify(s->GetFD()) + " as writable in poll");
+ socket_positions[ev.fd] = pos->second;
+ }
- pollfd *ev = &events[pos->second];
- ev->events &= ~POLLOUT;
+ socket_positions.erase(pos);
+ --SocketCount;
+ }
+ else if (before_registered && now_registered)
+ {
+ std::map<int, unsigned>::iterator pos = socket_positions.find(s->GetFD());
+ if (pos == socket_positions.end())
+ throw SocketException("Unable to modify fd " + stringify(s->GetFD()) + " in poll, it does not exist?");
- s->UnsetFlag(SF_WRITABLE);
+ pollfd &ev = events[pos->second];
+ ev.events = (s->HasFlag(SF_READABLE) ? POLLIN : 0) | (s->HasFlag(SF_WRITABLE) ? POLLOUT : 0);
+ }
}
void SocketEngine::Process()
{
- int total = poll(events, SocketCount, Config->ReadTimeout * 1000);
+ if (Sockets.size() > events.size())
+ events.resize(events.size() * 2);
+
+ int total = poll(&events.front(), events.size(), Config->ReadTimeout * 1000);
Anope::CurTime = time(NULL);
/* EINTR can be given if the read timeout expires */
- if (total == -1)
+ if (total < 0)
{
if (errno != EINTR)
Log() << "SockEngine::Process(): error: " << Anope::LastError();
return;
}
- for (int i = 0, processed = 0; i < SocketCount && processed != total; ++i)
+ for (unsigned i = 0, processed = 0; i < SocketCount && processed != static_cast<unsigned>(total); ++i)
{
pollfd *ev = &events[i];
@@ -161,13 +135,16 @@ void SocketEngine::Process()
if (ev->revents & (POLLERR | POLLRDHUP))
{
s->ProcessError();
- s->SetFlag(SF_DEAD);
delete s;
continue;
}
if (!s->Process())
+ {
+ if (s->HasFlag(SF_DEAD))
+ delete s;
continue;
+ }
if ((ev->revents & POLLIN) && !s->ProcessRead())
s->SetFlag(SF_DEAD);
diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp
index 2398047f3..0d8df20a2 100644
--- a/src/socketengines/socketengine_select.cpp
+++ b/src/socketengines/socketengine_select.cpp
@@ -11,8 +11,8 @@
#include "services.h"
#include "anope.h"
-#include "socketengine.h"
#include "sockets.h"
+#include "socketengine.h"
#include "logger.h"
#include "config.h"
@@ -28,56 +28,60 @@ static fd_set WriteFDs;
void SocketEngine::Init()
{
- MaxFD = 0;
- FDCount = 0;
FD_ZERO(&ReadFDs);
FD_ZERO(&WriteFDs);
}
void SocketEngine::Shutdown()
{
- for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end;)
- {
- Socket *s = it->second;
- ++it;
- delete s;
- }
- Sockets.clear();
+ while (!Sockets.empty())
+ delete Sockets.begin()->second;
}
-void SocketEngine::AddSocket(Socket *s)
+void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
{
- if (s->GetFD() > MaxFD)
- MaxFD = s->GetFD();
- FD_SET(s->GetFD(), &ReadFDs);
- Sockets[s->GetFD()] = s;
- ++FDCount;
-}
+ if (set == s->HasFlag(flag))
+ return;
-void SocketEngine::DelSocket(Socket *s)
-{
- if (s->GetFD() == MaxFD)
- --MaxFD;
- FD_CLR(s->GetFD(), &ReadFDs);
- FD_CLR(s->GetFD(), &WriteFDs);
- Sockets.erase(s->GetFD());
- --FDCount;
-}
+ bool before_registered = s->HasFlag(SF_READABLE) || s->HasFlag(SF_WRITABLE);
-void SocketEngine::MarkWritable(Socket *s)
-{
- if (s->HasFlag(SF_WRITABLE))
- return;
- FD_SET(s->GetFD(), &WriteFDs);
- s->SetFlag(SF_WRITABLE);
-}
+ if (set)
+ s->SetFlag(flag);
+ else
+ s->UnsetFlag(flag);
+
+ bool now_registered = s->HasFlag(SF_READABLE) || s->HasFlag(SF_WRITABLE);
-void SocketEngine::ClearWritable(Socket *s)
-{
- if (!s->HasFlag(SF_WRITABLE))
- return;
- FD_CLR(s->GetFD(), &WriteFDs);
- s->UnsetFlag(SF_WRITABLE);
+ if (!before_registered && now_registered)
+ {
+ if (s->GetFD() > MaxFD)
+ MaxFD = s->GetFD();
+ if (s->HasFlag(SF_READABLE))
+ FD_SET(s->GetFD(), &ReadFDs);
+ if (s->HasFlag(SF_WRITABLE))
+ FD_SET(s->GetFD(), &WriteFDs);
+ ++FDCount;
+ }
+ else if (before_registered && !now_registered)
+ {
+ if (s->GetFD() == MaxFD)
+ --MaxFD;
+ FD_CLR(s->GetFD(), &ReadFDs);
+ FD_CLR(s->GetFD(), &WriteFDs);
+ --FDCount;
+ }
+ else if (before_registered && now_registered)
+ {
+ if (s->HasFlag(SF_READABLE))
+ FD_SET(s->GetFD(), &ReadFDs);
+ else
+ FD_CLR(s->GetFD(), &ReadFDs);
+
+ if (s->HasFlag(SF_WRITABLE))
+ FD_SET(s->GetFD(), &WriteFDs);
+ else
+ FD_CLR(s->GetFD(), &WriteFDs);
+ }
}
void SocketEngine::Process()
@@ -123,13 +127,16 @@ void SocketEngine::Process()
if (has_error)
{
s->ProcessError();
- s->SetFlag(SF_DEAD);
delete s;
continue;
}
if (!s->Process())
+ {
+ if (s->HasFlag(SF_DEAD))
+ delete s;
continue;
+ }
if (has_read && !s->ProcessRead())
s->SetFlag(SF_DEAD);
diff --git a/src/sockets.cpp b/src/sockets.cpp
index 665db5ca2..5cf567de5 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -384,7 +384,7 @@ void SocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int por
s->OnError(Anope::LastError());
else
{
- SocketEngine::MarkWritable(s);
+ SocketEngine::Change(s, true, SF_WRITABLE);
s->SetFlag(SF_CONNECTING);
}
}
@@ -444,16 +444,19 @@ Socket::Socket(int sock, bool ipv6, int type) : Flags<SocketFlag>(SocketFlagStri
else
this->Sock = sock;
this->SetNonBlocking();
- SocketEngine::AddSocket(this);
+ SocketEngine::Sockets[this->Sock] = this;
+ SocketEngine::Change(this, true, SF_READABLE);
}
/** Default destructor
*/
Socket::~Socket()
{
- SocketEngine::DelSocket(this);
+ SocketEngine::Change(this, false, SF_READABLE);
+ SocketEngine::Change(this, false, SF_WRITABLE);
anope_close(this->Sock);
this->IO->Destroy();
+ SocketEngine::Sockets.erase(this->Sock);
}
/** Get the socket FD for this socket