X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=include%2Fsocketengine.h;h=a788618a27a47ceb6a5d6f6c2018c40396ccb26d;hb=2329d59b09cdc05b0b403f7d313df65492e1813b;hp=c99ffa5179a8cede60e3f3beb36b80e90da173a7;hpb=a6c55540f551674f17ccca73f116358b6b207721;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/include/socketengine.h b/include/socketengine.h index c99ffa517..a788618a2 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -1,366 +1,151 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev. + * E-mail: + * + * + * + * 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 +#include +#include +#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 -