2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5 * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
7 * This file is part of InspIRCd. InspIRCd is free software: you can
8 * redistribute it and/or modify it under the terms of the GNU General Public
9 * License as published by the Free Software Foundation, version 2.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "inspircd_config.h"
24 #include "socketengine.h"
27 #include <sys/select.h>
30 /** A specialisation of the SocketEngine class, designed to use traditional select().
32 class SelectEngine : public SocketEngine
35 /** Create a new SelectEngine
38 /** Delete a SelectEngine
40 virtual ~SelectEngine();
41 virtual bool AddFd(EventHandler* eh, int event_mask);
42 virtual void DelFd(EventHandler* eh);
43 void OnSetEvent(EventHandler* eh, int, int);
44 virtual int DispatchEvents();
45 virtual std::string GetName();
48 SelectEngine::SelectEngine()
50 MAX_DESCRIPTORS = FD_SETSIZE;
53 ref = new EventHandler* [GetMaxFds()];
54 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
57 SelectEngine::~SelectEngine()
62 bool SelectEngine::AddFd(EventHandler* eh, int event_mask)
65 if ((fd < 0) || (fd > GetMaxFds() - 1))
72 SocketEngine::SetEventMask(eh, event_mask);
75 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
79 void SelectEngine::DelFd(EventHandler* eh)
83 if ((fd < 0) || (fd > GetMaxFds() - 1))
89 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
92 void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
97 int SelectEngine::DispatchEvents()
101 socklen_t codesize = sizeof(int);
104 fd_set wfdset, rfdset, errfdset;
109 /* Populate the select FD sets (this is why select sucks compared to epoll, kqueue) */
110 for (unsigned int i = 0; i < FD_SETSIZE; i++)
112 EventHandler* eh = ref[i];
115 int state = eh->GetEventMask();
116 if (state & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
118 if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
120 FD_SET (i, &errfdset);
123 /* One second wait */
127 sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
128 ServerInstance->UpdateTime();
130 /* Nothing to process this time around */
134 for (int i = 0; i < FD_SETSIZE; i++)
136 EventHandler* ev = ref[i];
139 if (FD_ISSET (i, &errfdset))
142 if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
145 ev->HandleEvent(EVENT_ERROR, errcode);
150 /* NOTE: This is a pair of seperate if statements as the socket
151 * may be in both read and writeable state at the same time.
152 * If an error event occurs above it is not worth processing the
153 * read and write states even if set.
155 if (FD_ISSET (i, &rfdset))
158 SetEventMask(ev, ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
159 ev->HandleEvent(EVENT_READ);
163 if (FD_ISSET (i, &wfdset))
166 SetEventMask(ev, ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
167 ev->HandleEvent(EVENT_WRITE);
176 std::string SelectEngine::GetName()
181 SocketEngine* CreateSocketEngine()
183 return new SelectEngine;