1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * Inspire is copyright (C) 2002-2005 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
17 #ifndef __SOCKETENGINE__
18 #define __SOCKETENGINE__
22 #include "inspircd_config.h"
26 #include <sys/epoll.h>
30 #include <sys/types.h>
31 #include <sys/event.h>
40 fd_set wfdset, rfdset;
43 struct kevent ke_list[65535];
47 struct epoll_event events[65535];
54 bool AddFd(int fd, bool readable, char type);
56 bool Wait(std::vector<int> &fdlist);
57 std::string GetName();
76 // Fill the engine with client file descriptors pending an action
78 #define epoll_fill int i = epoll_wait(ep, event, 1, 5); \
81 log(DEBUG,"epoll_wait call: ep=%d, i=%d",ep,i); \
82 userrec* cu = fd_ref_table[event[0].data.fd];
84 #define kqueue_fill ts.tv_sec = 0; \
86 int i = kevent(kq, NULL, 0, &ke, 1, &ts); \
89 log(DEBUG,"kevent call: kq=%d, i=%d",kq,i); \
90 userrec* cu = fd_ref_table[ke.ident];
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++) \
98 if (count2a == clientlist.end()) \
100 userrec* cu = count2a->second;
103 #define engine_fill epoll_fill
106 #define engine_fill kqueue_fill
109 #define engine_fill select_fill
112 // how to determine if a socket needs attention if further checks are needed
114 #define epoll_check ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
116 #define kqueue_check ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
118 #define select_check ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1) && (FD_ISSET (cu->fd, &sfd)))
121 #define engine_check epoll_check
124 #define engine_check kqueue_check
127 #define engine_check select_check
130 // how to clean up an exiting client
132 #define epoll_cleanup log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
133 kill_link(cu,"Client exited"); \
134 log(DEBUG,"Bailing from client exit"); \
137 #define kqueue_cleanup log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
138 kill_link(cu,"Client exited"); \
139 log(DEBUG,"Bailing from client exit"); \
142 #define select_cleanup if (count2->second) \
144 log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
145 kill_link(cu,"Client exited"); \
146 log(DEBUG,"Bailing from client exit"); \
151 #define engine_cleanup epoll_cleanup
154 #define engine_cleanup kqueue_cleanup
157 #define engine_cleanup select_cleanup
161 // how to scan the set for fd's requiring action
163 #define select_scanset for (count = 0; count < boundPortCount; count++) \
165 FD_SET (openSockfd[count], &selectFds); \
167 tv.tv_usec = 30000L; \
168 selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv); \
169 if (selectResult > 0) \
171 for (count = 0; count < boundPortCount; count++) \
173 if (FD_ISSET (openSockfd[count], &selectFds)) \
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++) \
181 log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke_list[j].ident); \
182 for (count = 0; count < boundPortCount; count++) \
184 if ((unsigned)ke_list[j].ident == (unsigned)openSockfd[count]) \
187 #define epoll_scanset i = epoll_wait(lep, event, 32, EP_DELAY); \
188 if (i > 0) for (j = 0; j < i; j++) \
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++) \
193 if ((unsigned)event[j].data.fd == (unsigned)openSockfd[count]) \
197 #define engine_scanset epoll_scanset
200 #define engine_scanset kqueue_scanset
203 #define engine_scanset select_scanset
206 // a list of variables used specifically by this engine
208 #define kqueue_structs struct kevent ke; \
209 struct kevent ke_list[33]; \
212 #define epoll_structs struct epoll_event event[33];
214 #define select_structs fd_set sfd;
217 #define engine_structs epoll_structs
220 #define engine_structs kqueue_structs
223 #define engine_structs select_structs
226 // how to initialise the engine before using it
228 #define select_init while(0);
230 #define kqueue_init kq = kqueue(); \
233 if ((kq == -1) || (lkq == -1) || (skq == -1)) \
235 log(DEFAULT,"main: kqueue() failed!"); \
236 printf("ERROR: could not initialise kqueue event system. Shutting down.\n"); \
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)) \
245 log(DEFAULT,"main: epoll_create() failed!"); \
246 printf("ERROR: could not initialise epoll event system. Shutting down.\n"); \
252 #define engine_init epoll_init
255 #define engine_init kqueue_init
258 #define engine_init select_init
261 // how to delete a client fd from the engine
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); \
268 log(DEBUG,"kqueue: Failed to remove user from queue!"); \
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); \
277 log(DEBUG,"epoll: List deletion failure!"); \
280 #define select_delete_fd while(0);
284 #define engine_delete_fd epoll_delete_fd
287 #define engine_delete_fd kqueue_delete_fd
290 #define engine_delete_fd select_delete_fd
293 // how to add a client fd to the engine
295 #define select_add_fd while(0);
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); \
304 log(DEBUG,"epoll: List insertion failure!"); \
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); \
313 log(DEBUG,"kqueue: List insertion failure!"); \
317 #define engine_add_fd epoll_add_fd
320 #define engine_add_fd kqueue_add_fd
323 #define engine_add_fd select_add_fd
326 #define select_server_fill log(DEFAULT,"Using standard select socket engine.");
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++) \
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); \
338 log(DEFAULT,"main: add listen ports, epoll_ctl failed!"); \
339 printf("ERROR: could not initialise listening sockets in epoll list. Shutting down.\n"); \
344 #define kqueue_server_fill log(DEFAULT,"kqueue socket engine is enabled. Filling listen list."); \
345 for (count = 0; count < boundPortCount; count++) \
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); \
353 log(DEFAULT,"main: add listen ports to kqueue failed!"); \
354 printf("ERROR: could not initialise listening sockets in kqueue. Shutting down.\n"); \
360 #define engine_server_fill epoll_server_fill
363 #define engine_server_fill kqueue_server_fill
366 #define engine_server_fill select_server_fill
370 // what is this engine called?
373 #define engine_name "kqueue"
376 #define engine_name "select"
379 #define engine_name "epoll"