]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/socketengine.h
Made compile on freebsd
[user/henk/code/inspircd.git] / include / socketengine.h
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2005 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15 */
16
17 #ifndef __SOCKETENGINE__
18 #define __SOCKETENGINE__
19
20 #include <vector>
21 #include <string>
22 #include "inspircd_config.h"
23 #include "globals.h"
24 #include "inspircd.h"
25 #ifdef USE_EPOLL
26 #include <sys/epoll.h>
27 #define EP_DELAY 5
28 #endif
29 #ifdef USE_KQUEUE
30 #include <sys/types.h>
31 #include <sys/event.h>
32 #include <sys/time.h>
33 #endif
34
35 class SocketEngine {
36
37         std::vector<int> fds;
38         int EngineHandle;
39 #ifdef USE_SELECT
40         fd_set wfdset, rfdset;
41 #endif
42 #ifdef USE_KQUEUE
43         struct kevent ke_list[65535];
44         struct timespec ts;
45 #endif
46 #ifdef USE_EPOLL
47         struct epoll_event events[65535];
48 #endif
49
50 public:
51
52         SocketEngine();
53         ~SocketEngine();
54         bool AddFd(int fd, bool readable, char type);
55         bool DelFd(int fd);
56         bool Wait(std::vector<int> &fdlist);
57         std::string GetName();
58 };
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 // Fill the engine with client file descriptors pending an action
77
78 #define epoll_fill      int i = epoll_wait(ep, event, 1, 5); \
79                         if (i > 0) \
80                         { \
81                                 log(DEBUG,"epoll_wait call: ep=%d, i=%d",ep,i); \
82                                 userrec* cu = fd_ref_table[event[0].data.fd];
83
84 #define kqueue_fill     ts.tv_sec = 0; \
85                         ts.tv_nsec = 1000L; \
86                         int i = kevent(kq, NULL, 0, &ke, 1, &ts); \
87                         if (i > 0) \
88                         { \
89                                 log(DEBUG,"kevent call: kq=%d, i=%d",kq,i); \
90                                 userrec* cu = fd_ref_table[ke.ident];
91
92 #define select_fill     tval.tv_sec = 0; \
93                         tval.tv_usec = 1000L; \
94                         selectResult2 = select(FD_SETSIZE, &sfd, NULL, NULL, &tval); \
95                         if ((selectResult2 > 0) && (xcount != clientlist.end())) \
96                         for (user_hash::iterator count2a = xcount; count2a != endingiter; count2a++) \
97                         { \
98                                 if (count2a == clientlist.end()) \
99                                         break; \
100                                 userrec* cu = count2a->second;
101
102 #ifdef USE_EPOLL
103 #define engine_fill epoll_fill
104 #endif
105 #ifdef USE_KQUEUE
106 #define engine_fill kqueue_fill
107 #endif
108 #ifdef USE_SELECT
109 #define engine_fill select_fill
110 #endif
111
112 // how to determine if a socket needs attention if further checks are needed
113
114 #define epoll_check    ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
115
116 #define kqueue_check   ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
117
118 #define select_check   ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1) && (FD_ISSET (cu->fd, &sfd)))
119
120 #ifdef USE_EPOLL
121 #define engine_check epoll_check
122 #endif
123 #ifdef USE_KQUEUE
124 #define engine_check kqueue_check
125 #endif
126 #ifdef USE_SELECT
127 #define engine_check select_check
128 #endif
129
130 // how to clean up an exiting client
131
132 #define epoll_cleanup                   log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
133                                         kill_link(cu,"Client exited"); \
134                                         log(DEBUG,"Bailing from client exit"); \
135                                         goto label;
136
137 #define kqueue_cleanup                  log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
138                                         kill_link(cu,"Client exited"); \
139                                         log(DEBUG,"Bailing from client exit"); \
140                                         goto label;
141
142 #define select_cleanup                  if (count2->second) \
143                                         { \
144                                                 log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
145                                                 kill_link(cu,"Client exited"); \
146                                                 log(DEBUG,"Bailing from client exit"); \
147                                                 goto label; \
148                                         }
149
150 #ifdef USE_EPOLL
151 #define engine_cleanup epoll_cleanup
152 #endif
153 #ifdef USE_KQUEUE
154 #define engine_cleanup kqueue_cleanup
155 #endif
156 #ifdef USE_SELECT
157 #define engine_cleanup select_cleanup
158 #endif
159
160
161 // how to scan the set for fd's requiring action
162
163 #define select_scanset          for (count = 0; count < boundPortCount; count++) \
164                                 { \
165                                         FD_SET (openSockfd[count], &selectFds); \
166                                 } \
167                                 tv.tv_usec = 30000L; \
168                                 selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv); \
169                                 if (selectResult > 0) \
170                                 { \
171                                         for (count = 0; count < boundPortCount; count++) \
172                                 { \
173                                                 if (FD_ISSET (openSockfd[count], &selectFds)) \
174                                                 {
175
176 #define kqueue_scanset          ts.tv_sec = 0; \
177                                 ts.tv_nsec = 30000L; \
178                                 i = kevent(lkq, NULL, 0, ke_list, 32, &ts); \
179                                 if (i > 0) for (j = 0; j < i; j++) \
180                                 { \
181                                         log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke_list[j].ident); \
182                                         for (count = 0; count < boundPortCount; count++) \
183                                         { \
184                                                 if ((unsigned)ke_list[j].ident == (unsigned)openSockfd[count]) \
185                                                 {
186
187 #define epoll_scanset           i = epoll_wait(lep, event, 32, EP_DELAY); \
188                                 if (i > 0) for (j = 0; j < i; j++) \
189                                 { \
190                                         log(DEBUG,"epoll: Listening socket event, i=%d,events[j].data.fd=%d",i,event[j].data.fd); \
191                                         for (count = 0; count < boundPortCount; count++) \
192                                         { \
193                                                 if ((unsigned)event[j].data.fd == (unsigned)openSockfd[count]) \
194                                                 {
195
196 #ifdef USE_EPOLL
197 #define engine_scanset epoll_scanset
198 #endif
199 #ifdef USE_KQUEUE
200 #define engine_scanset kqueue_scanset
201 #endif
202 #ifdef USE_SELECT
203 #define engine_scanset select_scanset
204 #endif
205
206 // a list of variables used specifically by this engine
207
208 #define kqueue_structs struct kevent ke; \
209         struct kevent ke_list[33]; \
210         struct timespec ts;
211
212 #define epoll_structs struct epoll_event event[33];
213
214 #define select_structs fd_set sfd;
215
216 #ifdef USE_EPOLL
217 #define engine_structs epoll_structs
218 #endif
219 #ifdef USE_KQUEUE
220 #define engine_structs kqueue_structs
221 #endif
222 #ifdef USE_SELECT
223 #define engine_structs select_structs
224 #endif
225
226 // how to initialise the engine before using it
227
228 #define select_init     while(0);
229
230 #define kqueue_init     kq = kqueue(); \
231                         lkq = kqueue(); \
232                         skq = kqueue(); \
233                         if ((kq == -1) || (lkq == -1) || (skq == -1)) \
234                         { \
235                                 log(DEFAULT,"main: kqueue() failed!"); \
236                                 printf("ERROR: could not initialise kqueue event system. Shutting down.\n"); \
237                                 Exit(ERROR); \
238                         }
239
240 #define epoll_init      ep = epoll_create(MAXCLIENTS); \
241                         lep = epoll_create(32); \
242                         sep = epoll_create(128); \
243                         if ((ep == -1) || (lep == -1) || (sep == -1)) \
244                         { \
245                                 log(DEFAULT,"main: epoll_create() failed!"); \
246                                 printf("ERROR: could not initialise epoll event system. Shutting down.\n"); \
247                                 Exit(ERROR); \
248                         }
249
250
251 #ifdef USE_EPOLL
252 #define engine_init epoll_init
253 #endif
254 #ifdef USE_KQUEUE
255 #define engine_init kqueue_init
256 #endif
257 #ifdef USE_SELECT
258 #define engine_init select_init
259 #endif
260
261 // how to delete a client fd from the engine
262
263 #define kqueue_delete_fd        struct kevent ke; \
264                                 EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); \
265                                 int i = kevent(kq, &ke, 1, 0, 0, NULL); \
266                                 if (i == -1) \
267                                 { \
268                                         log(DEBUG,"kqueue: Failed to remove user from queue!"); \
269                                 }
270
271 #define epoll_delete_fd         struct epoll_event ev; \
272                                 ev.events = EPOLLIN | EPOLLET; \
273                                 ev.data.fd = user->fd; \
274                                 int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev); \
275                                 if (i < 0) \
276                                 { \
277                                         log(DEBUG,"epoll: List deletion failure!"); \
278                                 }
279
280 #define select_delete_fd        while(0);
281
282
283 #ifdef USE_EPOLL
284 #define engine_delete_fd epoll_delete_fd
285 #endif
286 #ifdef USE_KQUEUE
287 #define engine_delete_fd kqueue_delete_fd
288 #endif
289 #ifdef USE_SELECT
290 #define engine_delete_fd select_delete_fd
291 #endif
292
293 // how to add a client fd to the engine
294
295 #define select_add_fd           while(0);
296
297 #define epoll_add_fd            struct epoll_event ev; \
298                                 log(DEBUG,"epoll: Adduser to events, ep=%d socket=%d",ep,socket); \
299                                 ev.events = EPOLLIN | EPOLLET; \
300                                 ev.data.fd = socket; \
301                                 int i = epoll_ctl(ep, EPOLL_CTL_ADD, socket, &ev); \
302                                 if (i < 0) \
303                                 { \
304                                         log(DEBUG,"epoll: List insertion failure!"); \
305                                 }
306
307 #define kqueue_add_fd           struct kevent ke; \
308                                 log(DEBUG,"kqueue: Add user to events, kq=%d socket=%d",kq,socket);\
309                                 EV_SET(&ke, socket, EVFILT_READ, EV_ADD, 0, 0, NULL); \
310                                 int i = kevent(kq, &ke, 1, 0, 0, NULL); \
311                                 if (i == -1) \
312                                 { \
313                                         log(DEBUG,"kqueue: List insertion failure!"); \
314                                 }
315
316 #ifdef USE_EPOLL
317 #define engine_add_fd epoll_add_fd
318 #endif
319 #ifdef USE_KQUEUE
320 #define engine_add_fd kqueue_add_fd
321 #endif
322 #ifdef USE_SELECT
323 #define engine_add_fd select_add_fd
324 #endif
325
326 #define select_server_fill      log(DEFAULT,"Using standard select socket engine.");
327
328 #define epoll_server_fill        log(DEFAULT,"epoll socket engine is enabled. Filling listen list. boundPortcount=%d",boundPortCount); \
329                                 for (count = 0; count < boundPortCount; count++) \
330                                 { \
331                                         struct epoll_event ev; \
332                                         log(DEBUG,"epoll: Add listening socket to events, ep=%d socket=%d",lep,openSockfd[count]); \
333                                         ev.events = EPOLLIN | EPOLLET; \
334                                         ev.data.fd = openSockfd[count]; \
335                                         int i = epoll_ctl(lep, EPOLL_CTL_ADD, openSockfd[count], &ev); \
336                                         if (i < 0) \
337                                         { \
338                                                 log(DEFAULT,"main: add listen ports, epoll_ctl failed!"); \
339                                                 printf("ERROR: could not initialise listening sockets in epoll list. Shutting down.\n"); \
340                                                 Exit(ERROR); \
341                                         } \
342                                 }
343
344 #define kqueue_server_fill        log(DEFAULT,"kqueue socket engine is enabled. Filling listen list."); \
345         for (count = 0; count < boundPortCount; count++) \
346         { \
347                 struct kevent ke; \
348                 log(DEBUG,"kqueue: Add listening socket to events, kq=%d socket=%d",lkq,openSockfd[count]); \
349                 EV_SET(&ke, openSockfd[count], EVFILT_READ, EV_ADD, 0, MaxConn, NULL); \
350                 int i = kevent(lkq, &ke, 1, 0, 0, NULL); \
351                 if (i == -1) \
352                 { \
353                         log(DEFAULT,"main: add listen ports to kqueue failed!"); \
354                         printf("ERROR: could not initialise listening sockets in kqueue. Shutting down.\n"); \
355                         Exit(ERROR); \
356                 } \
357         }
358
359 #ifdef USE_EPOLL
360 #define engine_server_fill epoll_server_fill
361 #endif
362 #ifdef USE_KQUEUE
363 #define engine_server_fill kqueue_server_fill
364 #endif
365 #ifdef USE_SELECT
366 #define engine_server_fill select_server_fill
367 #endif
368
369
370 // what is this engine called?
371
372 #ifdef USE_KQUEUE
373 #define engine_name "kqueue"
374 #endif
375 #ifdef USE_SELECT
376 #define engine_name "select"
377 #endif
378 #ifdef USE_EPOLL
379 #define engine_name "epoll"
380 #endif
381
382
383 #endif