Switch to unified view

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)