|
a/src/netcon.cpp |
|
b/src/netcon.cpp |
|
... |
|
... |
27 |
|
27 |
|
28 |
#include <stdio.h>
|
28 |
#include <stdio.h>
|
29 |
#include <stdlib.h>
|
29 |
#include <stdlib.h>
|
30 |
#include <string.h>
|
30 |
#include <string.h>
|
31 |
#include <errno.h>
|
31 |
#include <errno.h>
|
|
|
32 |
#include <stdint.h>
|
32 |
|
33 |
|
33 |
#ifdef _AIX
|
34 |
#ifdef _AIX
|
34 |
#include <strings.h>
|
35 |
#include <strings.h>
|
35 |
#endif // _AIX
|
36 |
#endif // _AIX
|
36 |
|
37 |
|
37 |
#include <unistd.h>
|
38 |
#include <unistd.h>
|
38 |
#include <fcntl.h>
|
39 |
#include <fcntl.h>
|
39 |
#include <sys/time.h>
|
|
|
40 |
#include <sys/socket.h>
|
40 |
#include <sys/socket.h>
|
41 |
#include <sys/un.h>
|
41 |
#include <sys/un.h>
|
42 |
#include <netinet/in.h>
|
42 |
#include <netinet/in.h>
|
43 |
#include <netinet/tcp.h>
|
43 |
#include <netinet/tcp.h>
|
44 |
#include <arpa/inet.h>
|
44 |
#include <arpa/inet.h>
|
45 |
#include <netdb.h>
|
45 |
#include <netdb.h>
|
|
|
46 |
#ifdef HAVE_KQUEUE
|
|
|
47 |
#include <sys/types.h>
|
|
|
48 |
#include <sys/event.h>
|
|
|
49 |
#include <vector>
|
|
|
50 |
#endif
|
46 |
|
51 |
|
47 |
#include <map>
|
52 |
#include <map>
|
48 |
|
53 |
|
49 |
#include "log.h"
|
54 |
#include "log.h"
|
50 |
|
55 |
|
|
... |
|
... |
53 |
#ifndef SOCKLEN_T
|
58 |
#ifndef SOCKLEN_T
|
54 |
#define SOCKLEN_T socklen_t
|
59 |
#define SOCKLEN_T socklen_t
|
55 |
#endif
|
60 |
#endif
|
56 |
|
61 |
|
57 |
// Size of path buffer in sockaddr_un (AF_UNIX socket
|
62 |
// Size of path buffer in sockaddr_un (AF_UNIX socket
|
58 |
// addr). Mysteriously it's 108 (explicit value) under linux, no
|
63 |
// addr). Mysteriously it is 108 (explicit value) under linux, no
|
59 |
// define accessible. Let's take a little margin as it appears that
|
64 |
// define accessible. Let's take a little margin as it appears that
|
60 |
// some systems use 92. I believe we could also malloc a variable size
|
65 |
// some systems use 92. I believe we could also malloc a variable size
|
61 |
// struct but why bother.
|
66 |
// struct but why bother.
|
62 |
#ifndef UNIX_PATH_MAX
|
67 |
#ifndef UNIX_PATH_MAX
|
63 |
#define UNIX_PATH_MAX 90
|
68 |
#define UNIX_PATH_MAX 90
|
|
... |
|
... |
79 |
#endif
|
84 |
#endif
|
80 |
#ifndef freeZ
|
85 |
#ifndef freeZ
|
81 |
#define freeZ(X) if (X) {free(X);X=0;}
|
86 |
#define freeZ(X) if (X) {free(X);X=0;}
|
82 |
#endif
|
87 |
#endif
|
83 |
|
88 |
|
84 |
#define MILLIS(OLD, NEW) ( (long)(((NEW).tv_sec - (OLD).tv_sec) * 1000 + \
|
89 |
#define MILLIS(OLD, NEW) ( (uint64_t((NEW).tv_sec) - (OLD).tv_sec) * 1000 + \
|
85 |
((NEW).tv_usec - (OLD).tv_usec) / 1000))
|
90 |
((NEW).tv_usec - (OLD).tv_usec) / 1000 )
|
86 |
|
91 |
|
87 |
// Static method
|
92 |
// Static method
|
88 |
// Simplified interface to 'select()'. Only use one fd, for either
|
93 |
// Simplified interface to 'select()'. Only use one fd, for either
|
89 |
// reading or writing. This is only used when not using the
|
94 |
// reading or writing. This is only used when not using the
|
90 |
// selectloop() style of network i/o.
|
95 |
// selectloop() style of network i/o.
|
|
... |
|
... |
107 |
LOGDEB2("Netcon::select1: fd " << fd << " timeout\n");
|
112 |
LOGDEB2("Netcon::select1: fd " << fd << " timeout\n");
|
108 |
}
|
113 |
}
|
109 |
return ret;
|
114 |
return ret;
|
110 |
}
|
115 |
}
|
111 |
|
116 |
|
|
|
117 |
|
|
|
118 |
///////////////////////////////////////////
|
|
|
119 |
// SelectLoop
|
|
|
120 |
|
|
|
121 |
class SelectLoop::Internal {
|
|
|
122 |
public:
|
|
|
123 |
Internal() {
|
|
|
124 |
#ifdef HAVE_KQUEUE
|
|
|
125 |
if ((kq = kqueue()) == -1) {
|
|
|
126 |
LOGSYSERR("Netcon::selectloop", "kqueue", "");
|
|
|
127 |
}
|
|
|
128 |
#endif
|
|
|
129 |
}
|
|
|
130 |
|
|
|
131 |
~Internal() {
|
|
|
132 |
#ifdef HAVE_KQUEUE
|
|
|
133 |
if (kq >= 0)
|
|
|
134 |
close(kq);
|
|
|
135 |
#endif
|
|
|
136 |
}
|
|
|
137 |
|
|
|
138 |
// Set by client callback to tell selectloop to return.
|
|
|
139 |
bool selectloopDoReturn{false};
|
|
|
140 |
int selectloopReturnValue{0};
|
|
|
141 |
int placetostart{0};
|
|
|
142 |
|
|
|
143 |
// Map of NetconP indexed by fd
|
|
|
144 |
map<int, NetconP> polldata;
|
|
|
145 |
#ifdef HAVE_KQUEUE
|
|
|
146 |
int kq{-1};
|
|
|
147 |
#endif
|
|
|
148 |
// The last time we did the periodic thing. Initialized by setperiodic()
|
|
|
149 |
struct timeval lasthdlcall;
|
|
|
150 |
|
|
|
151 |
// The call back function and its parameter
|
|
|
152 |
int (*periodichandler)(void *){0};
|
|
|
153 |
void *periodicparam{0};
|
|
|
154 |
// The periodic interval
|
|
|
155 |
int periodicmillis{0};
|
|
|
156 |
|
|
|
157 |
void periodictimeout(struct timeval *tv);
|
|
|
158 |
void periodictimeout(struct timespec *ts);
|
|
|
159 |
int maybecallperiodic();
|
|
|
160 |
int setselevents(int fd, int events);
|
|
|
161 |
int setselevents(NetconP& con, int events);
|
|
|
162 |
};
|
|
|
163 |
|
|
|
164 |
SelectLoop::SelectLoop()
|
|
|
165 |
{
|
|
|
166 |
m = new Internal;
|
|
|
167 |
}
|
|
|
168 |
|
|
|
169 |
SelectLoop::~SelectLoop()
|
|
|
170 |
{
|
|
|
171 |
delete m;
|
|
|
172 |
}
|
|
|
173 |
|
|
|
174 |
void SelectLoop::loopReturn(int value)
|
|
|
175 |
{
|
|
|
176 |
m->selectloopDoReturn = true;
|
|
|
177 |
m->selectloopReturnValue = value;
|
|
|
178 |
}
|
|
|
179 |
|
112 |
void SelectLoop::setperiodichandler(int (*handler)(void *), void *p, int ms)
|
180 |
void SelectLoop::setperiodichandler(int (*handler)(void *), void *p, int ms)
|
113 |
{
|
181 |
{
|
114 |
m_periodichandler = handler;
|
182 |
m->periodichandler = handler;
|
115 |
m_periodicparam = p;
|
183 |
m->periodicparam = p;
|
116 |
m_periodicmillis = ms;
|
184 |
m->periodicmillis = ms;
|
117 |
if (m_periodicmillis > 0) {
|
185 |
if (m->periodicmillis > 0) {
|
118 |
gettimeofday(&m_lasthdlcall, 0);
|
186 |
gettimeofday(&m->lasthdlcall, 0);
|
119 |
}
|
187 |
}
|
120 |
}
|
188 |
}
|
121 |
|
189 |
|
122 |
// Compute the appropriate timeout so that the select call returns in
|
190 |
// Compute the appropriate timeout so that the select call returns in
|
123 |
// time to call the periodic routine.
|
191 |
// time to call the periodic routine.
|
124 |
void SelectLoop::periodictimeout(struct timeval *tv)
|
192 |
void SelectLoop::Internal::periodictimeout(struct timeval *tv)
|
125 |
{
|
193 |
{
|
126 |
// If periodic not set, the select call times out and we loop
|
194 |
// If periodic not set, the select call times out and we loop
|
127 |
// after a very long time (we'd need to pass NULL to select for an
|
195 |
// after a very long time (we'd need to pass NULL to select for an
|
128 |
// infinite wait, and I'm too lazy to handle it)
|
196 |
// infinite wait, and I'm too lazy to handle it)
|
129 |
if (m_periodicmillis <= 0) {
|
197 |
if (periodicmillis <= 0) {
|
130 |
tv->tv_sec = 10000;
|
198 |
tv->tv_sec = 10000;
|
131 |
tv->tv_usec = 0;
|
199 |
tv->tv_usec = 0;
|
132 |
return;
|
200 |
return;
|
133 |
}
|
201 |
}
|
134 |
|
202 |
|
135 |
struct timeval mtv;
|
203 |
struct timeval mtv;
|
136 |
gettimeofday(&mtv, 0);
|
204 |
gettimeofday(&mtv, 0);
|
137 |
int millis = m_periodicmillis - MILLIS(m_lasthdlcall, mtv);
|
205 |
int millis = periodicmillis - MILLIS(lasthdlcall, mtv);
|
138 |
|
206 |
|
139 |
// millis <= 0 means we should have already done the thing. *dont* set the
|
207 |
// millis <= 0 means we should have already done the thing. *dont* set the
|
140 |
// tv to 0, which means no timeout at all !
|
208 |
// tv to 0, which means no timeout at all !
|
141 |
if (millis <= 0) {
|
209 |
if (millis <= 0) {
|
142 |
millis = 1;
|
210 |
millis = 1;
|
143 |
}
|
211 |
}
|
144 |
tv->tv_sec = millis / 1000;
|
212 |
tv->tv_sec = millis / 1000;
|
145 |
tv->tv_usec = (millis % 1000) * 1000;
|
213 |
tv->tv_usec = (millis % 1000) * 1000;
|
146 |
}
|
214 |
}
|
147 |
|
215 |
|
|
|
216 |
void SelectLoop::Internal::periodictimeout(struct timespec *ts)
|
|
|
217 |
{
|
|
|
218 |
struct timeval tv;
|
|
|
219 |
periodictimeout(&tv);
|
|
|
220 |
ts->tv_sec = tv.tv_sec;
|
|
|
221 |
ts->tv_nsec = tv.tv_usec * 1000;
|
|
|
222 |
}
|
|
|
223 |
|
|
|
224 |
|
148 |
// Check if it's time to call the handler. selectloop will return to
|
225 |
// Check if it's time to call the handler. selectloop will return to
|
149 |
// caller if it or we return 0
|
226 |
// caller if either we or the handler return 0
|
150 |
int SelectLoop::maybecallperiodic()
|
227 |
int SelectLoop::Internal::maybecallperiodic()
|
151 |
{
|
228 |
{
|
152 |
if (m_periodicmillis <= 0) {
|
229 |
if (periodicmillis <= 0) {
|
153 |
return 1;
|
230 |
return 1;
|
154 |
}
|
231 |
}
|
|
|
232 |
|
155 |
struct timeval mtv;
|
233 |
struct timeval mtv;
|
156 |
gettimeofday(&mtv, 0);
|
234 |
gettimeofday(&mtv, 0);
|
157 |
int millis = m_periodicmillis - MILLIS(m_lasthdlcall, mtv);
|
235 |
int millis = periodicmillis - MILLIS(lasthdlcall, mtv);
|
|
|
236 |
|
158 |
if (millis <= 0) {
|
237 |
if (millis <= 0) {
|
159 |
gettimeofday(&m_lasthdlcall, 0);
|
238 |
lasthdlcall = mtv;
|
160 |
if (m_periodichandler) {
|
239 |
if (periodichandler) {
|
161 |
return m_periodichandler(m_periodicparam);
|
240 |
return periodichandler(periodicparam);
|
162 |
} else {
|
241 |
} else {
|
163 |
return 0;
|
242 |
return 0;
|
164 |
}
|
243 |
}
|
165 |
}
|
244 |
}
|
166 |
return 1;
|
245 |
return 1;
|
167 |
}
|
246 |
}
|
168 |
|
247 |
|
|
|
248 |
#ifndef HAVE_KQUEUE
|
|
|
249 |
|
169 |
int SelectLoop::doLoop()
|
250 |
int SelectLoop::doLoop()
|
170 |
{
|
251 |
{
|
171 |
for (;;) {
|
252 |
for (;;) {
|
172 |
if (m_selectloopDoReturn) {
|
253 |
if (m->selectloopDoReturn) {
|
173 |
m_selectloopDoReturn = false;
|
254 |
m->selectloopDoReturn = false;
|
174 |
LOGDEB("Netcon::selectloop: returning on request\n");
|
255 |
LOGDEB("Netcon::selectloop: returning on request\n");
|
175 |
return m_selectloopReturnValue;
|
256 |
return m->selectloopReturnValue;
|
176 |
}
|
257 |
}
|
|
|
258 |
|
177 |
int nfds;
|
259 |
int nfds;
|
178 |
fd_set rd, wd;
|
260 |
fd_set rd, wd;
|
179 |
FD_ZERO(&rd);
|
261 |
FD_ZERO(&rd);
|
180 |
FD_ZERO(&wd);
|
262 |
FD_ZERO(&wd);
|
181 |
|
263 |
|
182 |
// Walk the netcon map and set up the read and write fd_sets
|
264 |
// Walk the netcon map and set up the read and write fd_sets
|
183 |
// for select()
|
265 |
// for select()
|
184 |
nfds = 0;
|
266 |
nfds = 0;
|
185 |
for (map<int, NetconP>::iterator it = m_polldata.begin();
|
267 |
for (auto& entry : m->polldata) {
|
186 |
it != m_polldata.end(); it++) {
|
|
|
187 |
NetconP& pll = it->second;
|
268 |
NetconP& pll = entry.second;
|
188 |
int fd = it->first;
|
269 |
int fd = entry.first;
|
189 |
LOGDEB2("Selectloop: fd " << fd << " flags 0x" <<
|
270 |
LOGDEB2("Selectloop: fd " << fd << " flags 0x" <<
|
190 |
pll->m_wantedEvents << "\n");
|
271 |
pll->m_wantedEvents << "\n");
|
191 |
if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) {
|
272 |
if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) {
|
192 |
FD_SET(fd, &rd);
|
273 |
FD_SET(fd, &rd);
|
193 |
nfds = MAX(nfds, fd + 1);
|
274 |
nfds = MAX(nfds, fd + 1);
|
|
... |
|
... |
204 |
// client, it's up to client code to avoid or process this
|
285 |
// client, it's up to client code to avoid or process this
|
205 |
// condition.
|
286 |
// condition.
|
206 |
|
287 |
|
207 |
// Just in case there would still be open fds in there
|
288 |
// Just in case there would still be open fds in there
|
208 |
// (with no r/w flags set). Should not be needed, but safer
|
289 |
// (with no r/w flags set). Should not be needed, but safer
|
209 |
m_polldata.clear();
|
290 |
m->polldata.clear();
|
210 |
LOGDEB1("Netcon::selectloop: no fds\n");
|
291 |
LOGDEB1("Netcon::selectloop: no fds\n");
|
211 |
return 0;
|
292 |
return 0;
|
212 |
}
|
293 |
}
|
213 |
|
294 |
|
214 |
LOGDEB2("Netcon::selectloop: selecting, nfds = " << nfds << "\n");
|
295 |
LOGDEB2("Netcon::selectloop: selecting, nfds = " << nfds << "\n");
|
215 |
|
296 |
|
216 |
// Compute the next timeout according to what might need to be
|
297 |
// Compute the next timeout according to what might need to be
|
217 |
// done apart from waiting for data
|
298 |
// done apart from waiting for data
|
218 |
struct timeval tv;
|
299 |
struct timeval tv;
|
219 |
periodictimeout(&tv);
|
300 |
m->periodictimeout(&tv);
|
220 |
// Wait for something to happen
|
301 |
// Wait for something to happen
|
221 |
int ret = select(nfds, &rd, &wd, 0, &tv);
|
302 |
int ret = select(nfds, &rd, &wd, 0, &tv);
|
222 |
LOGDEB2("Netcon::selectloop: nfds " << nfds <<
|
303 |
LOGDEB2("Netcon::selectloop: nfds " << nfds <<
|
223 |
" select returns " << ret << "\n");
|
304 |
" select returns " << ret << "\n");
|
224 |
if (ret < 0) {
|
305 |
if (ret < 0) {
|
225 |
LOGSYSERR("Netcon::selectloop", "select", "");
|
306 |
LOGSYSERR("Netcon::selectloop", "select", "");
|
226 |
return -1;
|
307 |
return -1;
|
227 |
}
|
308 |
}
|
228 |
if (m_periodicmillis > 0 && maybecallperiodic() <= 0) {
|
309 |
if (m->periodicmillis > 0 && m->maybecallperiodic() <= 0) {
|
229 |
return 1;
|
310 |
return 1;
|
230 |
}
|
311 |
}
|
231 |
|
312 |
|
232 |
// Timeout, do it again.
|
313 |
// Timeout, do it again.
|
233 |
if (ret == 0) {
|
314 |
if (ret == 0) {
|
|
... |
|
... |
240 |
// Note that we do an fd sweep, not a map sweep. This is
|
321 |
// Note that we do an fd sweep, not a map sweep. This is
|
241 |
// inefficient because the fd array may be very sparse. Otoh, the
|
322 |
// inefficient because the fd array may be very sparse. Otoh, the
|
242 |
// map may change between 2 sweeps, so that we'd have to be smart
|
323 |
// map may change between 2 sweeps, so that we'd have to be smart
|
243 |
// with the iterator. As the cost per unused fd is low (just 2 bit
|
324 |
// with the iterator. As the cost per unused fd is low (just 2 bit
|
244 |
// flag tests), we keep it like this for now
|
325 |
// flag tests), we keep it like this for now
|
245 |
if (m_placetostart >= nfds) {
|
326 |
if (m->placetostart >= nfds) {
|
246 |
m_placetostart = 0;
|
327 |
m->placetostart = 0;
|
247 |
}
|
328 |
}
|
248 |
int i, fd;
|
329 |
int i, fd;
|
249 |
int activefds = 0;
|
330 |
int activefds = 0;
|
250 |
for (i = 0, fd = m_placetostart; i < nfds; i++, fd++) {
|
331 |
for (i = 0, fd = m->placetostart; i < nfds; i++, fd++) {
|
251 |
if (fd >= nfds) {
|
332 |
if (fd >= nfds) {
|
252 |
fd = 0;
|
333 |
fd = 0;
|
253 |
}
|
334 |
}
|
254 |
|
335 |
|
255 |
int canread = FD_ISSET(fd, &rd);
|
336 |
int canread = FD_ISSET(fd, &rd);
|
|
... |
|
... |
261 |
(canwrite ? "write" : "") << "\n");
|
342 |
(canwrite ? "write" : "") << "\n");
|
262 |
if (none) {
|
343 |
if (none) {
|
263 |
continue;
|
344 |
continue;
|
264 |
}
|
345 |
}
|
265 |
|
346 |
|
266 |
map<int, NetconP>::iterator it = m_polldata.find(fd);
|
347 |
auto it = m->polldata.find(fd);
|
267 |
if (it == m_polldata.end()) {
|
348 |
if (it == m->polldata.end()) {
|
268 |
// This should never happen, because we only set our
|
349 |
// This should never happen, because we only set our
|
269 |
// own fds in the mask !
|
350 |
// own fds in the mask !
|
270 |
LOGERR("Netcon::selectloop: fd " << fd << " not found\n");
|
351 |
LOGERR("Netcon::selectloop: fd " << fd << " not found\n");
|
271 |
continue;
|
352 |
continue;
|
272 |
}
|
353 |
}
|
273 |
activefds++;
|
354 |
activefds++;
|
274 |
// Next start will be one beyond last serviced (modulo nfds)
|
355 |
// Next start will be one beyond last serviced (modulo nfds)
|
275 |
m_placetostart = fd + 1;
|
356 |
m->placetostart = fd + 1;
|
276 |
|
357 |
|
277 |
NetconP& pll = it->second;
|
358 |
NetconP& pll = it->second;
|
278 |
if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0) {
|
359 |
if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0) {
|
279 |
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_READ;
|
360 |
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_READ;
|
280 |
}
|
361 |
}
|
|
... |
|
... |
283 |
}
|
364 |
}
|
284 |
if (!(pll->m_wantedEvents &
|
365 |
if (!(pll->m_wantedEvents &
|
285 |
(Netcon::NETCONPOLL_WRITE | Netcon::NETCONPOLL_READ))) {
|
366 |
(Netcon::NETCONPOLL_WRITE | Netcon::NETCONPOLL_READ))) {
|
286 |
LOGDEB0("Netcon::selectloop: fd " << it->first << " has 0x"
|
367 |
LOGDEB0("Netcon::selectloop: fd " << it->first << " has 0x"
|
287 |
<< it->second->m_wantedEvents << " mask, erasing\n");
|
368 |
<< it->second->m_wantedEvents << " mask, erasing\n");
|
288 |
m_polldata.erase(it);
|
369 |
m->polldata.erase(it);
|
289 |
}
|
370 |
}
|
290 |
} // fd sweep
|
371 |
} // fd sweep
|
291 |
|
372 |
|
292 |
if (ret > 0 && activefds != ret) {
|
373 |
if (ret > 0 && activefds != ret) {
|
293 |
LOGERR("Select returned " << ret << " not equal to " <<
|
374 |
LOGERR("Select returned " << ret << " not equal to " <<
|
|
... |
|
... |
297 |
} // forever loop
|
378 |
} // forever loop
|
298 |
LOGERR("SelectLoop::doLoop: got out of loop !\n");
|
379 |
LOGERR("SelectLoop::doLoop: got out of loop !\n");
|
299 |
return -1;
|
380 |
return -1;
|
300 |
}
|
381 |
}
|
301 |
|
382 |
|
|
|
383 |
#else // -> Using kqueue: use select()
|
|
|
384 |
|
|
|
385 |
int SelectLoop::doLoop()
|
|
|
386 |
{
|
|
|
387 |
for (;;) {
|
|
|
388 |
if (m->selectloopDoReturn) {
|
|
|
389 |
m->selectloopDoReturn = false;
|
|
|
390 |
LOGDEB("Netcon::selectloop: returning on request\n");
|
|
|
391 |
return m->selectloopReturnValue;
|
|
|
392 |
}
|
|
|
393 |
|
|
|
394 |
// Check that we do have something to wait for.
|
|
|
395 |
int nfds = 0;
|
|
|
396 |
for (auto& entry : m->polldata) {
|
|
|
397 |
NetconP& pll = entry.second;
|
|
|
398 |
if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) {
|
|
|
399 |
nfds++;
|
|
|
400 |
} else if (pll->m_wantedEvents & Netcon::NETCONPOLL_WRITE) {
|
|
|
401 |
nfds++;
|
|
|
402 |
}
|
|
|
403 |
}
|
|
|
404 |
if (nfds == 0) {
|
|
|
405 |
// This should never happen in a server as we should at least
|
|
|
406 |
// always monitor the main listening server socket. For a
|
|
|
407 |
// client, it's up to client code to avoid or process this
|
|
|
408 |
// condition.
|
|
|
409 |
|
|
|
410 |
// Just in case there would still be open fds in there
|
|
|
411 |
// (with no r/w flags set). Should not be needed, but safer
|
|
|
412 |
m->polldata.clear();
|
|
|
413 |
LOGDEB1("Netcon::selectloop: no fds\n");
|
|
|
414 |
return 0;
|
|
|
415 |
}
|
|
|
416 |
|
|
|
417 |
// Compute the next timeout according to what might need to be
|
|
|
418 |
// done apart from waiting for data
|
|
|
419 |
struct timespec ts;
|
|
|
420 |
m->periodictimeout(&ts);
|
|
|
421 |
// Wait for something to happen
|
|
|
422 |
vector<struct kevent> events;
|
|
|
423 |
events.resize(nfds);
|
|
|
424 |
LOGDEB("Netcon::selectloop: kevent(), nfds = " << nfds << "\n");
|
|
|
425 |
int ret = kevent(m->kq, 0, 0, &events[0], events.size(), &ts);
|
|
|
426 |
LOGDEB("Netcon::selectloop: nfds " << nfds <<
|
|
|
427 |
" kevent returns " << ret << "\n");
|
|
|
428 |
if (ret < 0) {
|
|
|
429 |
LOGSYSERR("Netcon::selectloop", "kevent", "");
|
|
|
430 |
return -1;
|
|
|
431 |
}
|
|
|
432 |
if (m->periodicmillis > 0 && m->maybecallperiodic() <= 0) {
|
|
|
433 |
return 1;
|
|
|
434 |
}
|
|
|
435 |
if (ret == 0) {
|
|
|
436 |
// Timeout, do it again.
|
|
|
437 |
continue;
|
|
|
438 |
}
|
|
|
439 |
|
|
|
440 |
for (int i = 0; i < ret; i++) {
|
|
|
441 |
struct kevent& ev = events[i];
|
|
|
442 |
if (ev.flags & EV_ERROR) {
|
|
|
443 |
LOGSYSERR("Netcon::selectLoop", "kevent", "");
|
|
|
444 |
LOGERR("Netcon::selectLoop: event error: " <<
|
|
|
445 |
strerror(ev.data));
|
|
|
446 |
return -1;
|
|
|
447 |
}
|
|
|
448 |
int canread = ev.filter == EVFILT_READ;
|
|
|
449 |
int canwrite = ev.filter == EVFILT_WRITE;
|
|
|
450 |
bool none = !canread && !canwrite;
|
|
|
451 |
LOGDEB("Netcon::selectloop: fd " << int(ev.ident) << " " <<
|
|
|
452 |
(none ? "blocked" : "can") << " " <<
|
|
|
453 |
(canread ? "read" : "") << " " <<
|
|
|
454 |
(canwrite ? "write" : "") << "\n");
|
|
|
455 |
if (none) {
|
|
|
456 |
LOGERR("Kevent returned unknown filter " << ev.filter <<endl);
|
|
|
457 |
continue;
|
|
|
458 |
}
|
|
|
459 |
|
|
|
460 |
auto it = m->polldata.find(int(ev.ident));
|
|
|
461 |
if (it == m->polldata.end()) {
|
|
|
462 |
LOGERR("Netcon::selectloop: fd " << int(ev.ident) <<
|
|
|
463 |
" not found\n");
|
|
|
464 |
continue;
|
|
|
465 |
}
|
|
|
466 |
NetconP& pll = it->second;
|
|
|
467 |
if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0) {
|
|
|
468 |
pll->setselevents(pll->getselevents() &
|
|
|
469 |
~Netcon::NETCONPOLL_READ);
|
|
|
470 |
}
|
|
|
471 |
if (canwrite && pll->cando(Netcon::NETCONPOLL_WRITE) <= 0) {
|
|
|
472 |
pll->setselevents(pll->getselevents() &
|
|
|
473 |
~Netcon::NETCONPOLL_WRITE);
|
|
|
474 |
}
|
|
|
475 |
if (!(pll->getselevents() &
|
|
|
476 |
(Netcon::NETCONPOLL_WRITE | Netcon::NETCONPOLL_READ))) {
|
|
|
477 |
LOGDEB0("Netcon::selectloop: fd " << it->first << " has 0x"
|
|
|
478 |
<< it->second->getselevents() << " mask, erasing\n");
|
|
|
479 |
m->polldata.erase(it);
|
|
|
480 |
}
|
|
|
481 |
} // fd sweep
|
|
|
482 |
|
|
|
483 |
} // forever loop
|
|
|
484 |
LOGERR("SelectLoop::doLoop: got out of loop !\n");
|
|
|
485 |
return -1;
|
|
|
486 |
}
|
|
|
487 |
|
|
|
488 |
#endif // kqueue version
|
|
|
489 |
|
|
|
490 |
int SelectLoop::Internal::setselevents(int fd, int events)
|
|
|
491 |
{
|
|
|
492 |
#ifdef HAVE_KQUEUE
|
|
|
493 |
auto it = polldata.find(fd);
|
|
|
494 |
if (it == polldata.end()) {
|
|
|
495 |
return -1;
|
|
|
496 |
}
|
|
|
497 |
return setselevents(it->second, events);
|
|
|
498 |
#endif
|
|
|
499 |
return 0;
|
|
|
500 |
}
|
|
|
501 |
|
|
|
502 |
int SelectLoop::Internal::setselevents(NetconP& con, int events)
|
|
|
503 |
{
|
|
|
504 |
#ifdef HAVE_KQUEUE
|
|
|
505 |
struct kevent event;
|
|
|
506 |
if (events & Netcon::NETCONPOLL_READ) {
|
|
|
507 |
EV_SET(&event, con->m_fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
|
|
508 |
if(kevent(kq, &event, 1, 0, 0, 0) < 0) {
|
|
|
509 |
LOGSYSERR("SelectLoop::addselcon", "kevent", "");
|
|
|
510 |
return -1;
|
|
|
511 |
}
|
|
|
512 |
} else {
|
|
|
513 |
EV_SET(&event, con->m_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
|
|
514 |
kevent(kq, &event, 1, 0, 0, 0);
|
|
|
515 |
}
|
|
|
516 |
if (events & Netcon::NETCONPOLL_WRITE) {
|
|
|
517 |
EV_SET(&event, con->m_fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
|
|
|
518 |
if(kevent(kq, &event, 1, 0, 0, 0) < 0) {
|
|
|
519 |
LOGSYSERR("SelectLoop::addselcon", "kevent", "");
|
|
|
520 |
return -1;
|
|
|
521 |
}
|
|
|
522 |
} else {
|
|
|
523 |
EV_SET(&event, con->m_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
|
|
|
524 |
kevent(kq, &event, 1, 0, 0, 0);
|
|
|
525 |
}
|
|
|
526 |
#endif
|
|
|
527 |
return 0;
|
|
|
528 |
}
|
|
|
529 |
|
302 |
// Add a connection to the monitored set.
|
530 |
// Add a connection to the monitored set. This can be used to change
|
|
|
531 |
// the event flags too (won't add duplicates)
|
303 |
int SelectLoop::addselcon(NetconP con, int events)
|
532 |
int SelectLoop::addselcon(NetconP con, int events)
|
304 |
{
|
533 |
{
|
305 |
if (!con) {
|
534 |
if (!con) {
|
306 |
return -1;
|
535 |
return -1;
|
307 |
}
|
536 |
}
|
308 |
LOGDEB1("Netcon::addselcon: fd " << con->m_fd << "\n");
|
537 |
LOGDEB1("Netcon::addselcon: fd " << con->m_fd << "\n");
|
309 |
con->set_nonblock(1);
|
538 |
con->set_nonblock(1);
|
310 |
con->setselevents(events);
|
539 |
con->m_wantedEvents = events;
|
311 |
m_polldata[con->m_fd] = con;
|
540 |
m->polldata[con->m_fd] = con;
|
312 |
con->setloop(this);
|
541 |
con->setloop(this);
|
313 |
return 0;
|
542 |
return m->setselevents(con, events);
|
314 |
}
|
543 |
}
|
315 |
|
544 |
|
316 |
// Remove a connection from the monitored set.
|
545 |
// Remove a connection from the monitored set.
|
317 |
int SelectLoop::remselcon(NetconP con)
|
546 |
int SelectLoop::remselcon(NetconP con)
|
318 |
{
|
547 |
{
|
319 |
if (!con) {
|
548 |
if (!con) {
|
320 |
return -1;
|
549 |
return -1;
|
321 |
}
|
550 |
}
|
322 |
LOGDEB1("Netcon::remselcon: fd " << con->m_fd << "\n");
|
551 |
LOGDEB1("Netcon::remselcon: fd " << con->m_fd << "\n");
|
323 |
map<int, NetconP>::iterator it = m_polldata.find(con->m_fd);
|
552 |
m->setselevents(con, 0);
|
|
|
553 |
auto it = m->polldata.find(con->m_fd);
|
324 |
if (it == m_polldata.end()) {
|
554 |
if (it == m->polldata.end()) {
|
325 |
LOGDEB1("Netcon::remselcon: con not found for fd " <<
|
555 |
LOGDEB1("Netcon::remselcon: con not found for fd " <<
|
326 |
con->m_fd << "\n");
|
556 |
con->m_fd << "\n");
|
327 |
return -1;
|
557 |
return -1;
|
328 |
}
|
558 |
}
|
329 |
con->setloop(0);
|
559 |
con->setloop(0);
|
330 |
m_polldata.erase(it);
|
560 |
m->polldata.erase(it);
|
331 |
return 0;
|
561 |
return 0;
|
332 |
}
|
562 |
}
|
333 |
|
563 |
|
334 |
//////////////////////////////////////////////////////////
|
564 |
//////////////////////////////////////////////////////////
|
335 |
// Base class (Netcon) methods
|
565 |
// Base class (Netcon) methods
|
|
... |
|
... |
392 |
}
|
622 |
}
|
393 |
}
|
623 |
}
|
394 |
return flags;
|
624 |
return flags;
|
395 |
}
|
625 |
}
|
396 |
|
626 |
|
|
|
627 |
int Netcon::setselevents(int events)
|
|
|
628 |
{
|
|
|
629 |
m_wantedEvents = events;
|
|
|
630 |
if (m_loop) {
|
|
|
631 |
m_loop->m->setselevents(m_fd, events);
|
|
|
632 |
}
|
|
|
633 |
return m_wantedEvents;
|
|
|
634 |
}
|
|
|
635 |
|
397 |
/////////////////////////////////////////////////////////////////////
|
636 |
/////////////////////////////////////////////////////////////////////
|
398 |
// Data socket (NetconData) methods
|
637 |
// Data socket (NetconData) methods
|
399 |
|
638 |
|
400 |
NetconData::NetconData(bool cancellable)
|
639 |
NetconData::NetconData(bool cancellable)
|
401 |
: m_buf(0), m_bufbase(0), m_bufbytes(0), m_bufsize(0), m_wkfds{-1,-1}
|
640 |
: m_buf(0), m_bufbase(0), m_bufbytes(0), m_bufsize(0), m_wkfds{-1,-1}
|
|
... |
|
... |
649 |
if (n == 0) {
|
888 |
if (n == 0) {
|
650 |
// EOF
|
889 |
// EOF
|
651 |
return 0;
|
890 |
return 0;
|
652 |
}
|
891 |
}
|
653 |
}
|
892 |
}
|
654 |
clearselevents(NETCONPOLL_WRITE);
|
893 |
m_wantedEvents &= ~NETCONPOLL_WRITE;
|
655 |
return 1;
|
894 |
return 1;
|
656 |
}
|
895 |
}
|
657 |
|
896 |
|
658 |
///////////////////////////////////////////////////////////////////////
|
897 |
///////////////////////////////////////////////////////////////////////
|
659 |
// Methods for a client connection (NetconCli)
|
898 |
// Methods for a client connection (NetconCli)
|