2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2013-2015 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (C) 2013, 2017, 2019 Sadie Powell <sadie@witchery.services>
6 * Copyright (C) 2012 Robby <robby@chatbelgie.be>
7 * Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
8 * Copyright (C) 2011, 2014 Adam <Adam@anope.org>
9 * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
10 * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
11 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
12 * Copyright (C) 2006-2008 Craig Edwards <brain@inspircd.org>
14 * This file is part of InspIRCd. InspIRCd is free software: you can
15 * redistribute it and/or modify it under the terms of the GNU General Public
16 * License as published by the Free Software Foundation, version 2.
18 * This program is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include <sys/select.h>
34 /** A specialisation of the SocketEngine class, designed to use traditional select().
38 fd_set ReadSet, WriteSet, ErrSet;
42 void SocketEngine::Init()
47 WSAStartup(MAKEWORD(2,2), &wsadata);
50 MaxSetSize = FD_SETSIZE;
57 void SocketEngine::Deinit()
61 void SocketEngine::RecoverFromFork()
65 bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
72 if (static_cast<size_t>(fd) >= GetMaxFds())
75 if (!SocketEngine::AddFdRef(eh))
78 eh->SetEventMask(event_mask);
79 OnSetEvent(eh, 0, event_mask);
84 ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
88 void SocketEngine::DelFd(EventHandler* eh)
95 if (static_cast<size_t>(fd) >= GetMaxFds())
98 SocketEngine::DelFdRef(eh);
100 FD_CLR(fd, &ReadSet);
101 FD_CLR(fd, &WriteSet);
106 ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
109 void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
111 int fd = eh->GetFd();
112 int diff = old_mask ^ new_mask;
114 if (diff & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
116 if (new_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
117 FD_SET(fd, &ReadSet);
119 FD_CLR(fd, &ReadSet);
121 if (diff & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
123 if (new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
124 FD_SET(fd, &WriteSet);
126 FD_CLR(fd, &WriteSet);
130 int SocketEngine::DispatchEvents()
136 fd_set rfdset = ReadSet, wfdset = WriteSet, errfdset = ErrSet;
138 int sresult = select(MaxFD + 1, &rfdset, &wfdset, &errfdset, &tval);
139 ServerInstance->UpdateTime();
141 for (int i = 0, j = sresult; i <= MaxFD && j > 0; i++)
143 int has_read = FD_ISSET(i, &rfdset), has_write = FD_ISSET(i, &wfdset), has_error = FD_ISSET(i, &errfdset);
145 if (!(has_read || has_write || has_error))
150 EventHandler* ev = GetRef(i);
158 socklen_t codesize = sizeof(int);
160 if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
163 ev->OnEventHandlerError(errcode);
169 ev->SetEventMask(ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
170 ev->OnEventHandlerRead();
177 int newmask = (ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
178 SocketEngine::OnSetEvent(ev, ev->GetEventMask(), newmask);
179 ev->SetEventMask(newmask);
180 ev->OnEventHandlerWrite();