]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine.cpp
bce1066cd4bf7df1525e87edca54de45e3e0d1ca
[user/henk/code/inspircd.git] / src / socketengine.cpp
1 #include "inspircd_config.h"
2 #include "globals.h"
3 #include "inspircd.h"
4 #ifdef USE_EPOLL
5 #include <sys/epoll.h>
6 #define EP_DELAY 5
7 #endif
8 #ifdef USE_KQUEUE
9 #include <sys/types.h>
10 #include <sys/event.h>
11 #include <sys/time.h>
12 #endif
13 #include <vector>
14 #include <string>
15 #include "socketengine.h"
16
17 char ref[65535];
18
19 SocketEngine::SocketEngine()
20 {
21         log(DEBUG,"SocketEngine::SocketEngine()");
22 #ifdef USE_EPOLL
23         EngineHandle = epoll_create(65535);
24 #endif
25 #ifdef USE_KQUEUE
26         EngineHandle = kqueue();
27 #endif
28 }
29
30 SocketEngine::~SocketEngine()
31 {
32         log(DEBUG,"SocketEngine::~SocketEngine()");
33 #ifdef USE_EPOLL
34         close(EngineHandle);
35 #endif
36 #ifdef USE_KQUEUE
37         close(EngineHandle);
38 #endif
39 }
40
41 char SocketEngine::GetType(int fd)
42 {
43         if ((fd < 0) || (fd > 65535))
44                 return X_EMPTY_SLOT;
45         /* Mask off the top bit used for 'read/write' state */
46         return (ref[fd] & ~0x80);
47 }
48
49 bool SocketEngine::AddFd(int fd, bool readable, char type)
50 {
51         if ((fd < 0) || (fd > 65535))
52                 return false;
53         this->fds.push_back(fd);
54         ref[fd] = type;
55         if (readable)
56         {
57                 log(DEBUG,"Set readbit");
58                 ref[fd] |= X_READBIT;
59         }
60         log(DEBUG,"Add socket %d",fd);
61 #ifdef USE_EPOLL
62         struct epoll_event ev;
63         log(DEBUG,"epoll: Add socket to events, ep=%d socket=%d",EngineHandle,fd);
64         readable ? ev.events = EPOLLIN | EPOLLET : ev.events = EPOLLOUT | EPOLLET;
65         ev.data.fd = fd;
66         int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
67         if (i < 0)
68         {
69                 log(DEBUG,"epoll: List insertion failure!");
70                 return false;
71         }
72 #endif
73 #ifdef USE_KQUEUE
74         struct kevent ke;
75         log(DEBUG,"kqueue: Add socket to events, kq=%d socket=%d",EngineHandle,fd);
76         EV_SET(&ke, fd, readable ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);
77         int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
78         if (i == -1)
79         {
80                 log(DEBUG,"kqueue: List insertion failure!");
81                 return false;
82         }
83 #endif
84 return true;
85 }
86
87 bool SocketEngine::DelFd(int fd)
88 {
89         log(DEBUG,"SocketEngine::DelFd(%d)",fd);
90
91         if ((fd < 0) || (fd > 65535))
92                 return false;
93
94         bool found = false;
95         for (std::vector<int>::iterator i = fds.begin(); i != fds.end(); i++)
96         {
97                 if (*i == fd)
98                 {
99                         fds.erase(i);
100                         log(DEBUG,"Deleted fd %d",fd);
101                         found = true;
102                         break;
103                 }
104         }
105 #ifdef USE_KQUEUE
106         struct kevent ke;
107         EV_SET(&ke, fd, ref[fd] && X_READBIT ? EVFILT_READ : EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
108         int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
109         if (i == -1)
110         {
111                 log(DEBUG,"kqueue: Failed to remove socket from queue!");
112                 return false;
113         }
114 #endif
115 #ifdef USE_EPOLL
116         struct epoll_event ev;
117         ref[fd] && X_READBIT ? ev.events = EPOLLIN | EPOLLET : ev.events = EPOLLOUT | EPOLLET;
118         ev.data.fd = fd;
119         int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
120         if (i < 0)
121         {
122                 log(DEBUG,"epoll: List deletion failure!");
123                 return false;
124         }
125 #endif
126         ref[fd] = 0;
127         return found;
128 }
129
130 bool SocketEngine::Wait(std::vector<int> &fdlist)
131 {
132         fdlist.clear();
133 #ifdef USE_SELECT
134         FD_ZERO(&wfdset);
135         FD_ZERO(&rfdset);
136         timeval tval;
137         int sresult;
138         for (unsigned int a = 0; a < fds.size(); a++)
139         {
140                 if (ref[fds[a]] & X_READBIT)
141                 {
142                         FD_SET (fds[a], &rfdset);
143                 }
144                 else
145                 {
146                         FD_SET (fds[a], &wfdset);
147                 }
148                 
149         }
150         tval.tv_sec = 0;
151         tval.tv_usec = 1000L;
152         sresult = select(FD_SETSIZE, &rfdset, &wfdset, NULL, &tval);
153         if (sresult > 0)
154         {
155                 for (unsigned int a = 0; a < fds.size(); a++)
156                 {
157                         if ((FD_ISSET (fds[a], &rfdset)) || (FD_ISSET (fds[a], &wfdset)))
158                         {
159                                 log(DEBUG,"...Adding active %d",fds[a]);
160                                 fdlist.push_back(fds[a]);
161                         }
162                 }
163         }
164 #endif
165 #ifdef USE_KQUEUE
166         ts.tv_nsec = 1000L;
167         ts.tv_sec = 0;
168         int i = kevent(EngineHandle, NULL, 0, &ke_list[0], 65535, &ts);
169         for (int j = 0; j < i; j++)
170                 fdlist.push_back(ke_list[j].ident);
171 #endif
172 #ifdef USE_EPOLL
173         int i = epoll_wait(EngineHandle, events, 65535, 1);
174         for (int j = 0; j < i; j++)
175                 fdlist.push_back(events[j].data.fd);
176 #endif
177         return true;
178 }
179
180 std::string SocketEngine::GetName()
181 {
182 #ifdef USE_SELECT
183         return "select";
184 #endif
185 #ifdef USE_KQUEUE
186         return "kqueue";
187 #endif
188 #ifdef USE_EPOLL
189         return "epoll";
190 #endif
191         return "misconfigured";
192 }