]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_select.cpp
Add support for blocking tag messages with the deaf mode.
[user/henk/code/inspircd.git] / src / socketengines / socketengine_select.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
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>
13  *
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.
17  *
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
21  * details.
22  *
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/>.
25  */
26
27
28 #include "inspircd.h"
29
30 #ifndef _WIN32
31 #include <sys/select.h>
32 #endif // _WIN32
33
34 /** A specialisation of the SocketEngine class, designed to use traditional select().
35  */
36 namespace
37 {
38         fd_set ReadSet, WriteSet, ErrSet;
39         int MaxFD = 0;
40 }
41
42 void SocketEngine::Init()
43 {
44 #ifdef _WIN32
45         // Set up winsock.
46         WSADATA wsadata;
47         WSAStartup(MAKEWORD(2,2), &wsadata);
48 #endif
49
50         MaxSetSize = FD_SETSIZE;
51
52         FD_ZERO(&ReadSet);
53         FD_ZERO(&WriteSet);
54         FD_ZERO(&ErrSet);
55 }
56
57 void SocketEngine::Deinit()
58 {
59 }
60
61 void SocketEngine::RecoverFromFork()
62 {
63 }
64
65 bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
66 {
67         int fd = eh->GetFd();
68
69         if (fd < 0)
70                 return false;
71
72         if (static_cast<size_t>(fd) >= GetMaxFds())
73                 return false;
74
75         if (!SocketEngine::AddFdRef(eh))
76                 return false;
77
78         eh->SetEventMask(event_mask);
79         OnSetEvent(eh, 0, event_mask);
80         FD_SET(fd, &ErrSet);
81         if (fd > MaxFD)
82                 MaxFD = fd;
83
84         ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
85         return true;
86 }
87
88 void SocketEngine::DelFd(EventHandler* eh)
89 {
90         int fd = eh->GetFd();
91
92         if (fd < 0)
93                 return;
94
95         if (static_cast<size_t>(fd) >= GetMaxFds())
96                 return;
97
98         SocketEngine::DelFdRef(eh);
99
100         FD_CLR(fd, &ReadSet);
101         FD_CLR(fd, &WriteSet);
102         FD_CLR(fd, &ErrSet);
103         if (fd == MaxFD)
104                 --MaxFD;
105
106         ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
107 }
108
109 void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
110 {
111         int fd = eh->GetFd();
112         int diff = old_mask ^ new_mask;
113
114         if (diff & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
115         {
116                 if (new_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
117                         FD_SET(fd, &ReadSet);
118                 else
119                         FD_CLR(fd, &ReadSet);
120         }
121         if (diff & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
122         {
123                 if (new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
124                         FD_SET(fd, &WriteSet);
125                 else
126                         FD_CLR(fd, &WriteSet);
127         }
128 }
129
130 int SocketEngine::DispatchEvents()
131 {
132         timeval tval;
133         tval.tv_sec = 1;
134         tval.tv_usec = 0;
135
136         fd_set rfdset = ReadSet, wfdset = WriteSet, errfdset = ErrSet;
137
138         int sresult = select(MaxFD + 1, &rfdset, &wfdset, &errfdset, &tval);
139         ServerInstance->UpdateTime();
140
141         for (int i = 0, j = sresult; i <= MaxFD && j > 0; i++)
142         {
143                 int has_read = FD_ISSET(i, &rfdset), has_write = FD_ISSET(i, &wfdset), has_error = FD_ISSET(i, &errfdset);
144
145                 if (!(has_read || has_write || has_error))
146                         continue;
147
148                 --j;
149
150                 EventHandler* ev = GetRef(i);
151                 if (!ev)
152                         continue;
153
154                 if (has_error)
155                 {
156                         stats.ErrorEvents++;
157
158                         socklen_t codesize = sizeof(int);
159                         int errcode = 0;
160                         if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
161                                 errcode = errno;
162
163                         ev->OnEventHandlerError(errcode);
164                         continue;
165                 }
166
167                 if (has_read)
168                 {
169                         ev->SetEventMask(ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
170                         ev->OnEventHandlerRead();
171                         if (ev != GetRef(i))
172                                 continue;
173                 }
174
175                 if (has_write)
176                 {
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();
181                 }
182         }
183
184         return sresult;
185 }