X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsocketengines%2Fsocketengine_poll.cpp;h=8fa0a13c5ad256958f9bde0f843d2b5aac5b6084;hb=72a6b6077644abbdad1a61acbbd07bd01ba1b9bd;hp=e38e0fac1c4f67f537a921f428fcb48cb7063aa0;hpb=7525d32ac0d85ff1957f61ec653f78702093a8a7;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index e38e0fac1..8fa0a13c5 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -1,6 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2014 Adam * Copyright (C) 2009 Daniel De Graaf * Copyright (C) 2009 Uli Schlachter * Copyright (C) 2009 Craig Edwards @@ -20,65 +21,31 @@ */ -#include "inspircd.h" -#include "exitcodes.h" - -#ifndef SOCKETENGINE_POLL -#define SOCKETENGINE_POLL - #include #include #include #include -#include "inspircd_config.h" +#include "exitcodes.h" #include "inspircd.h" #include "socketengine.h" -#ifndef _WIN32 -# ifndef __USE_XOPEN -# define __USE_XOPEN /* fuck every fucking OS ever made. needed by poll.h to work.*/ -# endif -# include -# include -# include -#else -# define struct pollfd WSAPOLLFD -# define poll WSAPoll -#endif - -class InspIRCd; +#include +#include /** A specialisation of the SocketEngine class, designed to use poll(). */ -class PollEngine : public SocketEngine +namespace { -private: /** These are used by poll() to hold socket events */ - struct pollfd *events; - /** This map maps fds to an index in the events array. + std::vector events(16); + /** This vector maps fds to an index in the events array. */ - std::map fd_mappings; -public: - /** Create a new PollEngine - */ - PollEngine(); - /** Delete a PollEngine - */ - virtual ~PollEngine(); - virtual bool AddFd(EventHandler* eh, int event_mask); - virtual void OnSetEvent(EventHandler* eh, int old_mask, int new_mask); - virtual EventHandler* GetRef(int fd); - virtual void DelFd(EventHandler* eh); - virtual int DispatchEvents(); - virtual std::string GetName(); -}; - -#endif - -PollEngine::PollEngine() + std::vector fd_mappings(16); +} + +void SocketEngine::Init() { - CurrentSetSize = 0; struct rlimit limits; if (!getrlimit(RLIMIT_NOFILE, &limits)) { @@ -86,23 +53,18 @@ PollEngine::PollEngine() } else { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno)); std::cout << "ERROR: Can't determine maximum number of open sockets: " << strerror(errno) << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); } +} - ref = new EventHandler* [GetMaxFds()]; - events = new struct pollfd[GetMaxFds()]; - - memset(events, 0, GetMaxFds() * sizeof(struct pollfd)); - memset(ref, 0, GetMaxFds() * sizeof(EventHandler*)); +void SocketEngine::Deinit() +{ } -PollEngine::~PollEngine() +void SocketEngine::RecoverFromFork() { - // No destruction required, either. - delete[] ref; - delete[] events; } static int mask_to_poll(int event_mask) @@ -115,71 +77,70 @@ static int mask_to_poll(int event_mask) return rv; } -bool PollEngine::AddFd(EventHandler* eh, int event_mask) +bool SocketEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); return false; } - if (fd_mappings.find(fd) != fd_mappings.end()) + if (static_cast(fd) < fd_mappings.size() && fd_mappings[fd] != -1) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); return false; } unsigned int index = CurrentSetSize; + if (!SocketEngine::AddFdRef(eh)) + { + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); + return false; + } + + while (static_cast(fd) >= fd_mappings.size()) + fd_mappings.resize(fd_mappings.size() * 2, -1); fd_mappings[fd] = index; - ref[index] = eh; + + ResizeDouble(events); events[index].fd = fd; events[index].events = mask_to_poll(event_mask); - ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[index].events, index); - SocketEngine::SetEventMask(eh, event_mask); - CurrentSetSize++; + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d (%d; index %d)", fd, events[index].events, index); + eh->SetEventMask(event_mask); return true; } -EventHandler* PollEngine::GetRef(int fd) -{ - std::map::iterator it = fd_mappings.find(fd); - if (it == fd_mappings.end()) - return NULL; - return ref[it->second]; -} - -void PollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) +void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) { - std::map::iterator it = fd_mappings.find(eh->GetFd()); - if (it == fd_mappings.end()) + int fd = eh->GetFd(); + if (fd < 0 || static_cast(fd) >= fd_mappings.size() || fd_mappings[fd] == -1) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"SetEvents() on unknown fd: %d", eh->GetFd()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SetEvents() on unknown fd: %d", eh->GetFd()); return; } - events[it->second].events = mask_to_poll(new_mask); + events[fd_mappings[fd]].events = mask_to_poll(new_mask); } -void PollEngine::DelFd(EventHandler* eh) +void SocketEngine::DelFd(EventHandler* eh) { int fd = eh->GetFd(); if ((fd < 0) || (fd > MAX_DESCRIPTORS)) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); return; } - std::map::iterator it = fd_mappings.find(fd); - if (it == fd_mappings.end()) + if (static_cast(fd) >= fd_mappings.size() || fd_mappings[fd] == -1) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd() on unknown fd: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd() on unknown fd: %d", fd); return; } - unsigned int index = it->second; + unsigned int index = fd_mappings[fd]; unsigned int last_index = CurrentSetSize - 1; int last_fd = events[last_index].fd; @@ -193,89 +154,78 @@ void PollEngine::DelFd(EventHandler* eh) // move last_fd from last_index into index events[index].fd = last_fd; events[index].events = events[last_index].events; - - ref[index] = ref[last_index]; } // Now remove all data for the last fd we got into out list. // Above code made sure this always is right - fd_mappings.erase(it); + fd_mappings[fd] = -1; events[last_index].fd = 0; events[last_index].events = 0; - ref[last_index] = NULL; - CurrentSetSize--; + SocketEngine::DelFdRef(eh); - ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d (index: %d) " + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d (index: %d) " "(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index); } -int PollEngine::DispatchEvents() +int SocketEngine::DispatchEvents() { - int i = poll(events, CurrentSetSize, 1000); - int index; - socklen_t codesize = sizeof(int); - int errcode; + int i = poll(&events[0], CurrentSetSize, 1000); int processed = 0; ServerInstance->UpdateTime(); - if (i > 0) + for (int index = 0; index < CurrentSetSize && processed < i; index++) { - for (index = 0; index < CurrentSetSize && processed != i; index++) + struct pollfd& pfd = events[index]; + + // Copy these in case the vector gets resized and pfd invalidated + const int fd = pfd.fd; + const short revents = pfd.revents; + + if (revents) + processed++; + + EventHandler* eh = GetRef(fd); + if (!eh) + continue; + + if (revents & POLLHUP) { - if (events[index].revents) - processed++; - EventHandler* eh = ref[index]; - if (!eh) - continue; + eh->HandleEvent(EVENT_ERROR, 0); + continue; + } + + if (revents & POLLERR) + { + // Get error number + socklen_t codesize = sizeof(int); + int errcode; + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) + errcode = errno; + eh->HandleEvent(EVENT_ERROR, errcode); + continue; + } - if (events[index].revents & POLLHUP) - { - eh->HandleEvent(EVENT_ERROR, 0); + if (revents & POLLIN) + { + eh->SetEventMask(eh->GetEventMask() & ~FD_READ_WILL_BLOCK); + eh->HandleEvent(EVENT_READ); + if (eh != GetRef(fd)) + // whoops, deleted out from under us continue; - } + } - if (events[index].revents & POLLERR) - { - // Get fd - int fd = events[index].fd; + if (revents & POLLOUT) + { + int mask = eh->GetEventMask(); + mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE); + eh->SetEventMask(mask); - // Get error number - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) - errcode = errno; - eh->HandleEvent(EVENT_ERROR, errcode); - continue; - } - - if (events[index].revents & POLLIN) - { - SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK); - eh->HandleEvent(EVENT_READ); - if (eh != ref[index]) - // whoops, deleted out from under us - continue; - } - - if (events[index].revents & POLLOUT) - { - int mask = eh->GetEventMask(); - mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE); - SetEventMask(eh, mask); - events[index].events = mask_to_poll(mask); - eh->HandleEvent(EVENT_WRITE); - } + // The vector could've been resized, reference can be invalid by now; don't use it + events[index].events = mask_to_poll(mask); + eh->HandleEvent(EVENT_WRITE); } } return i; } - -std::string PollEngine::GetName() -{ - return "poll"; -} - -SocketEngine* CreateSocketEngine() -{ - return new PollEngine; -}