1 /* +------------------------------------+
\r * | Inspire Internet Relay Chat Daemon |
\r * +------------------------------------+
\r *
\r * InspIRCd: (C) 2002-2007 InspIRCd Development Team
\r * See: http://www.inspircd.org/wiki/index.php/Credits
\r *
\r * This program is free but copyrighted software; see
\r * the file COPYING for details.
\r *
\r * ---------------------------------------------------
\r */
\r\r#include "inspircd.h"
\r#include "exitcodes.h"
\r#include <sys/epoll.h>
\r#include "socketengine_epoll.h"
\r\rEPollEngine::EPollEngine(InspIRCd* Instance) : SocketEngine(Instance)
\r{
\r EngineHandle = epoll_create(MAX_DESCRIPTORS);
\r\r if (EngineHandle == -1)
\r {
\r ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
\r ServerInstance->Log(SPARSE,"ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.");
\r printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
\r printf("ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.\n");
\r InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);
\r }
\r CurrentSetSize = 0;
\r}
\r\rEPollEngine::~EPollEngine()
\r{
\r close(EngineHandle);
\r}
\r\rbool EPollEngine::AddFd(EventHandler* eh)
\r{
\r int fd = eh->GetFd();
\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))
\r return false;
\r\r if (GetRemainingFds() <= 1)
\r return false;
\r\r if (ref[fd])
\r return false;
\r\r ref[fd] = eh;
\r struct epoll_event ev;
\r memset(&ev,0,sizeof(struct epoll_event));
\r eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT;
\r ev.data.fd = fd;
\r int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
\r if (i < 0)
\r {
\r return false;
\r }
\r\r ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
\r CurrentSetSize++;
\r return true;
\r}
\r\rvoid EPollEngine::WantWrite(EventHandler* eh)
\r{
\r /** Use oneshot so that the system removes the writeable
\r * status for us and saves us a call.
\r */
\r struct epoll_event ev;
\r memset(&ev,0,sizeof(struct epoll_event));
\r ev.events = EPOLLOUT;
\r ev.data.fd = eh->GetFd();
\r epoll_ctl(EngineHandle, EPOLL_CTL_MOD, eh->GetFd(), &ev);
\r}
\r\rbool EPollEngine::DelFd(EventHandler* eh, bool force)
\r{
\r int fd = eh->GetFd();
\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))
\r return false;
\r\r struct epoll_event ev;
\r memset(&ev,0,sizeof(struct epoll_event));
\r eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT;
\r ev.data.fd = fd;
\r int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
\r\r if (i < 0 && !force)
\r return false;
\r\r CurrentSetSize--;
\r ref[fd] = NULL;
\r\r ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
\r return true;
\r}
\r\rint EPollEngine::GetMaxFds()
\r{
\r return MAX_DESCRIPTORS;
\r}
\r\rint EPollEngine::GetRemainingFds()
\r{
\r return MAX_DESCRIPTORS - CurrentSetSize;
\r}
\r\rint EPollEngine::DispatchEvents()
\r{
\r socklen_t codesize;
\r int errcode;
\r int i = epoll_wait(EngineHandle, events, MAX_DESCRIPTORS, 1000);
\r for (int j = 0; j < i; j++)
\r {
\r if (events[j].events & EPOLLHUP)
\r {
\r if (ref[events[j].data.fd])
\r ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, 0);
\r continue;
\r }
\r if (events[j].events & EPOLLERR)
\r {
\r /* Get error number */
\r if (getsockopt(events[j].data.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
\r errcode = errno;
\r if (ref[events[j].data.fd])
\r ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, errcode);
\r continue;
\r }
\r if (events[j].events & EPOLLOUT)
\r {
\r struct epoll_event ev;
\r memset(&ev,0,sizeof(struct epoll_event));
\r ev.events = EPOLLIN;
\r ev.data.fd = events[j].data.fd;
\r epoll_ctl(EngineHandle, EPOLL_CTL_MOD, events[j].data.fd, &ev);
\r if (ref[events[j].data.fd])
\r ref[events[j].data.fd]->HandleEvent(EVENT_WRITE);
\r }
\r else
\r {
\r if (ref[events[j].data.fd])
\r ref[events[j].data.fd]->HandleEvent(EVENT_READ);
\r }
\r }
\r\r return i;
\r}
\r\rstd::string EPollEngine::GetName()
\r{
\r return "epoll";
\r}
\r\r