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/>.
22 #include "socketengine.h"
25 #include <sys/select.h>
28 /** A specialisation of the SocketEngine class, designed to use traditional select().
30 class SelectEngine : public SocketEngine
32 fd_set ReadSet, WriteSet, ErrSet;
36 /** Create a new SelectEngine
39 /** Delete a SelectEngine
41 virtual ~SelectEngine();
42 virtual bool AddFd(EventHandler* eh, int event_mask);
43 virtual void DelFd(EventHandler* eh);
44 void OnSetEvent(EventHandler* eh, int, int);
45 virtual int DispatchEvents();
46 virtual std::string GetName();
49 SelectEngine::SelectEngine()
51 MAX_DESCRIPTORS = FD_SETSIZE;
54 ref = new EventHandler* [GetMaxFds()];
55 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
63 SelectEngine::~SelectEngine()
68 bool SelectEngine::AddFd(EventHandler* eh, int event_mask)
71 if ((fd < 0) || (fd > GetMaxFds() - 1))
79 SocketEngine::SetEventMask(eh, event_mask);
80 OnSetEvent(eh, 0, event_mask);
87 ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
91 void SelectEngine::DelFd(EventHandler* eh)
95 if ((fd < 0) || (fd > GetMaxFds() - 1))
101 FD_CLR(fd, &ReadSet);
102 FD_CLR(fd, &WriteSet);
107 ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
110 void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
112 int fd = eh->GetFd();
113 int diff = old_mask ^ new_mask;
115 if (diff & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
117 if (new_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
118 FD_SET(fd, &ReadSet);
120 FD_CLR(fd, &ReadSet);
122 if (diff & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
124 if (new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
125 FD_SET(fd, &WriteSet);
127 FD_CLR(fd, &WriteSet);
131 int SelectEngine::DispatchEvents()
133 static timeval tval = { 1, 0 };
135 fd_set rfdset = ReadSet, wfdset = WriteSet, errfdset = ErrSet;
137 int sresult = select(MaxFD + 1, &rfdset, &wfdset, &errfdset, &tval);
138 ServerInstance->UpdateTime();
140 /* Nothing to process this time around */
144 for (int i = 0, j = sresult; i <= MaxFD && j > 0; i++)
146 int has_read = FD_ISSET(i, &rfdset), has_write = FD_ISSET(i, &wfdset), has_error = FD_ISSET(i, &errfdset);
148 if (has_read || has_write || has_error)
152 EventHandler* ev = ref[i];
160 socklen_t codesize = sizeof(int);
162 if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
165 ev->HandleEvent(EVENT_ERROR, errcode);
172 SetEventMask(ev, ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
173 ev->HandleEvent(EVENT_READ);
180 int newmask = (ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
181 this->OnSetEvent(ev, ev->GetEventMask(), newmask);
182 SetEventMask(ev, newmask);
183 ev->HandleEvent(EVENT_WRITE);
191 std::string SelectEngine::GetName()
196 SocketEngine* CreateSocketEngine()
198 return new SelectEngine;