X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsocketengines%2Fsocketengine_poll.cpp;h=16917ffbc658a6483c597658ac4412e8f726524e;hb=7aa5e059a8f66d91bd8b69c58c657ceb70b4baff;hp=3ed284166ccc13a61229bc102bd93e9fe6950db9;hpb=43847ec9c7e1a195163eb4c529f1c92fd1ace0a4;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index 3ed284166..16917ffbc 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -3,24 +3,110 @@ * +------------------------------------+ * * InspIRCd: (C) 2002-2009 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits + * See: http://wiki.inspircd.org/Credits * * This program is free but copyrighted software; see - * the file COPYING for details. + * the file COPYING for details. * * --------------------------------------------------- */ #include "inspircd.h" #include "exitcodes.h" -#include "socketengines/socketengine_poll.h" +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#ifndef __SOCKETENGINE_POLL__ +#define __SOCKETENGINE_POLL__ + +#include +#include +#include +#include "inspircd_config.h" +#include "inspircd.h" +#include "socketengine.h" + +#ifndef WINDOWS + #ifndef __USE_XOPEN + #define __USE_XOPEN /* fuck every fucking OS ever made. needed by poll.h to work.*/ + #endif + #include + #include +#else + /* *grumble* */ + #define struct pollfd WSAPOLLFD + #define poll WSAPoll +#endif + +class InspIRCd; + +/** A specialisation of the SocketEngine class, designed to use poll(). + */ +class PollEngine : public SocketEngine +{ +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::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 bool DelFd(EventHandler* eh, bool force = false); + virtual int DispatchEvents(); + virtual std::string GetName(); +}; + +#endif + #include +#ifdef __FreeBSD__ + #include +#endif -PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance) +PollEngine::PollEngine() { - // Poll requires no special setup (which is nice). CurrentSetSize = 0; - MAX_DESCRIPTORS = 0; +#ifndef __FreeBSD__ + int max = ulimit(4, 0); + if (max > 0) + { + MAX_DESCRIPTORS = max; + } + else + { + ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno)); + printf("ERROR: Can't determine maximum number of open sockets: %s\n", strerror(errno)); + ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE); + } +#else + int mib[2]; + size_t len; + + mib[0] = CTL_KERN; + mib[1] = KERN_MAXFILES; + len = sizeof(MAX_DESCRIPTORS); + sysctl(mib, 2, &MAX_DESCRIPTORS, &len, NULL, 0); +#endif ref = new EventHandler* [GetMaxFds()]; events = new struct pollfd[GetMaxFds()]; @@ -36,7 +122,17 @@ PollEngine::~PollEngine() delete[] events; } -bool PollEngine::AddFd(EventHandler* eh) +static int mask_to_poll(int event_mask) +{ + int rv = 0; + if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ)) + rv |= POLLIN; + if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) + rv |= POLLOUT; + return rv; +} + +bool PollEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) @@ -45,37 +141,43 @@ bool PollEngine::AddFd(EventHandler* eh) return false; } - if (GetRemainingFds() <= 1) - { - ServerInstance->Logs->Log("SOCKET",DEBUG,"No remaining FDs cannot add fd: %d", fd); - return false; - } - - if (ref[fd]) + if (fd_mappings.find(fd) != fd_mappings.end()) { ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd); return false; } - ref[fd] = eh; - events[fd].fd = fd; - if (eh->Readable()) - { - events[fd].events = POLLIN; - } - else - { - events[fd].events = POLLOUT; - } + unsigned int index = CurrentSetSize; - ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d)", fd, events[fd].events); + fd_mappings[fd] = index; + ref[index] = eh; + 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[fd].events, index); + SocketEngine::SetEventMask(eh, event_mask); CurrentSetSize++; return true; } -void PollEngine::WantWrite(EventHandler* eh) +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) { - events[eh->GetFd()].events = POLLIN | POLLOUT; + std::map::iterator it = fd_mappings.find(eh->GetFd()); + if (it == fd_mappings.end()) + { + ServerInstance->Logs->Log("SOCKET",DEBUG,"SetEvents() on unknown fd: %d", eh->GetFd()); + return; + } + + events[it->second].events = mask_to_poll(new_mask); } bool PollEngine::DelFd(EventHandler* eh, bool force) @@ -87,88 +189,94 @@ bool PollEngine::DelFd(EventHandler* eh, bool force) return false; } - events[fd].fd = -1; - events[fd].events = 0; + std::map::iterator it = fd_mappings.find(fd); + if (it == fd_mappings.end()) + { + ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd() on unknown fd: %d", fd); + return false; + } - CurrentSetSize--; - ref[fd] = NULL; + unsigned int index = it->second; + unsigned int last_index = CurrentSetSize - 1; + int last_fd = events[last_index].fd; - ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d", fd); - return true; -} + if (index != last_index) + { + // We need to move the last fd we got into this gap (gaps are evil!) -int PollEngine::GetMaxFds() -{ - if (MAX_DESCRIPTORS) - return MAX_DESCRIPTORS; + // So update the mapping for the last fd to its new position + fd_mappings[last_fd] = index; - int max = ulimit(4, 0); - if (max > 0) - { - MAX_DESCRIPTORS = max; - return max; - } - else - { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); - printf("ERROR: Can't determine maximum number of open sockets!\n"); - ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE); + // 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]; } - return 0; -} -int PollEngine::GetRemainingFds() -{ - return MAX_DESCRIPTORS - CurrentSetSize; + // 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); + events[last_index].fd = 0; + events[last_index].events = 0; + ref[last_index] = NULL; + + CurrentSetSize--; + + ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d (index: %d) " + "(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index); + return true; } int PollEngine::DispatchEvents() { - int i = poll(events, GetMaxFds() - 1, 1000); - int fd = 0; + int i = poll(events, CurrentSetSize, 1000); + int index; socklen_t codesize = sizeof(int); int errcode; int processed = 0; if (i > 0) { - for (fd = 0; fd < GetMaxFds() - 1 && processed != i; fd++) + for (index = 0; index < CurrentSetSize && processed != i; index++) { - if (events[fd].revents) + if (events[index].revents) processed++; + EventHandler* eh = ref[index]; + if (!eh) + continue; - if (events[fd].revents & POLLHUP) + if (events[index].revents & POLLHUP) { - if (ref[fd]) - ref[fd]->HandleEvent(EVENT_ERROR, 0); + eh->HandleEvent(EVENT_ERROR, 0); continue; } - if (events[fd].revents & POLLERR) + if (events[index].revents & POLLERR) { + // Get fd + int fd = events[index].fd; + // Get error number if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; - if (ref[fd]) - ref[fd]->HandleEvent(EVENT_ERROR, errcode); + eh->HandleEvent(EVENT_ERROR, errcode); continue; } - if (events[fd].revents & POLLOUT) + if (events[index].revents & POLLIN) { - // Switch to wanting read again - // event handlers have to request to write again if they need it - events[fd].events = POLLIN; - - - if (ref[fd]) - ref[fd]->HandleEvent(EVENT_WRITE); + SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK); + eh->HandleEvent(EVENT_READ); } - - if (events[fd].revents & POLLIN) + + if (events[index].revents & POLLOUT) { - if (ref[fd]) - ref[fd]->HandleEvent(EVENT_READ); + 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); } } } @@ -181,3 +289,7 @@ std::string PollEngine::GetName() return "poll"; } +SocketEngine* CreateSocketEngine() +{ + return new PollEngine; +}