*/
-#ifndef SOCKETENGINE_POLL
-#define SOCKETENGINE_POLL
-
-#include <iostream>
-#include <vector>
-#include <string>
-#include <map>
#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 <poll.h>
-# include <sys/poll.h>
-# include <sys/resource.h>
-#else
-# define struct pollfd WSAPOLLFD
-# define poll WSAPoll
-#endif
-
-class InspIRCd;
+
+#include <sys/poll.h>
+#include <sys/resource.h>
/** 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
*/
- std::vector<struct pollfd> events;
+ std::vector<struct pollfd> events(16);
/** This vector maps fds to an index in the events array.
*/
- std::vector<int> fd_mappings;
-public:
- /** Create a new PollEngine
- */
- PollEngine();
- virtual bool AddFd(EventHandler* eh, int event_mask);
- virtual void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
- virtual void DelFd(EventHandler* eh);
- virtual int DispatchEvents();
- virtual std::string GetName();
-};
-
-#endif
+ std::vector<int> fd_mappings(16);
+}
-PollEngine::PollEngine() : events(1), fd_mappings(1)
+void SocketEngine::Init()
{
- CurrentSetSize = 0;
struct rlimit limits;
if (!getrlimit(RLIMIT_NOFILE, &limits))
{
}
else
{
- 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);
+ // MAX_DESCRIPTORS is mainly used for display purposes, it's not a problem that getrlimit() failed
+ MAX_DESCRIPTORS = -1;
}
}
+void SocketEngine::Deinit()
+{
+}
+
+void SocketEngine::RecoverFromFork()
+{
+}
+
static int mask_to_poll(int event_mask)
{
int rv = 0;
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))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d)", fd);
return false;
}
return false;
}
- if (!SocketEngine::AddFd(eh))
+ unsigned int index = CurrentSetSize;
+
+ if (!SocketEngine::AddFdRef(eh))
{
ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd);
return false;
}
- unsigned int index = CurrentSetSize;
-
while (static_cast<unsigned int>(fd) >= fd_mappings.size())
fd_mappings.resize(fd_mappings.size() * 2, -1);
fd_mappings[fd] = index;
events[index].events = mask_to_poll(event_mask);
ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d (%d; index %d)", fd, events[index].events, index);
- SocketEngine::SetEventMask(eh, event_mask);
- CurrentSetSize++;
+ eh->SetEventMask(event_mask);
return true;
}
-void PollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
+void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
{
int fd = eh->GetFd();
if (fd < 0 || static_cast<unsigned int>(fd) >= fd_mappings.size() || fd_mappings[fd] == -1)
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))
+ if (fd < 0)
{
- ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d)", fd);
return;
}
events[last_index].fd = 0;
events[last_index].events = 0;
- SocketEngine::DelFd(eh);
-
- CurrentSetSize--;
+ SocketEngine::DelFdRef(eh);
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[0], CurrentSetSize, 1000);
- int index;
- socklen_t codesize = sizeof(int);
- int errcode;
int processed = 0;
ServerInstance->UpdateTime();
- for (index = 0; index < CurrentSetSize && processed < i; index++)
+ for (int index = 0; index < CurrentSetSize && processed < i; index++)
{
struct pollfd& pfd = events[index];
- if (pfd.revents)
+ // 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(pfd.fd);
+ EventHandler* eh = GetRef(fd);
if (!eh)
continue;
- if (pfd.revents & POLLHUP)
+ if (revents & POLLHUP)
{
- eh->HandleEvent(EVENT_ERROR, 0);
+ eh->OnEventHandlerError(0);
continue;
}
- if (pfd.revents & POLLERR)
+ if (revents & POLLERR)
{
// Get error number
- if (getsockopt(pfd.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+ socklen_t codesize = sizeof(int);
+ int errcode;
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
errcode = errno;
- eh->HandleEvent(EVENT_ERROR, errcode);
+ eh->OnEventHandlerError(errcode);
continue;
}
- if (pfd.revents & POLLIN)
+ if (revents & POLLIN)
{
- SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
- eh->HandleEvent(EVENT_READ);
- if (eh != GetRef(pfd.fd))
+ eh->SetEventMask(eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
+ eh->OnEventHandlerRead();
+ if (eh != GetRef(fd))
// whoops, deleted out from under us
continue;
}
- if (pfd.revents & POLLOUT)
+ if (revents & POLLOUT)
{
int mask = eh->GetEventMask();
mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE);
- SetEventMask(eh, mask);
- pfd.events = mask_to_poll(mask);
- eh->HandleEvent(EVENT_WRITE);
+ eh->SetEventMask(mask);
+
+ // The vector could've been resized, reference can be invalid by now; don't use it
+ events[index].events = mask_to_poll(mask);
+ eh->eh->OnEventHandlerWrite();
}
}
return i;
}
-
-std::string PollEngine::GetName()
-{
- return "poll";
-}
-
-SocketEngine* CreateSocketEngine()
-{
- return new PollEngine;
-}