]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - include/socketengine.h
Extra checking that the fd's we pass to SocketEngine::AddFd were added (a lot of...
[user/henk/code/inspircd.git] / include / socketengine.h
index c99ffa5179a8cede60e3f3beb36b80e90da173a7..a788618a27a47ceb6a5d6f6c2018c40396ccb26d 100644 (file)
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
+ *                       E-mail:
+ *                <brain@chatspike.net>
+ *                <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+*/
+
+#ifndef __SOCKETENGINE__
+#define __SOCKETENGINE__
+
+#include <vector>
+#include <string>
+#include <map>
+#include "inspircd_config.h"
+#include "globals.h"
+#include "inspircd.h"
+
+/**
+ * Each of these values represents a socket
+ * type in our reference table (the reference
+ * table itself is only accessible to
+ * socketengine.cpp)
+ */
+const char X_EMPTY_SLOT                = 0;
+const char X_LISTEN             = 1;
+const char X_ESTAB_CLIENT       = 2;
+const char X_ESTAB_MODULE       = 3;
+const char X_ESTAB_DNS          = 4;
+
+/**
+ * To indicate that a socket is readable, we
+ * mask its top bit with this X_READBIT value.
+ * The socket engine can handle two types of
+ * socket, readable and writeable (;error sockets
+ * are dealt with when read() and write() return
+ * negative or zero values).
+ */
+const char X_READBIT            = 0x80;
+
+/**
+ * The actual socketengine class presents the
+ * same interface on all operating systems, but
+ * its private members and internal behaviour
+ * should be treated as blackboxed, and vary
+ * from system to system and upon the config
+ * settings chosen by the server admin. The current
+ * version supports select, epoll and kqueue.
+ * The configure script will enable a socket engine
+ * based upon what OS is detected, and will derive
+ * a class from SocketEngine based upon what it finds.
+ * The derived classes file will also implement a
+ * classfactory, SocketEngineFactory, which will
+ * create a derived instance of SocketEngine using
+ * polymorphism so that the core and modules do not
+ * have to be aware of which SocketEngine derived
+ * class they are using.
+ */
+class SocketEngine : public Extensible
+{
+protected:
+       int EngineHandle;                       /* Handle to the socket engine if needed */
+       int CurrentSetSize;                     /* Current number of descriptors in the engine */
+       char ref[MAX_DESCRIPTORS];              /* Reference table */
+public:
+
+       /** Constructor
+        * The constructor transparently initializes
+        * the socket engine which the ircd is using.
+        * Please note that if there is a catastrophic
+        * failure (for example, you try and enable
+        * epoll on a 2.4 linux kernel) then this
+        * function may bail back to the shell.
+        */
+       SocketEngine();
+
+       /** Destructor
+        * The destructor transparently tidies up
+        * any resources used by the socket engine.
+        */
+       virtual ~SocketEngine();
+
+       /** Add a file descriptor to the engine
+        * Use AddFd to add a file descriptor to the
+        * engine and have the socket engine monitor
+        * it. You must provide a type (see the consts
+        * in socketengine.h) and a boolean flag to
+        * indicate wether to watch this fd for read
+        * or write events (there is currently no
+        * need for support of both).
+        */
+       virtual bool AddFd(int fd, bool readable, char type);
+
+       /** Returns the type value for this file descriptor
+        * This function masks off the X_READBIT value
+        * so that the type of the socket can be obtained.
+        * The core uses this to decide where to dispatch
+        * the event to. Please note that some engines
+        * such as select() have an upper limit of 1024
+        * descriptors which may be active at any one time,
+        * where others such as kqueue have no practical
+        * limits at all.
+        */
+       char GetType(int fd);
+
+       /** Returns the maximum number of file descriptors
+        * you may store in the socket engine at any one time.
+        */
+       virtual int GetMaxFds();
+
+       /** Returns the number of file descriptor slots
+        * which are available for storing fds.
+        */
+       virtual int GetRemainingFds();
+
+       /** Delete a file descriptor from the engine
+        * This function call deletes a file descriptor
+        * from the engine, returning true if it succeeded
+        * and false if it failed.
+        */
+       virtual bool DelFd(int fd);
+
+       /** Returns true if a socket exists in the socket
+        * engine's list.
+        */
+       bool HasFd(int fd);
+
+       /** Waits for an event.
+        * Please note that this doesnt wait long, only
+        * a couple of milliseconds. It returns a list
+        * of active file descriptors in the vector
+        * fdlist which the core may then act upon.
+        */
+       virtual int Wait(int* fdlist);
+
+       /** Returns the socket engines name
+        * This returns the name of the engine for use
+        * in /VERSION responses.
+        */
+       virtual std::string GetName();
+};
 
-#define epoll_fill      int i = epoll_wait(ep, event, 1, 5); \
-                        if (i > 0) \
-                        { \
-                                log(DEBUG,"epoll_wait call: ep=%d, i=%d",ep,i); \
-                                userrec* cu = fd_ref_table[event[0].data.fd];
-
-#define kqueue_fill     ts.tv_sec = 0; \
-                        ts.tv_nsec = 1000L; \
-                        int i = kevent(kq, NULL, 0, &ke, 1, &ts); \
-                        if (i > 0) \
-                        { \
-                                log(DEBUG,"kevent call: kq=%d, i=%d",kq,i); \
-                                userrec* cu = fd_ref_table[ke.ident];
-
-#define select_fill     tval.tv_sec = 0; \
-                        tval.tv_usec = 1000L; \
-                        selectResult2 = select(FD_SETSIZE, &sfd, NULL, NULL, &tval); \
-                        if ((selectResult2 > 0) && (xcount != clientlist.end())) \
-                        for (user_hash::iterator count2a = xcount; count2a != endingiter; count2a++) \
-                        { \
-                                if (count2a == clientlist.end()) \
-                                        break; \
-                                userrec* cu = count2a->second;
-
-#ifdef USE_EPOLL
-#define engine_fill epoll_fill
-#endif
-#ifdef USE_KQUEUE
-#define engine_fill kqueue_fill
-#endif
-#ifdef USE_SELECT
-#define engine_fill select_fill
-#endif
-
-#define epoll_check    ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
-
-#define kqueue_check   ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
-
-#define select_check   ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1) && (FD_ISSET (cu->fd, &sfd)))
-
-#ifdef USE_EPOLL
-#define engine_check epoll_check
-#endif
-#ifdef USE_KQUEUE
-#define engine_check kqueue_check
-#endif
-#ifdef USE_SELECT
-#define engine_check select_check
-#endif
-
-#define epoll_cleanup                   log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
-                                        kill_link(cu,"Client exited"); \
-                                        log(DEBUG,"Bailing from client exit"); \
-                                        goto label;
-
-#define kqueue_cleanup                  log(DEBUG,"InspIRCd: Exited: %s",cu->nick); \
-                                        kill_link(cu,"Client exited"); \
-                                        log(DEBUG,"Bailing from client exit"); \
-                                        goto label;
-
-#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
-
-
-#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
-
-#define epoll_server_populate               i = epoll_wait(sep, event, 1, EP_DELAY); \
-                                       if (i > 0) \
-                                       { \
-                                               log(DEBUG,"epoll: Listening server socket event, i=%d, event.data.fd=%d",i,event[0].data.fd); \
-                                               for (int x = 0; x != SERVERportCount; x++) \
-                                               { \
-                                                       if ((me[x]) && ((unsigned)event[0].data.fd == (unsigned)me[x]->fd)) \
-                                                       {
-#define kqueue_server_populate              ts.tv_sec = 0; \
-                                       ts.tv_nsec = 30000L; \
-                                       i = kevent(skq, NULL, 0, &ke, 1, &ts); \
-                                       if (i > 0) \
-                                       { \
-                                               log(DEBUG,"kqueue: Listening server socket event, i=%d, ke.ident=%d",i,ke.ident); \
-                                               for (int x = 0; x != SERVERportCount; x++) \
-                                               { \
-                                                       if ((me[x]) && ((unsigned)ke.ident == (unsigned)me[x]->fd)) \
-                                                       {
-
-#define select_server_populate              FD_ZERO(&serverfds); \
-                                       for (int x = 0; x != SERVERportCount; x++) \
-                                       { \
-                                               if (me[x]) \
-                                                       FD_SET(me[x]->fd, &serverfds); \
-                                       } \
-                                       tvs.tv_usec = 30000L; \
-                                       tvs.tv_sec = 0; \
-                                       int servresult = select(FD_SETSIZE, &serverfds, NULL, NULL, &tvs); \
-                                       if (servresult > 0) \
-                                       { \
-                                               for (int x = 0; x != SERVERportCount; x++) \
-                                               { \
-                                                       if ((me[x]) && (FD_ISSET (me[x]->fd, &serverfds))) \
-                                                       { 
-
-
-#ifdef USE_EPOLL
-#define engine_server_populate epoll_server_populate
-#endif
-#ifdef USE_KQUEUE
-#define engine_server_populate kqueue_server_populate
-#endif
-#ifdef USE_SELECT
-#define engine_server_populate select_server_populate
-#endif
-
-#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 serverfds; \
-        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
-
-#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
-
-#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); \
-                                       } \
-                               } \
-                               for (int t = 0; t != SERVERportCount; t++) \
-                               { \
-                                       struct epoll_event ev; \
-                                       log(DEBUG,"epoll: Add listening server socket to events, ep=%d socket=%d",sep,me[t]->fd); \
-                                       ev.events = EPOLLIN | EPOLLET; \
-                                       ev.data.fd = me[t]->fd; \
-                                       int i = epoll_ctl(sep, EPOLL_CTL_ADD, me[t]->fd, &ev); \
-                                       if (i == -1) \
-                                       { \
-                                               log(DEFAULT,"main: add server listen ports, epoll_ctl failed!"); \
-                                               printf("ERROR: could not initialise server 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); \
-                } \
-        } \
-        for (int t = 0; t != SERVERportCount; t++) \
-        { \
-                struct kevent ke; \
-                if (me[t]) \
-                { \
-                        log(DEBUG,"kqueue: Add listening SERVER socket to events, kq=%d socket=%d",skq,me[t]->fd); \
-                        EV_SET(&ke, me[t]->fd, EVFILT_READ, EV_ADD, 0, MaxConn, NULL); \
-                        int i = kevent(skq, &ke, 1, 0, 0, NULL); \
-                        if (i == -1) \
-                        { \
-                                log(DEFAULT,"main: add server listen ports to kqueue failed!"); \
-                                printf("ERROR: could not initialise listening server 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
-
-
-#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
-
-#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
-
-#ifdef USE_KQUEUE
-#define engine_name "kqueue"
-#endif
-#ifdef USE_SELECT
-#define engine_name "select"
-#endif
-#ifdef USE_EPOLL
-#define engine_name "epoll"
-#endif
-