]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine.cpp
2fa1526042043ac59853ba96a49a46db95b155a2
[user/henk/code/inspircd.git] / src / socketengine.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 #include "inspircd_config.h"
18 #include "globals.h"
19 #include "inspircd.h"
20 #ifdef USE_EPOLL
21 #include <sys/epoll.h>
22 #endif
23 #ifdef USE_KQUEUE
24 #include <sys/types.h>
25 #include <sys/event.h>
26 #include <sys/time.h>
27 #endif
28 #include <vector>
29 #include <string>
30 #include "socketengine.h"
31
32 char ref[MAX_DESCRIPTORS];
33
34 SocketEngine::SocketEngine()
35 {
36         log(DEBUG,"SocketEngine::SocketEngine()");
37 #ifdef USE_EPOLL
38         EngineHandle = epoll_create(MAX_DESCRIPTORS);
39 #endif
40 #ifdef USE_KQUEUE
41         EngineHandle = kqueue();
42 #endif
43         CurrentSetSize = 0;
44 }
45
46 SocketEngine::~SocketEngine()
47 {
48         log(DEBUG,"SocketEngine::~SocketEngine()");
49 #ifdef USE_EPOLL
50         close(EngineHandle);
51 #endif
52 #ifdef USE_KQUEUE
53         close(EngineHandle);
54 #endif
55 }
56
57 char SocketEngine::GetType(int fd)
58 {
59         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
60                 return X_EMPTY_SLOT;
61         /* Mask off the top bit used for 'read/write' state */
62         return (ref[fd] & ~0x80);
63 }
64
65 bool SocketEngine::AddFd(int fd, bool readable, char type)
66 {
67         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
68         {
69                 log(DEFAULT,"ERROR: FD of %d added above max of %d",fd,MAX_DESCRIPTORS);
70                 return false;
71         }
72         if (GetRemainingFds() <= 1)
73         {
74                 log(DEFAULT,"ERROR: System out of file descriptors!");
75                 return false;
76         }
77 #ifdef USE_SELECT
78         fds[fd] = fd;
79 #endif
80         ref[fd] = type;
81         if (readable)
82         {
83                 log(DEBUG,"Set readbit");
84                 ref[fd] |= X_READBIT;
85         }
86         log(DEBUG,"Add socket %d",fd);
87 #ifdef USE_EPOLL
88         struct epoll_event ev;
89         log(DEBUG,"epoll: Add socket to events, ep=%d socket=%d",EngineHandle,fd);
90         readable ? ev.events = EPOLLIN : ev.events = EPOLLOUT;
91         ev.data.fd = fd;
92         int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
93         if (i < 0)
94         {
95                 log(DEBUG,"epoll: List insertion failure!");
96                 return false;
97         }
98 #endif
99 #ifdef USE_KQUEUE
100         struct kevent ke;
101         log(DEBUG,"kqueue: Add socket to events, kq=%d socket=%d",EngineHandle,fd);
102         EV_SET(&ke, fd, readable ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);
103         int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
104         if (i == -1)
105         {
106                 log(DEBUG,"kqueue: List insertion failure!");
107                 return false;
108         }
109 #endif
110         CurrentSetSize++;
111         return true;
112 }
113
114 bool SocketEngine::DelFd(int fd)
115 {
116         log(DEBUG,"SocketEngine::DelFd(%d)",fd);
117
118         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
119                 return false;
120
121 #ifdef USE_SELECT
122         std::map<int,int>::iterator t = fds.find(fd);
123         if (t != fds.end())
124         {
125                 fds.erase(t);
126                 log(DEBUG,"Deleted fd %d",fd);
127         }
128 #endif
129 #ifdef USE_KQUEUE
130         struct kevent ke;
131         EV_SET(&ke, fd, ref[fd] & X_READBIT ? EVFILT_READ : EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
132         int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
133         if (i == -1)
134         {
135                 log(DEBUG,"kqueue: Failed to remove socket from queue!");
136                 return false;
137         }
138 #endif
139 #ifdef USE_EPOLL
140         struct epoll_event ev;
141         ref[fd] && X_READBIT ? ev.events = EPOLLIN : ev.events = EPOLLOUT;
142         ev.data.fd = fd;
143         int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
144         if (i < 0)
145         {
146                 log(DEBUG,"epoll: List deletion failure!");
147                 return false;
148         }
149 #endif
150         CurrentSetSize--;
151         ref[fd] = 0;
152         return true;
153 }
154
155 int SocketEngine::GetMaxFds()
156 {
157 #ifdef USE_SELECT
158         return FD_SETSIZE;
159 #endif
160 #ifdef USE_KQUEUE
161         return MAX_DESCRIPTORS;
162 #endif
163 #ifdef USE_EPOLL
164         return MAX_DESCRIPTORS;
165 #endif
166 }
167
168 int SocketEngine::GetRemainingFds()
169 {
170 #ifdef USE_SELECT
171         return FD_SETSIZE - CurrentSetSize;
172 #endif
173 #ifdef USE_KQUEUE
174         return MAX_DESCRIPTORS - CurrentSetSize;
175 #endif
176 #ifdef USE_EPOLL
177         return MAX_DESCRIPTORS - CurrentSetSize;
178 #endif
179 }
180
181 int SocketEngine::Wait(int* fdlist)
182 {
183         int result = 0;
184 #ifdef USE_SELECT
185         FD_ZERO(&wfdset);
186         FD_ZERO(&rfdset);
187         timeval tval;
188         int sresult;
189         for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
190         {
191                 if (ref[a->second] & X_READBIT)
192                 {
193                         FD_SET (a->second, &rfdset);
194                 }
195                 else
196                 {
197                         FD_SET (a->second, &wfdset);
198                 }
199                 
200         }
201         tval.tv_sec = 0;
202         tval.tv_usec = 100L;
203         sresult = select(FD_SETSIZE, &rfdset, &wfdset, NULL, &tval);
204         if (sresult > 0)
205         {
206                 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
207                 {
208                         if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)))
209                                 fdlist[result++] = a->second;
210                 }
211         }
212 #endif
213 #ifdef USE_KQUEUE
214         ts.tv_nsec = 10000L;
215         ts.tv_sec = 0;
216         int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts);
217         for (int j = 0; j < i; j++)
218                 fdlist[result++] = ke_list[j].ident;
219 #endif
220 #ifdef USE_EPOLL
221         int i = epoll_wait(EngineHandle, events, MAX_DESCRIPTORS, 100);
222         for (int j = 0; j < i; j++)
223                 fdlist[result++] = events[j].data.fd;
224 #endif
225         return result;
226 }
227
228 std::string SocketEngine::GetName()
229 {
230 #ifdef USE_SELECT
231         return "select";
232 #endif
233 #ifdef USE_KQUEUE
234         return "kqueue";
235 #endif
236 #ifdef USE_EPOLL
237         return "epoll";
238 #endif
239         return "misconfigured";
240 }