]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_poll.cpp
m_dnsbl updates
[user/henk/code/inspircd.git] / src / socketengines / socketengine_poll.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *    the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "exitcodes.h"
16 /*       +------------------------------------+
17  *       | Inspire Internet Relay Chat Daemon |
18  *       +------------------------------------+
19  *
20  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
21  * See: http://wiki.inspircd.org/Credits
22  *
23  * This program is free but copyrighted software; see
24  *            the file COPYING for details.
25  *
26  * ---------------------------------------------------
27  */
28
29 #ifndef __SOCKETENGINE_POLL__
30 #define __SOCKETENGINE_POLL__
31
32 #include <vector>
33 #include <string>
34 #include <map>
35 #include "inspircd_config.h"
36 #include "inspircd.h"
37 #include "socketengine.h"
38
39 #ifndef WINDOWS
40         #ifndef __USE_XOPEN
41             #define __USE_XOPEN /* fuck every fucking OS ever made. needed by poll.h to work.*/
42         #endif
43         #include <poll.h>
44         #include <sys/poll.h>
45 #else
46         /* *grumble* */
47         #define struct pollfd WSAPOLLFD
48         #define poll WSAPoll
49 #endif
50
51 class InspIRCd;
52
53 /** A specialisation of the SocketEngine class, designed to use poll().
54  */
55 class PollEngine : public SocketEngine
56 {
57 private:
58         /** These are used by poll() to hold socket events
59          */
60         struct pollfd *events;
61         /** This map maps fds to an index in the events array.
62          */
63         std::map<int, unsigned int> fd_mappings;
64 public:
65         /** Create a new PollEngine
66          */
67         PollEngine();
68         /** Delete a PollEngine
69          */
70         virtual ~PollEngine();
71         virtual bool AddFd(EventHandler* eh, int event_mask);
72         virtual void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
73         virtual EventHandler* GetRef(int fd);
74         virtual bool DelFd(EventHandler* eh, bool force = false);
75         virtual int DispatchEvents();
76         virtual std::string GetName();
77 };
78
79 #endif
80
81 #include <ulimit.h>
82 #ifdef __FreeBSD__
83         #include <sys/sysctl.h>
84 #endif
85
86 PollEngine::PollEngine()
87 {
88         CurrentSetSize = 0;
89 #ifndef __FreeBSD__
90         int max = ulimit(4, 0);
91         if (max > 0)
92         {
93                 MAX_DESCRIPTORS = max;
94         }
95         else
96         {
97                 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno));
98                 printf("ERROR: Can't determine maximum number of open sockets: %s\n", strerror(errno));
99                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
100         }
101 #else
102         int mib[2];
103         size_t len;
104
105         mib[0] = CTL_KERN;
106         mib[1] = KERN_MAXFILES;
107         len = sizeof(MAX_DESCRIPTORS);
108         sysctl(mib, 2, &MAX_DESCRIPTORS, &len, NULL, 0);
109 #endif
110
111         ref = new EventHandler* [GetMaxFds()];
112         events = new struct pollfd[GetMaxFds()];
113
114         memset(events, 0, GetMaxFds() * sizeof(struct pollfd));
115         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
116 }
117
118 PollEngine::~PollEngine()
119 {
120         // No destruction required, either.
121         delete[] ref;
122         delete[] events;
123 }
124
125 static int mask_to_poll(int event_mask)
126 {
127         int rv = 0;
128         if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
129                 rv |= POLLIN;
130         if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
131                 rv |= POLLOUT;
132         return rv;
133 }
134
135 bool PollEngine::AddFd(EventHandler* eh, int event_mask)
136 {
137         int fd = eh->GetFd();
138         if ((fd < 0) || (fd > GetMaxFds() - 1))
139         {
140                 ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
141                 return false;
142         }
143
144         if (fd_mappings.find(fd) != fd_mappings.end())
145         {
146                 ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
147                 return false;
148         }
149
150         unsigned int index = CurrentSetSize;
151
152         fd_mappings[fd] = index;
153         ref[index] = eh;
154         events[index].fd = fd;
155         events[index].events = mask_to_poll(event_mask);
156
157         ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[fd].events, index);
158         SocketEngine::SetEventMask(eh, event_mask);
159         CurrentSetSize++;
160         return true;
161 }
162
163 EventHandler* PollEngine::GetRef(int fd)
164 {
165         std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
166         if (it == fd_mappings.end())
167                 return NULL;
168         return ref[it->second];
169 }
170
171 void PollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
172 {
173         std::map<int, unsigned int>::iterator it = fd_mappings.find(eh->GetFd());
174         if (it == fd_mappings.end())
175         {
176                 ServerInstance->Logs->Log("SOCKET",DEBUG,"SetEvents() on unknown fd: %d", eh->GetFd());
177                 return;
178         }
179
180         events[it->second].events = mask_to_poll(new_mask);
181 }
182
183 bool PollEngine::DelFd(EventHandler* eh, bool force)
184 {
185         int fd = eh->GetFd();
186         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
187         {
188                 ServerInstance->Logs->Log("SOCKET", DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
189                 return false;
190         }
191
192         std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
193         if (it == fd_mappings.end())
194         {
195                 ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd() on unknown fd: %d", fd);
196                 return false;
197         }
198
199         unsigned int index = it->second;
200         unsigned int last_index = CurrentSetSize - 1;
201         int last_fd = events[last_index].fd;
202
203         if (index != last_index)
204         {
205                 // We need to move the last fd we got into this gap (gaps are evil!)
206
207                 // So update the mapping for the last fd to its new position
208                 fd_mappings[last_fd] = index;
209
210                 // move last_fd from last_index into index
211                 events[index].fd = last_fd;
212                 events[index].events = events[last_index].events;
213
214                 ref[index] = ref[last_index];
215         }
216
217         // Now remove all data for the last fd we got into out list.
218         // Above code made sure this always is right
219         fd_mappings.erase(it);
220         events[last_index].fd = 0;
221         events[last_index].events = 0;
222         ref[last_index] = NULL;
223
224         CurrentSetSize--;
225
226         ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d (index: %d) "
227                         "(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index);
228         return true;
229 }
230
231 int PollEngine::DispatchEvents()
232 {
233         int i = poll(events, CurrentSetSize, 1000);
234         int index;
235         socklen_t codesize = sizeof(int);
236         int errcode;
237         int processed = 0;
238         ServerInstance->UpdateTime();
239
240         if (i > 0)
241         {
242                 for (index = 0; index < CurrentSetSize && processed != i; index++)
243                 {
244                         if (events[index].revents)
245                                 processed++;
246                         EventHandler* eh = ref[index];
247                         if (!eh)
248                                 continue;
249
250                         if (events[index].revents & POLLHUP)
251                         {
252                                 eh->HandleEvent(EVENT_ERROR, 0);
253                                 continue;
254                         }
255
256                         if (events[index].revents & POLLERR)
257                         {
258                                 // Get fd
259                                 int fd = events[index].fd;
260
261                                 // Get error number
262                                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
263                                         errcode = errno;
264                                 eh->HandleEvent(EVENT_ERROR, errcode);
265                                 continue;
266                         }
267
268                         if (events[index].revents & POLLIN)
269                         {
270                                 SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
271                                 eh->HandleEvent(EVENT_READ);
272                         }
273                         
274                         if (events[index].revents & POLLOUT)
275                         {
276                                 int mask = eh->GetEventMask();
277                                 mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE);
278                                 SetEventMask(eh, mask);
279                                 events[index].events = mask_to_poll(mask);
280                                 eh->HandleEvent(EVENT_WRITE);
281                         }
282                 }
283         }
284
285         return i;
286 }
287
288 std::string PollEngine::GetName()
289 {
290         return "poll";
291 }
292
293 SocketEngine* CreateSocketEngine()
294 {
295         return new PollEngine;
296 }