X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsocketengines%2Fsocketengine_poll.cpp;h=e38e0fac1c4f67f537a921f428fcb48cb7063aa0;hb=4c751dbbe8945e5efc230a59b0ed51c2ba10cf92;hp=cee6a90cb59ee023cf533e046b535951302a230c;hpb=b6dbd6caab62bc2c0d11ce5a45d511611eb9c2ef;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index cee6a90cb..e38e0fac1 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -1,29 +1,95 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon * - * InspIRCd: (C) 2002-2009 InspIRCd Development Team - * See: http://wiki.inspircd.org/Credits + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2009 Uli Schlachter + * Copyright (C) 2009 Craig Edwards + * Copyright (C) 2008 Robin Burchell * - * This program is free but copyrighted software; see - * the file COPYING for details. + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. * - * --------------------------------------------------- + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + #include "inspircd.h" #include "exitcodes.h" -#include "socketengines/socketengine_poll.h" -#include -#ifdef __FreeBSD__ - #include + +#ifndef SOCKETENGINE_POLL +#define SOCKETENGINE_POLL + +#include +#include +#include +#include +#include "inspircd_config.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; + +/** 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 void DelFd(EventHandler* eh); + virtual int DispatchEvents(); + virtual std::string GetName(); +}; + #endif -PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance) +PollEngine::PollEngine() { - // Poll requires no special setup (which is nice). CurrentSetSize = 0; - MAX_DESCRIPTORS = 0; + struct rlimit limits; + if (!getrlimit(RLIMIT_NOFILE, &limits)) + { + MAX_DESCRIPTORS = limits.rlim_cur; + } + else + { + ServerInstance->Logs->Log("SOCKET", 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()]; @@ -39,7 +105,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)) @@ -48,12 +124,6 @@ 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 (fd_mappings.find(fd) != fd_mappings.end()) { ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd); @@ -65,16 +135,10 @@ bool PollEngine::AddFd(EventHandler* eh) fd_mappings[fd] = index; ref[index] = eh; events[index].fd = fd; - if (eh->Readable()) - { - events[index].events = POLLIN; - } - else - { - events[index].events = POLLOUT; - } + 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); + ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[index].events, index); + SocketEngine::SetEventMask(eh, event_mask); CurrentSetSize++; return true; } @@ -87,32 +151,32 @@ EventHandler* PollEngine::GetRef(int fd) return ref[it->second]; } -void PollEngine::WantWrite(EventHandler* eh) +void PollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) { std::map::iterator it = fd_mappings.find(eh->GetFd()); if (it == fd_mappings.end()) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"WantWrite() on unknown fd: %d", eh->GetFd()); + ServerInstance->Logs->Log("SOCKET",DEBUG,"SetEvents() on unknown fd: %d", eh->GetFd()); return; } - events[it->second].events = POLLIN | POLLOUT; + events[it->second].events = mask_to_poll(new_mask); } -bool PollEngine::DelFd(EventHandler* eh, bool force) +void PollEngine::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()); - return false; + return; } 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; + return; } unsigned int index = it->second; @@ -144,49 +208,6 @@ bool PollEngine::DelFd(EventHandler* eh, bool force) 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::GetMaxFds() -{ -#ifndef __FreeBSD__ - if (MAX_DESCRIPTORS) - return MAX_DESCRIPTORS; - - int max = ulimit(4, 0); - if (max > 0) - { - MAX_DESCRIPTORS = max; - return max; - } - else - { - MAX_DESCRIPTORS = 0; - 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); - } - return 0; -#else - if (!MAX_DESCRIPTORS) - { - int mib[2], maxfiles; - size_t len; - - mib[0] = CTL_KERN; - mib[1] = KERN_MAXFILES; - len = sizeof(maxfiles); - sysctl(mib, 2, &maxfiles, &len, NULL, 0); - MAX_DESCRIPTORS = maxfiles; - return maxfiles; - } - return MAX_DESCRIPTORS; -#endif -} - -int PollEngine::GetRemainingFds() -{ - return MAX_DESCRIPTORS - CurrentSetSize; } int PollEngine::DispatchEvents() @@ -196,6 +217,7 @@ int PollEngine::DispatchEvents() socklen_t codesize = sizeof(int); int errcode; int processed = 0; + ServerInstance->UpdateTime(); if (i > 0) { @@ -203,11 +225,13 @@ int PollEngine::DispatchEvents() { if (events[index].revents) processed++; + EventHandler* eh = ref[index]; + if (!eh) + continue; if (events[index].revents & POLLHUP) { - if (ref[index]) - ref[index]->HandleEvent(EVENT_ERROR, 0); + eh->HandleEvent(EVENT_ERROR, 0); continue; } @@ -219,25 +243,26 @@ int PollEngine::DispatchEvents() // Get error number if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; - if (ref[index]) - ref[index]->HandleEvent(EVENT_ERROR, errcode); + eh->HandleEvent(EVENT_ERROR, errcode); continue; } - if (events[index].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[index].events = POLLIN; - - if (ref[index]) - ref[index]->HandleEvent(EVENT_WRITE); + 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 & POLLIN) + + if (events[index].revents & POLLOUT) { - if (ref[index]) - ref[index]->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); } } } @@ -250,3 +275,7 @@ std::string PollEngine::GetName() return "poll"; } +SocketEngine* CreateSocketEngine() +{ + return new PollEngine; +}