1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
16 #include <sys/select.h>
18 /* +------------------------------------+
19 * | Inspire Internet Relay Chat Daemon |
20 * +------------------------------------+
22 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
23 * See: http://wiki.inspircd.org/Credits
25 * This program is free but copyrighted software; see
26 * the file COPYING for details.
28 * ---------------------------------------------------
31 #ifndef __SOCKETENGINE_SELECT__
32 #define __SOCKETENGINE_SELECT__
38 #include <sys/select.h>
40 #include "inspircd_config.h"
42 #include "socketengine.h"
44 /** A specialisation of the SocketEngine class, designed to use traditional select().
46 class SelectEngine : public SocketEngine
49 /** Create a new SelectEngine
52 /** Delete a SelectEngine
54 virtual ~SelectEngine();
55 virtual bool AddFd(EventHandler* eh, int event_mask);
56 virtual bool DelFd(EventHandler* eh, bool force = false);
57 void OnSetEvent(EventHandler* eh, int, int);
58 virtual int DispatchEvents();
59 virtual std::string GetName();
66 SelectEngine::SelectEngine()
68 MAX_DESCRIPTORS = FD_SETSIZE;
71 ref = new EventHandler* [GetMaxFds()];
72 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
75 SelectEngine::~SelectEngine()
80 bool SelectEngine::AddFd(EventHandler* eh, int event_mask)
83 if ((fd < 0) || (fd > GetMaxFds() - 1))
90 SocketEngine::SetEventMask(eh, event_mask);
93 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
97 bool SelectEngine::DelFd(EventHandler* eh, bool force)
101 if ((fd < 0) || (fd > GetMaxFds() - 1))
107 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
111 void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
113 // deal with it later
116 int SelectEngine::DispatchEvents()
120 socklen_t codesize = sizeof(int);
123 fd_set wfdset, rfdset, errfdset;
128 /* Populate the select FD sets (this is why select sucks compared to epoll, kqueue, IOCP) */
129 for (int i = 0; i < FD_SETSIZE; i++)
131 EventHandler* eh = ref[i];
134 int state = eh->GetEventMask();
135 if (state & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
137 if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
139 FD_SET (i, &errfdset);
142 /* One second wait */
146 sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
148 /* Nothing to process this time around */
152 for (int i = 0; i < FD_SETSIZE; i++)
154 EventHandler* ev = ref[i];
157 if (FD_ISSET (i, &errfdset))
160 if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
163 ev->HandleEvent(EVENT_ERROR, errcode);
168 /* NOTE: This is a pair of seperate if statements as the socket
169 * may be in both read and writeable state at the same time.
170 * If an error event occurs above it is not worth processing the
171 * read and write states even if set.
173 if (FD_ISSET (i, &rfdset))
176 SetEventMask(ev, ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
177 ev->HandleEvent(EVENT_READ);
179 if (FD_ISSET (i, &wfdset))
182 SetEventMask(ev, ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
183 ev->HandleEvent(EVENT_WRITE);
192 std::string SelectEngine::GetName()
197 SocketEngine* CreateSocketEngine()
199 return new SelectEngine;