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