]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine.cpp
Switch <stdint.h> test to use a test file too.
[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::HasFd(int fd)
98 {
99         if ((fd < 0) || (fd > GetMaxFds()))
100                 return false;
101         return (ref[fd] != NULL);
102 }
103
104 EventHandler* SocketEngine::GetRef(int fd)
105 {
106         if ((fd < 0) || (fd > GetMaxFds()))
107                 return 0;
108         return ref[fd];
109 }
110
111 bool SocketEngine::BoundsCheckFd(EventHandler* eh)
112 {
113         if (!eh)
114                 return false;
115         if ((eh->GetFd() < 0) || (eh->GetFd() > GetMaxFds()))
116                 return false;
117         return true;
118 }
119
120
121 int SocketEngine::Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen)
122 {
123         return accept(fd->GetFd(), addr, addrlen);
124 }
125
126 int SocketEngine::Close(EventHandler* fd)
127 {
128 #ifdef _WIN32
129         return closesocket(fd->GetFd());
130 #else
131         return close(fd->GetFd());
132 #endif
133 }
134
135 int SocketEngine::Close(int fd)
136 {
137 #ifdef _WIN32
138         return closesocket(fd);
139 #else
140         return close(fd);
141 #endif
142 }
143
144 int SocketEngine::Blocking(int fd)
145 {
146 #ifdef _WIN32
147         unsigned long opt = 0;
148         return ioctlsocket(fd, FIONBIO, &opt);
149 #else
150         int flags = fcntl(fd, F_GETFL, 0);
151         return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
152 #endif
153 }
154
155 int SocketEngine::NonBlocking(int fd)
156 {
157 #ifdef _WIN32
158         unsigned long opt = 1;
159         return ioctlsocket(fd, FIONBIO, &opt);
160 #else
161         int flags = fcntl(fd, F_GETFL, 0);
162         return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
163 #endif
164 }
165
166 void SocketEngine::SetReuse(int fd)
167 {
168         int on = 1;
169         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
170 }
171
172 int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
173 {
174         int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen);
175         if (nbRecvd > 0)
176                 this->UpdateStats(nbRecvd, 0);
177         return nbRecvd;
178 }
179
180 int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags)
181 {
182         int nbSent = send(fd->GetFd(), (const char*)buf, len, flags);
183         if (nbSent > 0)
184                 this->UpdateStats(0, nbSent);
185         return nbSent;
186 }
187
188 int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags)
189 {
190         int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags);
191         if (nbRecvd > 0)
192                 this->UpdateStats(nbRecvd, 0);
193         return nbRecvd;
194 }
195
196 int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen)
197 {
198         int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, to, tolen);
199         if (nbSent > 0)
200                 this->UpdateStats(0, nbSent);
201         return nbSent;
202 }
203
204 int SocketEngine::Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen)
205 {
206         int ret = connect(fd->GetFd(), serv_addr, addrlen);
207 #ifdef _WIN32
208         if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
209                 errno = EINPROGRESS;
210 #endif
211         return ret;
212 }
213
214 int SocketEngine::Shutdown(EventHandler* fd, int how)
215 {
216         return shutdown(fd->GetFd(), how);
217 }
218
219 int SocketEngine::Bind(int fd, const irc::sockets::sockaddrs& addr)
220 {
221         return bind(fd, &addr.sa, addr.sa_size());
222 }
223
224 int SocketEngine::Listen(int sockfd, int backlog)
225 {
226         return listen(sockfd, backlog);
227 }
228
229 int SocketEngine::Shutdown(int fd, int how)
230 {
231         return shutdown(fd, how);
232 }
233
234 void SocketEngine::RecoverFromFork()
235 {
236 }
237
238 void SocketEngine::UpdateStats(size_t len_in, size_t len_out)
239 {
240         if (lastempty != ServerInstance->Time())
241         {
242                 lastempty = ServerInstance->Time();
243                 indata = outdata = 0;
244         }
245         indata += len_in;
246         outdata += len_out;
247 }
248
249 void SocketEngine::GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total)
250 {
251         UpdateStats(0, 0); /* Forces emptying of the values if its been more than a second */
252         float in_kbit = indata * 8;
253         float out_kbit = outdata * 8;
254         kbitpersec_total = ((in_kbit + out_kbit) / 1024);
255         kbitpersec_in = in_kbit / 1024;
256         kbitpersec_out = out_kbit / 1024;
257 }
258
259 std::string SocketEngine::LastError()
260 {
261 #ifndef _WIN32
262         return strerror(errno);
263 #else
264         char szErrorString[500];
265         DWORD dwErrorCode = WSAGetLastError();
266         if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0)
267                 sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode);
268
269         std::string::size_type p;
270         std::string ret = szErrorString;
271         while ((p = ret.find_last_of("\r\n")) != std::string::npos)
272                 ret.erase(p, 1);
273
274         return ret;
275 #endif
276 }
277
278 std::string SocketEngine::GetError(int errnum)
279 {
280 #ifndef _WIN32
281         return strerror(errnum);
282 #else
283         WSASetLastError(errnum);
284         return LastError();
285 #endif
286 }