]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine.cpp
Merge pull request #308 from SaberUK/insp20-fingerprint
[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];
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 WINDOWS
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 WINDOWS
138         return closesocket(fd);
139 #else
140         return close(fd);
141 #endif
142 }
143
144 int SocketEngine::Blocking(int fd)
145 {
146 #ifdef WINDOWS
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 WINDOWS
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         struct linger linger = { 0, 0 };
170         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
171         /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */
172         linger.l_onoff = 1;
173         linger.l_linger = 1;
174         setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));
175 }
176
177 int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
178 {
179         int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen);
180         if (nbRecvd > 0)
181                 this->UpdateStats(nbRecvd, 0);
182         return nbRecvd;
183 }
184
185 int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags)
186 {
187         int nbSent = send(fd->GetFd(), (const char*)buf, len, flags);
188         if (nbSent > 0)
189                 this->UpdateStats(0, nbSent);
190         return nbSent;
191 }
192
193 int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags)
194 {
195         int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags);
196         if (nbRecvd > 0)
197                 this->UpdateStats(nbRecvd, 0);
198         return nbRecvd;
199 }
200
201 int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen)
202 {
203         int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, to, tolen);
204         if (nbSent > 0)
205                 this->UpdateStats(0, nbSent);
206         return nbSent;
207 }
208
209 int SocketEngine::Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen)
210 {
211         int ret = connect(fd->GetFd(), serv_addr, addrlen);
212 #ifdef WINDOWS
213         if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
214                 errno = EINPROGRESS;
215 #endif
216         return ret;
217 }
218
219 int SocketEngine::Shutdown(EventHandler* fd, int how)
220 {
221         return shutdown(fd->GetFd(), how);
222 }
223
224 int SocketEngine::Bind(int fd, const irc::sockets::sockaddrs& addr)
225 {
226         return bind(fd, &addr.sa, addr.sa_size());
227 }
228
229 int SocketEngine::Listen(int sockfd, int backlog)
230 {
231         return listen(sockfd, backlog);
232 }
233
234 int SocketEngine::Shutdown(int fd, int how)
235 {
236         return shutdown(fd, how);
237 }
238
239 void SocketEngine::RecoverFromFork()
240 {
241 }
242
243 void SocketEngine::UpdateStats(size_t len_in, size_t len_out)
244 {
245         if (lastempty != ServerInstance->Time())
246         {
247                 lastempty = ServerInstance->Time();
248                 indata = outdata = 0;
249         }
250         indata += len_in;
251         outdata += len_out;
252 }
253
254 void SocketEngine::GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total)
255 {
256         UpdateStats(0, 0); /* Forces emptying of the values if its been more than a second */
257         float in_kbit = indata * 8;
258         float out_kbit = outdata * 8;
259         kbitpersec_total = ((in_kbit + out_kbit) / 1024);
260         kbitpersec_in = in_kbit / 1024;
261         kbitpersec_out = out_kbit / 1024;
262 }