00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "inspircd_config.h"
00018 #include "globals.h"
00019 #include "inspircd.h"
00020 #ifdef USE_EPOLL
00021 #include <sys/epoll.h>
00022 #define EP_DELAY 5
00023 #endif
00024 #ifdef USE_KQUEUE
00025 #include <sys/types.h>
00026 #include <sys/event.h>
00027 #include <sys/time.h>
00028 #endif
00029 #include <vector>
00030 #include <string>
00031 #include "socketengine.h"
00032
00033 char ref[65535];
00034
00035 SocketEngine::SocketEngine()
00036 {
00037 log(DEBUG,"SocketEngine::SocketEngine()");
00038 #ifdef USE_EPOLL
00039 EngineHandle = epoll_create(65535);
00040 #endif
00041 #ifdef USE_KQUEUE
00042 EngineHandle = kqueue();
00043 #endif
00044 }
00045
00046 SocketEngine::~SocketEngine()
00047 {
00048 log(DEBUG,"SocketEngine::~SocketEngine()");
00049 #ifdef USE_EPOLL
00050 close(EngineHandle);
00051 #endif
00052 #ifdef USE_KQUEUE
00053 close(EngineHandle);
00054 #endif
00055 }
00056
00057 char SocketEngine::GetType(int fd)
00058 {
00059 if ((fd < 0) || (fd > 65535))
00060 return X_EMPTY_SLOT;
00061
00062 return (ref[fd] & ~0x80);
00063 }
00064
00065 bool SocketEngine::AddFd(int fd, bool readable, char type)
00066 {
00067 if ((fd < 0) || (fd > 65535))
00068 return false;
00069 this->fds.push_back(fd);
00070 ref[fd] = type;
00071 if (readable)
00072 {
00073 log(DEBUG,"Set readbit");
00074 ref[fd] |= X_READBIT;
00075 }
00076 log(DEBUG,"Add socket %d",fd);
00077 #ifdef USE_EPOLL
00078 struct epoll_event ev;
00079 log(DEBUG,"epoll: Add socket to events, ep=%d socket=%d",EngineHandle,fd);
00080 readable ? ev.events = EPOLLIN | EPOLLET : ev.events = EPOLLOUT | EPOLLET;
00081 ev.data.fd = fd;
00082 int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
00083 if (i < 0)
00084 {
00085 log(DEBUG,"epoll: List insertion failure!");
00086 return false;
00087 }
00088 #endif
00089 #ifdef USE_KQUEUE
00090 struct kevent ke;
00091 log(DEBUG,"kqueue: Add socket to events, kq=%d socket=%d",EngineHandle,fd);
00092 EV_SET(&ke, fd, readable ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);
00093 int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
00094 if (i == -1)
00095 {
00096 log(DEBUG,"kqueue: List insertion failure!");
00097 return false;
00098 }
00099 #endif
00100 return true;
00101 }
00102
00103 bool SocketEngine::DelFd(int fd)
00104 {
00105 log(DEBUG,"SocketEngine::DelFd(%d)",fd);
00106
00107 if ((fd < 0) || (fd > 65535))
00108 return false;
00109
00110 bool found = false;
00111 for (std::vector<int>::iterator i = fds.begin(); i != fds.end(); i++)
00112 {
00113 if (*i == fd)
00114 {
00115 fds.erase(i);
00116 log(DEBUG,"Deleted fd %d",fd);
00117 found = true;
00118 break;
00119 }
00120 }
00121 #ifdef USE_KQUEUE
00122 struct kevent ke;
00123 EV_SET(&ke, fd, ref[fd] & X_READBIT ? EVFILT_READ : EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
00124 int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
00125 if (i == -1)
00126 {
00127 log(DEBUG,"kqueue: Failed to remove socket from queue!");
00128 return false;
00129 }
00130 #endif
00131 #ifdef USE_EPOLL
00132 struct epoll_event ev;
00133 ref[fd] && X_READBIT ? ev.events = EPOLLIN | EPOLLET : ev.events = EPOLLOUT | EPOLLET;
00134 ev.data.fd = fd;
00135 int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
00136 if (i < 0)
00137 {
00138 log(DEBUG,"epoll: List deletion failure!");
00139 return false;
00140 }
00141 #endif
00142 ref[fd] = 0;
00143 return found;
00144 }
00145
00146 bool SocketEngine::Wait(std::vector<int> &fdlist)
00147 {
00148 fdlist.clear();
00149 #ifdef USE_SELECT
00150 FD_ZERO(&wfdset);
00151 FD_ZERO(&rfdset);
00152 timeval tval;
00153 int sresult;
00154 for (unsigned int a = 0; a < fds.size(); a++)
00155 {
00156 if (ref[fds[a]] & X_READBIT)
00157 {
00158 FD_SET (fds[a], &rfdset);
00159 }
00160 else
00161 {
00162 FD_SET (fds[a], &wfdset);
00163 }
00164
00165 }
00166 tval.tv_sec = 0;
00167 tval.tv_usec = 100L;
00168 sresult = select(FD_SETSIZE, &rfdset, &wfdset, NULL, &tval);
00169 if (sresult > 0)
00170 {
00171 for (unsigned int a = 0; a < fds.size(); a++)
00172 {
00173 if ((FD_ISSET (fds[a], &rfdset)) || (FD_ISSET (fds[a], &wfdset)))
00174 fdlist.push_back(fds[a]);
00175 }
00176 }
00177 #endif
00178 #ifdef USE_KQUEUE
00179 ts.tv_nsec = 10000L;
00180 ts.tv_sec = 0;
00181 int i = kevent(EngineHandle, NULL, 0, &ke_list[0], 65535, &ts);
00182 for (int j = 0; j < i; j++)
00183 fdlist.push_back(ke_list[j].ident);
00184 #endif
00185 #ifdef USE_EPOLL
00186 int i = epoll_wait(EngineHandle, events, 65535, 100);
00187 for (int j = 0; j < i; j++)
00188 fdlist.push_back(events[j].data.fd);
00189 #endif
00190 return true;
00191 }
00192
00193 std::string SocketEngine::GetName()
00194 {
00195 #ifdef USE_SELECT
00196 return "select";
00197 #endif
00198 #ifdef USE_KQUEUE
00199 return "kqueue";
00200 #endif
00201 #ifdef USE_EPOLL
00202 return "epoll";
00203 #endif
00204 return "misconfigured";
00205 }