/* +------------------------------------+ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * * InspIRCd: (C) 2002-2008 InspIRCd Development Team * See: http://www.inspircd.org/wiki/index.php/Credits * * This program is free but copyrighted software; see * the file COPYING for details. * * --------------------------------------------------- */ #include "inspircd.h" #include "exitcodes.h" #include "socketengine_poll.h" PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance) { // Poll requires no special setup (which is nice). CurrentSetSize = 0; memset(&events, 0, MAX_DESCRIPTORS); } PollEngine::~PollEngine() { // No destruction required, either. } bool PollEngine::AddFd(EventHandler* eh) { int fd = eh->GetFd(); if ((fd < 0) || (fd > MAX_DESCRIPTORS)) return false; if (GetRemainingFds() <= 1) return false; if (ref[fd]) return false; ref[fd] = eh; events[fd].fd = fd; if (eh->Readable()) { events[fd].events = POLLIN; } else { events[fd].events = POLLOUT; } ServerInstance->Log(DEBUG,"New file descriptor: %d (%d)", fd, events[fd].events); CurrentSetSize++; return true; } void PollEngine::WantWrite(EventHandler* eh) { events[eh->GetFd()].events = POLLIN | POLLOUT; } bool PollEngine::DelFd(EventHandler* eh, bool force) { int fd = eh->GetFd(); if ((fd < 0) || (fd > MAX_DESCRIPTORS)) return false; events[fd].fd = -1; events[fd].events = 0; CurrentSetSize--; ref[fd] = NULL; ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd); return true; } int PollEngine::GetMaxFds() { return MAX_DESCRIPTORS; } int PollEngine::GetRemainingFds() { return MAX_DESCRIPTORS - CurrentSetSize; } int PollEngine::DispatchEvents() { int i = poll(events, MAX_DESCRIPTORS, 1000); int fd = 0; socklen_t codesize = sizeof(int); int errcode; int processed = 0; if (i > 0) { for (fd = 0; fd < MAX_DESCRIPTORS && processed != i; fd++) { if (events[fd].revents) processed++; if (events[fd].revents & POLLHUP) { if (ref[fd]) ref[fd]->HandleEvent(EVENT_ERROR, 0); continue; } if (events[fd].revents & POLLERR) { // Get error number if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; if (ref[fd]) ref[fd]->HandleEvent(EVENT_ERROR, errcode); continue; } if (events[fd].revents & POLLOUT) { // 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); } if (events[fd].revents & POLLIN) { if (ref[fd]) ref[fd]->HandleEvent(EVENT_READ); } } } return i; } std::string PollEngine::GetName() { return "poll"; }