]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine.cpp
New socketengine stuff:
[user/henk/code/inspircd.git] / src / socketengine.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc>
7  *   Copyright (C) 2007 Burlex <???@???>
8  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
9  *
10  * This file is part of InspIRCd.  InspIRCd is free software: you can
11  * redistribute it and/or modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation, version 2.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #include "inspircd.h"
25
26 EventHandler::EventHandler()
27 {
28         fd = -1;
29         event_mask = 0;
30 }
31
32 void EventHandler::SetFd(int FD)
33 {
34         this->fd = FD;
35 }
36
37 SocketEngine::SocketEngine()
38 {
39         TotalEvents = WriteEvents = ReadEvents = ErrorEvents = 0;
40         lastempty = ServerInstance->Time();
41         indata = outdata = 0;
42 }
43
44 SocketEngine::~SocketEngine()
45 {
46 }
47
48 void SocketEngine::SetEventMask(EventHandler* eh, int mask)
49 {
50         eh->event_mask = mask;
51 }
52
53 void SocketEngine::ChangeEventMask(EventHandler* eh, int change)
54 {
55         int old_m = eh->event_mask;
56         int new_m = old_m;
57
58         // if we are changing read/write type, remove the previously set bit
59         if (change & FD_WANT_READ_MASK)
60                 new_m &= ~FD_WANT_READ_MASK;
61         if (change & FD_WANT_WRITE_MASK)
62                 new_m &= ~FD_WANT_WRITE_MASK;
63
64         // if adding a trial read/write, insert it into the set
65         if (change & FD_TRIAL_NOTE_MASK && !(old_m & FD_TRIAL_NOTE_MASK))
66                 trials.insert(eh->GetFd());
67
68         new_m |= change;
69         if (new_m == old_m)
70                 return;
71
72         eh->event_mask = new_m;
73         OnSetEvent(eh, old_m, new_m);
74 }
75
76 void SocketEngine::DispatchTrialWrites()
77 {
78         std::vector<int> working_list;
79         working_list.reserve(trials.size());
80         working_list.assign(trials.begin(), trials.end());
81         trials.clear();
82         for(unsigned int i=0; i < working_list.size(); i++)
83         {
84                 int fd = working_list[i];
85                 EventHandler* eh = GetRef(fd);
86                 if (!eh)
87                         continue;
88                 int mask = eh->event_mask;
89                 eh->event_mask &= ~(FD_ADD_TRIAL_READ | FD_ADD_TRIAL_WRITE);
90                 if ((mask & (FD_ADD_TRIAL_READ | FD_READ_WILL_BLOCK)) == FD_ADD_TRIAL_READ)
91                         eh->HandleEvent(EVENT_READ, 0);
92                 if ((mask & (FD_ADD_TRIAL_WRITE | FD_WRITE_WILL_BLOCK)) == FD_ADD_TRIAL_WRITE)
93                         eh->HandleEvent(EVENT_WRITE, 0);
94         }
95 }
96
97 bool SocketEngine::AddFd(EventHandler* eh)
98 {
99         int fd = eh->GetFd();
100         if (HasFd(fd))
101                 return false;
102
103         while (static_cast<unsigned int>(fd) >= ref.size())
104                 ref.resize(ref.empty() ? 1 : (ref.size() * 2));
105         ref[fd] = eh;
106         return true;
107 }
108
109 void SocketEngine::DelFd(EventHandler *eh)
110 {
111         int fd = eh->GetFd();
112         if (GetRef(fd) == eh)
113                 ref[fd] = NULL;
114 }
115
116 bool SocketEngine::HasFd(int fd)
117 {
118         return GetRef(fd) != NULL;
119 }
120
121 EventHandler* SocketEngine::GetRef(int fd)
122 {
123         if (fd < 0 || static_cast<unsigned int>(fd) >= ref.size())
124                 return 0;
125         return ref[fd];
126 }
127
128 bool SocketEngine::BoundsCheckFd(EventHandler* eh)
129 {
130         if (!eh)
131                 return false;
132         if ((eh->GetFd() < 0) || (eh->GetFd() > GetMaxFds()))
133                 return false;
134         return true;
135 }
136
137
138 int SocketEngine::Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen)
139 {
140         return accept(fd->GetFd(), addr, addrlen);
141 }
142
143 int SocketEngine::Close(EventHandler* fd)
144 {
145 #ifdef _WIN32
146         return closesocket(fd->GetFd());
147 #else
148         return close(fd->GetFd());
149 #endif
150 }
151
152 int SocketEngine::Close(int fd)
153 {
154 #ifdef _WIN32
155         return closesocket(fd);
156 #else
157         return close(fd);
158 #endif
159 }
160
161 int SocketEngine::Blocking(int fd)
162 {
163 #ifdef _WIN32
164         unsigned long opt = 0;
165         return ioctlsocket(fd, FIONBIO, &opt);
166 #else
167         int flags = fcntl(fd, F_GETFL, 0);
168         return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
169 #endif
170 }
171
172 int SocketEngine::NonBlocking(int fd)
173 {
174 #ifdef _WIN32
175         unsigned long opt = 1;
176         return ioctlsocket(fd, FIONBIO, &opt);
177 #else
178         int flags = fcntl(fd, F_GETFL, 0);
179         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
180 #endif
181 }
182
183 void SocketEngine::SetReuse(int fd)
184 {
185         int on = 1;
186         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
187 }
188
189 int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
190 {
191         int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen);
192         if (nbRecvd > 0)
193                 this->UpdateStats(nbRecvd, 0);
194         return nbRecvd;
195 }
196
197 int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags)
198 {
199         int nbSent = send(fd->GetFd(), (const char*)buf, len, flags);
200         if (nbSent > 0)
201                 this->UpdateStats(0, nbSent);
202         return nbSent;
203 }
204
205 int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags)
206 {
207         int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags);
208         if (nbRecvd > 0)
209                 this->UpdateStats(nbRecvd, 0);
210         return nbRecvd;
211 }
212
213 int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen)
214 {
215         int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, to, tolen);
216         if (nbSent > 0)
217                 this->UpdateStats(0, nbSent);
218         return nbSent;
219 }
220
221 int SocketEngine::Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen)
222 {
223         int ret = connect(fd->GetFd(), serv_addr, addrlen);
224 #ifdef _WIN32
225         if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
226                 errno = EINPROGRESS;
227 #endif
228         return ret;
229 }
230
231 int SocketEngine::Shutdown(EventHandler* fd, int how)
232 {
233         return shutdown(fd->GetFd(), how);
234 }
235
236 int SocketEngine::Bind(int fd, const irc::sockets::sockaddrs& addr)
237 {
238         return bind(fd, &addr.sa, addr.sa_size());
239 }
240
241 int SocketEngine::Listen(int sockfd, int backlog)
242 {
243         return listen(sockfd, backlog);
244 }
245
246 int SocketEngine::Shutdown(int fd, int how)
247 {
248         return shutdown(fd, how);
249 }
250
251 void SocketEngine::RecoverFromFork()
252 {
253 }
254
255 void SocketEngine::UpdateStats(size_t len_in, size_t len_out)
256 {
257         if (lastempty != ServerInstance->Time())
258         {
259                 lastempty = ServerInstance->Time();
260                 indata = outdata = 0;
261         }
262         indata += len_in;
263         outdata += len_out;
264 }
265
266 void SocketEngine::GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total)
267 {
268         UpdateStats(0, 0); /* Forces emptying of the values if its been more than a second */
269         float in_kbit = indata * 8;
270         float out_kbit = outdata * 8;
271         kbitpersec_total = ((in_kbit + out_kbit) / 1024);
272         kbitpersec_in = in_kbit / 1024;
273         kbitpersec_out = out_kbit / 1024;
274 }
275
276 std::string SocketEngine::LastError()
277 {
278 #ifndef _WIN32
279         return strerror(errno);
280 #else
281         char szErrorString[500];
282         DWORD dwErrorCode = WSAGetLastError();
283         if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0)
284                 sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode);
285         return szErrorString;
286 #endif
287 }
288
289 std::string SocketEngine::GetError(int errnum)
290 {
291 #ifndef _WIN32
292         return strerror(errnum);
293 #else
294         WSASetLastError(errnum);
295         return LastError();
296 #endif
297 }