diff options
-rw-r--r-- | data/modules.example.conf | 7 | ||||
-rw-r--r-- | include/socketengine.h | 22 | ||||
-rw-r--r-- | include/sockets.h | 1 | ||||
-rw-r--r-- | modules/extra/m_httpd.cpp | 15 | ||||
-rw-r--r-- | modules/extra/m_ssl.cpp | 18 | ||||
-rw-r--r-- | modules/extra/webcpanel/pages/chanserv/access.cpp | 2 | ||||
-rw-r--r-- | modules/extra/webcpanel/pages/chanserv/akick.cpp | 2 | ||||
-rw-r--r-- | modules/extra/webcpanel/pages/chanserv/set.cpp | 2 | ||||
-rw-r--r-- | modules/extra/webcpanel/pages/index.cpp | 2 | ||||
-rw-r--r-- | modules/extra/webcpanel/pages/logout.cpp | 2 | ||||
-rw-r--r-- | modules/extra/webcpanel/webcpanel.cpp | 2 | ||||
-rw-r--r-- | modules/extra/webcpanel/webcpanel.h | 1 | ||||
-rw-r--r-- | src/dns.cpp | 17 | ||||
-rw-r--r-- | src/socket_clients.cpp | 4 | ||||
-rw-r--r-- | src/socket_transport.cpp | 10 | ||||
-rw-r--r-- | src/socketengines/pipeengine_pipe.cpp | 5 | ||||
-rw-r--r-- | src/socketengines/socketengine_epoll.cpp | 120 | ||||
-rw-r--r-- | src/socketengines/socketengine_kqueue.cpp | 111 | ||||
-rw-r--r-- | src/socketengines/socketengine_poll.cpp | 143 | ||||
-rw-r--r-- | src/socketengines/socketengine_select.cpp | 87 | ||||
-rw-r--r-- | src/sockets.cpp | 9 |
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 |