-#define select_cleanup if (count2->second) \
- { \
- log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
- kill_link(cu,"Client exited"); \
- log(DEBUG,"Bailing from client exit"); \
- goto label; \
- }
-
-#ifdef USE_EPOLL
-#define engine_cleanup epoll_cleanup
-#endif
-#ifdef USE_KQUEUE
-#define engine_cleanup kqueue_cleanup
-#endif
-#ifdef USE_SELECT
-#define engine_cleanup select_cleanup
-#endif
-
-
-// how to scan the set for fd's requiring action
-
-#define select_scanset for (count = 0; count < boundPortCount; count++) \
- { \
- FD_SET (openSockfd[count], &selectFds); \
- } \
- tv.tv_usec = 30000L; \
- selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv); \
- if (selectResult > 0) \
- { \
- for (count = 0; count < boundPortCount; count++) \
- { \
- if (FD_ISSET (openSockfd[count], &selectFds)) \
- {
-
-#define kqueue_scanset ts.tv_sec = 0; \
- ts.tv_nsec = 30000L; \
- i = kevent(lkq, NULL, 0, ke_list, 32, &ts); \
- if (i > 0) for (j = 0; j < i; j++) \
- { \
- log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke_list[j].ident); \
- for (count = 0; count < boundPortCount; count++) \
- { \
- if ((unsigned)ke_list[j].ident == (unsigned)openSockfd[count]) \
- {
-
-#define epoll_scanset i = epoll_wait(lep, event, 32, EP_DELAY); \
- if (i > 0) for (j = 0; j < i; j++) \
- { \
- log(DEBUG,"epoll: Listening socket event, i=%d,events[j].data.fd=%d",i,event[j].data.fd); \
- for (count = 0; count < boundPortCount; count++) \
- { \
- if ((unsigned)event[j].data.fd == (unsigned)openSockfd[count]) \
- {
-
-#ifdef USE_EPOLL
-#define engine_scanset epoll_scanset
-#endif
-#ifdef USE_KQUEUE
-#define engine_scanset kqueue_scanset
-#endif
-#ifdef USE_SELECT
-#define engine_scanset select_scanset
-#endif
-
-// a list of variables used specifically by this engine
-
-#define kqueue_structs struct kevent ke; \
- struct kevent ke_list[33]; \
- struct timespec ts;
-
-#define epoll_structs struct epoll_event event[33];
-
-#define select_structs fd_set sfd;
-
-#ifdef USE_EPOLL
-#define engine_structs epoll_structs
-#endif
-#ifdef USE_KQUEUE
-#define engine_structs kqueue_structs
-#endif
-#ifdef USE_SELECT
-#define engine_structs select_structs
-#endif
-
-// how to initialise the engine before using it
-
-#define select_init while(0);
-
-#define kqueue_init kq = kqueue(); \
- lkq = kqueue(); \
- skq = kqueue(); \
- if ((kq == -1) || (lkq == -1) || (skq == -1)) \
- { \
- log(DEFAULT,"main: kqueue() failed!"); \
- printf("ERROR: could not initialise kqueue event system. Shutting down.\n"); \
- Exit(ERROR); \
- }
-
-#define epoll_init ep = epoll_create(MAXCLIENTS); \
- lep = epoll_create(32); \
- sep = epoll_create(128); \
- if ((ep == -1) || (lep == -1) || (sep == -1)) \
- { \
- log(DEFAULT,"main: epoll_create() failed!"); \
- printf("ERROR: could not initialise epoll event system. Shutting down.\n"); \
- Exit(ERROR); \
- }
-
-
-#ifdef USE_EPOLL
-#define engine_init epoll_init
-#endif
-#ifdef USE_KQUEUE
-#define engine_init kqueue_init
-#endif
-#ifdef USE_SELECT
-#define engine_init select_init
-#endif
-
-// how to delete a client fd from the engine
-
-#define kqueue_delete_fd struct kevent ke; \
- EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); \
- int i = kevent(kq, &ke, 1, 0, 0, NULL); \
- if (i == -1) \
- { \
- log(DEBUG,"kqueue: Failed to remove user from queue!"); \
- }
-
-#define epoll_delete_fd struct epoll_event ev; \
- ev.events = EPOLLIN | EPOLLET; \
- ev.data.fd = user->fd; \
- int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev); \
- if (i < 0) \
- { \
- log(DEBUG,"epoll: List deletion failure!"); \
- }
-
-#define select_delete_fd while(0);
-
-
-#ifdef USE_EPOLL
-#define engine_delete_fd epoll_delete_fd
-#endif
-#ifdef USE_KQUEUE
-#define engine_delete_fd kqueue_delete_fd
-#endif
-#ifdef USE_SELECT
-#define engine_delete_fd select_delete_fd
-#endif
-
-// how to add a client fd to the engine
-
-#define select_add_fd while(0);
-
-#define epoll_add_fd struct epoll_event ev; \
- log(DEBUG,"epoll: Adduser to events, ep=%d socket=%d",ep,socket); \
- ev.events = EPOLLIN | EPOLLET; \
- ev.data.fd = socket; \
- int i = epoll_ctl(ep, EPOLL_CTL_ADD, socket, &ev); \
- if (i < 0) \
- { \
- log(DEBUG,"epoll: List insertion failure!"); \
- }
-
-#define kqueue_add_fd struct kevent ke; \
- log(DEBUG,"kqueue: Add user to events, kq=%d socket=%d",kq,socket);\
- EV_SET(&ke, socket, EVFILT_READ, EV_ADD, 0, 0, NULL); \
- int i = kevent(kq, &ke, 1, 0, 0, NULL); \
- if (i == -1) \
- { \
- log(DEBUG,"kqueue: List insertion failure!"); \
- }
-
-#ifdef USE_EPOLL
-#define engine_add_fd epoll_add_fd
-#endif
-#ifdef USE_KQUEUE
-#define engine_add_fd kqueue_add_fd
-#endif
-#ifdef USE_SELECT
-#define engine_add_fd select_add_fd
-#endif
-
-#define select_server_fill log(DEFAULT,"Using standard select socket engine.");
-
-#define epoll_server_fill log(DEFAULT,"epoll socket engine is enabled. Filling listen list. boundPortcount=%d",boundPortCount); \
- for (count = 0; count < boundPortCount; count++) \
- { \
- struct epoll_event ev; \
- log(DEBUG,"epoll: Add listening socket to events, ep=%d socket=%d",lep,openSockfd[count]); \
- ev.events = EPOLLIN | EPOLLET; \
- ev.data.fd = openSockfd[count]; \
- int i = epoll_ctl(lep, EPOLL_CTL_ADD, openSockfd[count], &ev); \
- if (i < 0) \
- { \
- log(DEFAULT,"main: add listen ports, epoll_ctl failed!"); \
- printf("ERROR: could not initialise listening sockets in epoll list. Shutting down.\n"); \
- Exit(ERROR); \
- } \
- }
-
-#define kqueue_server_fill log(DEFAULT,"kqueue socket engine is enabled. Filling listen list."); \
- for (count = 0; count < boundPortCount; count++) \
- { \
- struct kevent ke; \
- log(DEBUG,"kqueue: Add listening socket to events, kq=%d socket=%d",lkq,openSockfd[count]); \
- EV_SET(&ke, openSockfd[count], EVFILT_READ, EV_ADD, 0, MaxConn, NULL); \
- int i = kevent(lkq, &ke, 1, 0, 0, NULL); \
- if (i == -1) \
- { \
- log(DEFAULT,"main: add listen ports to kqueue failed!"); \
- printf("ERROR: could not initialise listening sockets in kqueue. Shutting down.\n"); \
- Exit(ERROR); \
- } \
- }
-
-#ifdef USE_EPOLL
-#define engine_server_fill epoll_server_fill
-#endif
-#ifdef USE_KQUEUE
-#define engine_server_fill kqueue_server_fill
-#endif
-#ifdef USE_SELECT
-#define engine_server_fill select_server_fill
-#endif
-
-
-// what is this engine called?
+ /** Destructor.
+ * The destructor transparently tidies up
+ * any resources used by the socket engine.
+ */
+ virtual ~SocketEngine();
+
+ /** Add an EventHandler object to the engine. Use AddFd to add a file
+ * descriptor to the engine and have the socket engine monitor it. You
+ * must provide an object derived from EventHandler which implements
+ * HandleEvent().
+ * @param eh An event handling object to add
+ * @param event_mask The initial event mask for the object
+ */
+ virtual bool AddFd(EventHandler* eh, int event_mask) = 0;
+
+ /** If you call this function and pass it an
+ * event handler, that event handler will
+ * receive the next available write event,
+ * even if the socket is a readable socket only.
+ * Developers should avoid constantly keeping
+ * an eventhandler in the writeable state,
+ * as this will consume large amounts of
+ * CPU time.
+ * @param eh The event handler to change
+ * @param event_mask The changes to make to the wait state
+ */
+ void ChangeEventMask(EventHandler* eh, int event_mask);
+
+ /** Returns the highest file descriptor you may store in the socket engine
+ * @return The maximum fd value
+ */
+ inline int GetMaxFds() const { return MAX_DESCRIPTORS; }
+
+ /** Returns the number of file descriptors being queried
+ * @return The set size
+ */
+ inline int GetUsedFds() const { return CurrentSetSize; }
+
+ /** Delete an event handler from the engine.
+ * This function call deletes an EventHandler
+ * from the engine, returning true if it succeeded
+ * and false if it failed. This does not free the
+ * EventHandler pointer using delete, if this is
+ * required you must do this yourself.
+ * Note on forcing deletes. DO NOT DO THIS! This is
+ * extremely dangerous and will most likely render the
+ * socketengine dead. This was added only for handling
+ * very rare cases where broken 3rd party libs destroys
+ * the OS socket beyond our control. If you can't explain
+ * in minute details why forcing is absolutely necessary
+ * then you don't need it. That was a NO!
+ * @param eh The event handler object to remove
+ * @param force *DANGEROUS* See method description!
+ * @return True if the event handler was removed
+ */
+ virtual bool DelFd(EventHandler* eh, bool force = false) = 0;
+
+ /** Returns true if a file descriptor exists in
+ * the socket engine's list.
+ * @param fd The event handler to look for
+ * @return True if this fd has an event handler
+ */
+ virtual bool HasFd(int fd);
+
+ /** Returns the EventHandler attached to a specific fd.
+ * If the fd isnt in the socketengine, returns NULL.
+ * @param fd The event handler to look for
+ * @return A pointer to the event handler, or NULL
+ */
+ virtual EventHandler* GetRef(int fd);
+
+ /** Waits for events and dispatches them to handlers. Please note that
+ * this doesn't wait long, only a couple of milliseconds. It returns the
+ * number of events which occurred during this call. This method will
+ * dispatch events to their handlers by calling their
+ * EventHandler::HandleEvent() methods with the necessary EventType
+ * value.
+ * @return The number of events which have occured.
+ */
+ virtual int DispatchEvents() = 0;
+
+ /** Dispatch trial reads and writes. This causes the actual socket I/O
+ * to happen when writes have been pre-buffered.
+ */
+ virtual void DispatchTrialWrites();
+
+ /** Returns the socket engines name. This returns the name of the
+ * engine for use in /VERSION responses.
+ * @return The socket engine name
+ */
+ virtual std::string GetName() = 0;
+
+ /** Returns true if the file descriptors in the given event handler are
+ * within sensible ranges which can be handled by the socket engine.
+ */
+ virtual bool BoundsCheckFd(EventHandler* eh);
+
+ /** Abstraction for BSD sockets accept(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen);
+
+ /** Abstraction for BSD sockets close(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Close(EventHandler* fd);
+
+ /** Abstraction for BSD sockets close(2).
+ * This function should emulate its namesake system call exactly.
+ * This function should emulate its namesake system call exactly.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Close(int fd);
+
+ /** Abstraction for BSD sockets send(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Send(EventHandler* fd, const void *buf, size_t len, int flags);
+
+ /** Abstraction for BSD sockets recv(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Recv(EventHandler* fd, void *buf, size_t len, int flags);
+
+ /** Abstraction for BSD sockets recvfrom(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen);
+
+ /** Abstraction for BSD sockets sendto(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen);
+
+ /** Abstraction for BSD sockets connect(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen);
+
+ /** Make a file descriptor blocking.
+ * @param fd a file descriptor to set to blocking mode
+ * @return 0 on success, -1 on failure, errno is set appropriately.
+ */
+ virtual int Blocking(int fd);
+
+ /** Make a file descriptor nonblocking.
+ * @param fd A file descriptor to set to nonblocking mode
+ * @return 0 on success, -1 on failure, errno is set appropriately.
+ */
+ virtual int NonBlocking(int fd);
+
+ /** Abstraction for BSD sockets shutdown(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Shutdown(EventHandler* fd, int how);
+
+ /** Abstraction for BSD sockets shutdown(2).
+ * This function should emulate its namesake system call exactly.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Shutdown(int fd, int how);
+
+ /** Abstraction for BSD sockets bind(2).
+ * This function should emulate its namesake system call exactly.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Bind(int fd, const sockaddr *my_addr, socklen_t addrlen);
+
+ /** Abstraction for BSD sockets listen(2).
+ * This function should emulate its namesake system call exactly.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int Listen(int sockfd, int backlog);
+
+ /** Abstraction for BSD sockets getsockname(2).
+ * This function should emulate its namesake system call exactly.
+ * @param fd This version of the call takes an EventHandler instead of a bare file descriptor.
+ * @return This method should return exactly the same values as the system call it emulates.
+ */
+ virtual int GetSockName(EventHandler* fd, sockaddr *name, socklen_t* namelen);
+
+ /** This function is called immediately after fork().
+ * Some socket engines (notably kqueue) cannot have their
+ * handles inherited by forked processes. This method
+ * allows for the socket engine to re-create its handle
+ * after the daemon forks as the socket engine is created
+ * long BEFORE the daemon forks.
+ * @return void, but it is acceptable for this function to bail back to
+ * the shell or operating system on fatal error.
+ */
+ virtual void RecoverFromFork();
+
+ /** Get data transfer statistics, kilobits per second in and out and total.
+ */
+ void GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total);
+};