Coverage Report

Created: 2026-09-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/io_wait.h
Line
Count
Source
1
/*
2
 * Copyright (C) 2014-2015 OpenSIPS Solutions
3
 * Copyright (C) 2005 iptelorg GmbH
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20
 *
21
 * History:
22
 * --------
23
 *  2005-06-13  created by andrei
24
 *  2005-06-26  added kqueue (andrei)
25
 *  2005-07-01  added /dev/poll (andrei)
26
 *  2014-08-25  looping functions moved to io_wait_loop.h (bogdan)
27
 */
28
29
/*!
30
 * \file
31
 * \brief tcp io wait common stuff used by tcp_main.c & tcp_read.c
32
 * - \ref TCPiowait
33
 */
34
35
/*! \page TCPiowait TCP io wait common stuff used by tcp_main.c & tcp_read.c
36
 * All the functions are inline because of speed reasons and because they are
37
 * used only from 2 places.
38
 * You also have to define:
39
 *   -  int handle_io(struct fd_map* fm, int idx) (see below)
40
 *     (this could be trivially replaced by a callback pointer entry attached
41
 *      to the io_wait handler if more flexibility rather then performance
42
 *      is needed)
43
 *   -   fd_type - define to some enum of you choice and define also
44
 *                FD_TYPE_DEFINED (if you don't do it fd_type will be defined
45
 *                to int). 0 has a special not set/not init. meaning
46
 *                (a lot of sanity checks and the sigio_rt code are based on
47
 *                 this assumption)
48
 *   -  local_malloc (defaults to pkg_malloc)
49
 *   -  local_free   (defaults to pkg_free)
50
 *
51
 */
52
53
54
#ifndef _io_wait_h
55
#define _io_wait_h
56
57
#include <errno.h>
58
#include <string.h>
59
#ifdef HAVE_SIGIO_RT
60
#define __USE_GNU /* or else F_SETSIG won't be included */
61
#define _GNU_SOURCE /* define this as well */
62
#include <sys/types.h> /* recv */
63
#include <sys/socket.h> /* recv */
64
#include <signal.h> /* sigprocmask, sigwait a.s.o */
65
#endif
66
#ifdef HAVE_EPOLL
67
#include <sys/epoll.h>
68
#endif
69
#ifdef HAVE_KQUEUE
70
#include <sys/types.h> /* needed on freebsd */
71
#include <sys/event.h>
72
#include <sys/time.h>
73
#endif
74
#ifdef HAVE_DEVPOLL
75
#include <sys/devpoll.h>
76
#endif
77
#ifdef HAVE_SELECT
78
/* needed on openbsd for select*/
79
#include <sys/time.h>
80
#include <sys/types.h>
81
#include <unistd.h>
82
/* needed according to POSIX for select*/
83
#include <sys/select.h>
84
#endif
85
#include <sys/poll.h>
86
#include <fcntl.h>
87
88
#include "dprint.h"
89
90
#include "poll_types.h" /* poll_types*/
91
#include "pt.h" /* mypid() */
92
#include "error.h"
93
94
#ifdef __OS_linux
95
#include <features.h>     /* for GLIBC version testing */
96
#endif
97
#ifdef EXTRA_DEBUG
98
#include "lib/dbg/backtrace.h"
99
#endif
100
101
#ifndef FD_TYPE_DEFINED
102
typedef int fd_type;
103
#define FD_TYPE_DEFINED
104
#endif
105
106
/*! \brief maps a fd to some other structure; used in almost all cases
107
 * except epoll and maybe kqueue or /dev/poll */
108
struct fd_map {
109
  int fd;               /* fd no */
110
  fd_type type;         /* "data" type */
111
  void* data;           /* pointer to the corresponding structure */
112
  int flags;            /* so far used to indicate whether we should 
113
                         * read, write or both ; last 4 are reserved for 
114
                         * internal usage */
115
  int app_flags;        /* flags to be used by upper layer apps, not by
116
                         * the reactor */
117
  utime_t timeout;
118
};
119
120
121
#ifdef HAVE_KQUEUE
122
#ifndef KQ_CHANGES_ARRAY_SIZE
123
#define KQ_CHANGES_ARRAY_SIZE 128
124
125
#ifdef __OS_netbsd
126
#define KEV_UDATA_CAST (intptr_t)
127
#else
128
#define KEV_UDATA_CAST
129
#endif
130
131
#endif
132
#endif
133
134
135
0
#define IO_FD_CLOSING 16
136
137
/*! \brief handler structure */
138
struct io_wait_handler{
139
  char *name;
140
  int max_prio;
141
#ifdef HAVE_EPOLL
142
  struct epoll_event* ep_array;
143
  int epfd; /* epoll ctrl fd */
144
#endif
145
#ifdef HAVE_SIGIO_RT
146
  sigset_t sset; /* signal mask for sigio & sigrtmin */
147
  int signo;     /* real time signal used */
148
#endif
149
#ifdef HAVE_KQUEUE
150
  struct kevent* kq_array;   /* used for the eventlist*/
151
  struct kevent* kq_changes; /* used for the changelist */
152
  size_t kq_nchanges;
153
  size_t kq_changes_size; /* size of the changes array */
154
  int kq_fd;
155
#endif
156
#ifdef HAVE_DEVPOLL
157
  int dpoll_fd;
158
  struct pollfd* dp_changes;
159
#endif
160
#ifdef HAVE_SELECT
161
  fd_set master_set;
162
  int max_fd_select; /* maximum select used fd */
163
#endif
164
  /* common stuff for POLL, SIGIO_RT and SELECT
165
   * since poll support is always compiled => this will always be compiled */
166
  int *prio_idx; /* size of max_prio - idxs in fd_array where prio changes*/
167
  struct fd_map* fd_hash;
168
  struct pollfd* fd_array;
169
  int fd_no; /*  current index used in fd_array */
170
  int max_fd_no; /* maximum fd no, is also the size of fd_array,
171
                   fd_hash  and ep_array*/
172
  enum poll_types poll_method;
173
  int flags;
174
};
175
176
typedef struct io_wait_handler io_wait_h;
177
178
179
/*! \brief get the corresponding fd_map structure pointer */
180
0
#define get_fd_map(h, fd)   (&(h)->fd_hash[(fd)])
181
182
/*! \brief remove a fd_map structure from the hash;
183
 * the pointer must be returned by get_fd_map or hash_fd_map
184
 */
185
#define unhash_fd_map(pfm,c_flags,sock_flags,erase) \
186
0
  do{ \
187
0
    if ((c_flags & IO_FD_CLOSING) || (pfm->flags&IO_WATCH_PRV_FILTER)==sock_flags) { \
188
0
      (pfm)->type=0 /*F_NONE */; \
189
0
      (pfm)->fd=-1; \
190
0
      (pfm)->flags = 0; \
191
0
      (pfm)->data = NULL; \
192
0
      erase = 1; \
193
0
    } else { \
194
0
      (pfm)->flags &= ~sock_flags; \
195
0
      erase = 0; \
196
0
    } \
197
0
  }while(0)
198
199
#define unhash_fd_map2(pfm,c_flags,sock_flags,erase)  \
200
0
  do{ \
201
0
    if ((c_flags & IO_FD_CLOSING) || (pfm->flags&IO_WATCH_PRV_FILTER)==sock_flags) { \
202
0
      rla_log("erase case detected with sflags=%x\n",sock_flags); \
203
0
      (pfm)->type=0 /*F_NONE */; \
204
0
      (pfm)->fd=-1; \
205
0
      (pfm)->flags = 0; \
206
0
      (pfm)->data = NULL; \
207
0
      erase = 1; \
208
0
    } else { \
209
0
      rla_log("not erasing flags=%x, flags=%x\n",(pfm)->flags,sock_flags); \
210
0
      (pfm)->flags &= ~sock_flags; \
211
0
      erase = 0; \
212
0
    } \
213
0
  }while(0)
214
215
216
/*! \brief add a fd_map structure to the fd hash */
217
static inline struct fd_map* hash_fd_map( io_wait_h* h,
218
            int fd,
219
            fd_type type,
220
            void* data,
221
            int flags,
222
            utime_t timeout,
223
            int *already)
224
0
{
225
0
  if (h->fd_hash[fd].fd <= 0) {
226
0
    *already = 0;
227
0
  } else {
228
0
    *already = 1;
229
0
  }
230
231
0
  h->fd_hash[fd].fd=fd;
232
0
  h->fd_hash[fd].type=type;
233
0
  h->fd_hash[fd].data=data;
234
235
0
  h->fd_hash[fd].flags|=flags;
236
237
0
  h->fd_hash[fd].timeout = timeout;
238
239
0
  return &h->fd_hash[fd];
240
0
}
Unexecuted instantiation: net_tcp_proc.c:hash_fd_map
Unexecuted instantiation: net_tcp.c:hash_fd_map
Unexecuted instantiation: tcp_common.c:hash_fd_map
Unexecuted instantiation: net_udp.c:hash_fd_map
Unexecuted instantiation: async.c:hash_fd_map
Unexecuted instantiation: timer.c:hash_fd_map
Unexecuted instantiation: reactor.c:hash_fd_map
Unexecuted instantiation: io_wait.c:hash_fd_map
Unexecuted instantiation: cfg_reload.c:hash_fd_map
Unexecuted instantiation: cfg.tab.c:hash_fd_map
241
242
243
#ifdef HAVE_KQUEUE
244
/*
245
 * kqueue specific function: register a change
246
 * (adds a change to the kevent change array, and if full flushes it first)
247
 * returns: -1 on error, 0 on success
248
 */
249
static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag,
250
                void* data)
251
{
252
  int n;
253
  struct timespec tspec;
254
255
  if (h->kq_nchanges>=h->kq_changes_size){
256
    /* changes array full ! */
257
    LM_WARN("[%s] kqueue changes array full trying to flush...\n",
258
      h->name);
259
    tspec.tv_sec=0;
260
    tspec.tv_nsec=0;
261
again:
262
    n=kevent(h->kq_fd, h->kq_changes, h->kq_nchanges, 0, 0, &tspec);
263
    if (n==-1){
264
      if (errno==EINTR) goto again;
265
      LM_ERR("[%s] kevent flush changes failed: %s [%d]\n",
266
        h->name, strerror(errno), errno);
267
      return -1;
268
    }
269
    h->kq_nchanges=0; /* changes array is empty */
270
  }
271
  EV_SET(&h->kq_changes[h->kq_nchanges], fd, filter, flag, 0, 0,
272
      KEV_UDATA_CAST data);
273
  h->kq_nchanges++;
274
  return 0;
275
}
276
#endif
277
278
279
0
#define IO_WATCH_READ            (1<<0)
280
0
#define IO_WATCH_WRITE           (1<<1)
281
#define IO_WATCH_ERROR           (1<<2)
282
0
#define IO_WATCH_TIMEOUT         (1<<3)
283
/* 24 starting are reserved, do not attempt to use */
284
0
#define IO_WATCH_PRV_FILTER      ((1<<24)-1)
285
0
#define IO_WATCH_PRV_CHECKED     (1<<29)
286
0
#define IO_WATCH_PRV_TRIG_READ   (1<<30)
287
0
#define IO_WATCH_PRV_TRIG_WRITE  (1<<31)
288
289
#define fd_array_print \
290
  do { \
291
    int k;\
292
    LM_DBG("[%s] size=%d, fd array is",h->name,h->fd_no);\
293
    for(k=0;k<h->fd_no;k++) LM_GEN1(L_DBG," %d flags = %d",h->fd_array[k].fd,h->fd_hash[h->fd_array[k].fd].flags);\
294
    LM_GEN1(L_DBG,"\n"); \
295
    LM_DBG("[%s] size=%d, prio array is",h->name,h->max_prio);\
296
    for(k=0;k<h->max_prio;k++) LM_GEN1(L_DBG," %d",h->prio_idx[k]);\
297
    LM_GEN1(L_DBG,"\n"); \
298
  }while(0)
299
300
301
#define check_io_data() \
302
0
  do { \
303
0
    struct fd_map* _e;\
304
0
    int _t,k;\
305
0
    check_error = 0;\
306
0
    if (!reactor_dbg_fd_check) break;\
307
0
    /* iterate the fd_array and check if fd_hash is properly set for each */ \
308
0
    for(k=0;k<h->fd_no;k++) {\
309
0
      _e = get_fd_map(h, h->fd_array[k].fd); \
310
0
      if (_e->type==0 || _e->fd<=0 || \
311
0
      (_e->flags&(IO_WATCH_READ|IO_WATCH_WRITE))==0 ) {\
312
0
        LM_BUG("fd_array idx %d (fd=%d) points to bogus map "\
313
0
          "(fd=%d,type=%d,flags=%x,data=%p)\n",k,h->fd_array[k].fd,\
314
0
          _e->fd, _e->type, _e->flags, _e->data);\
315
0
          check_error = 1;\
316
0
      }\
317
0
      _e->flags |= IO_WATCH_PRV_CHECKED;\
318
0
    }\
319
0
    /* iterate the fd_map and see if all records are checked */ \
320
0
    _t = 0; \
321
0
    for(k=0;k<h->max_fd_no;k++) {\
322
0
      _e = get_fd_map(h, k); \
323
0
      if (_e->type==0) { \
324
0
        /* fd not in used, everything should be on zero */ \
325
0
        if (_e->fd>0 || _e->data!=NULL || _e->flags!=0 ) {\
326
0
          LM_BUG("unused fd_map fd=%d has bogus data "\
327
0
          "(fd=%d,flags=%x,data=%p)\n",k,\
328
0
          _e->fd, _e->flags, _e->data);\
329
0
          check_error = 1;\
330
0
        }\
331
0
      } else {\
332
0
        /* fd in used, check if in checked */ \
333
0
        if (_e->fd<=0 || \
334
0
        (_e->flags&(IO_WATCH_READ|IO_WATCH_WRITE))==0 ) {\
335
0
        LM_BUG("used fd map fd=%d has bogus data "\
336
0
          "(fd=%d,type=%d,flags=%x,data=%p)\n",k,\
337
0
          _e->fd, _e->type, _e->flags, _e->data);\
338
0
          check_error = 1;\
339
0
        }\
340
0
        /* the map is valid */ \
341
0
        if ((_e->flags&IO_WATCH_PRV_CHECKED)==0) {\
342
0
          LM_BUG("used fd map fd=%d is not present in fd_array "\
343
0
            "(fd=%d,type=%d,flags=%x,data=%p)\n",k,\
344
0
            _e->fd, _e->type, _e->flags, _e->data);\
345
0
            check_error = 1;\
346
0
        }\
347
0
        _e->flags &= ~IO_WATCH_PRV_CHECKED;\
348
0
        _t++;\
349
0
      }\
350
0
    }\
351
0
    if (_t!=h->fd_no) { \
352
0
      LM_BUG("fd_map versus fd_array size mismatch: %d versus %d\n",\
353
0
        _t, h->fd_no);\
354
0
      check_error = 1;\
355
0
    }\
356
0
  } while(0)
357
358
359
/*! \brief generic io_watch_add function
360
 * \return 0 on success, -1 on error
361
 *
362
 * this version should be faster than pointers to poll_method specific
363
 * functions (it avoids functions calls, the overhead being only an extra
364
 *  switch())
365
*/
366
inline static int io_watch_add( io_wait_h* h, // lgtm [cpp/use-of-goto]
367
                int fd,
368
                fd_type type,
369
                void* data,
370
                int prio,
371
                utime_t timeout,
372
                int flags)
373
0
{
374
375
  /* helper macros */
376
0
#define fd_array_setup \
377
0
  do{ \
378
0
    n = h->prio_idx[prio]; \
379
0
    if (n<h->fd_no)\
380
0
      memmove( &h->fd_array[n+1], &h->fd_array[n],\
381
0
        (h->fd_no-n)*sizeof(*(h->fd_array)) ); \
382
0
    h->fd_array[n].fd=fd; \
383
0
    h->fd_array[n].events=0; \
384
0
    if (flags & IO_WATCH_READ) \
385
0
      h->fd_array[n].events|=POLLIN; /* useless for select */ \
386
0
    if (flags & IO_WATCH_WRITE) \
387
0
      h->fd_array[n].events|=POLLOUT; /* useless for select */ \
388
0
    h->fd_array[n].revents=0;     /* useless for select */ \
389
0
    for( n=prio ; n<h->max_prio ; n++) \
390
0
      h->prio_idx[n]++; \
391
0
    h->fd_no++; \
392
0
  }while(0)
393
394
0
#define set_fd_flags(f) \
395
0
  do{ \
396
0
      ctl_flags=fcntl(fd, F_GETFL); \
397
0
      if (ctl_flags==-1){ \
398
0
        LM_ERR("[%s] fcntl: GETFL failed:" \
399
0
          " %s [%d]\n", h->name, strerror(errno), errno); \
400
0
        goto error; \
401
0
      } \
402
0
      if (fcntl(fd, F_SETFL, ctl_flags|(f))==-1){ \
403
0
        LM_ERR("[%s] fcntl: SETFL" \
404
0
          " failed: %s [%d]\n", h->name, strerror(errno), errno);\
405
0
        goto error; \
406
0
      } \
407
0
  }while(0)
408
409
410
0
  struct fd_map* e;
411
0
  int already=-1;
412
0
#ifdef HAVE_EPOLL
413
0
  struct epoll_event ep_event;
414
0
#endif
415
#ifdef HAVE_DEVPOLL
416
  struct pollfd pfd;
417
#endif
418
0
  int ctl_flags;
419
0
  int n;  //FIXME
420
0
  int check_error;
421
#if 0 //defined(HAVE_SIGIO_RT) || defined (HAVE_EPOLL) FIXME
422
  int n;
423
  int idx;
424
  int check_io;
425
  struct pollfd pf;
426
427
  check_io=0; /* set to 1 if we need to check for pre-existing queued
428
           io/data on the fd */
429
  idx=-1;
430
#endif
431
0
  e=0;
432
433
0
  if (fd==-1){
434
0
    LM_CRIT("fd is -1!\n");
435
0
    goto error0;
436
0
  }
437
  /* check if not too big */
438
0
  if (h->fd_no >= h->max_fd_no || fd >= h->max_fd_no) {
439
0
    LM_CRIT("[%s] maximum fd number exceeded: %d, %d/%d\n",
440
0
      h->name, fd, h->fd_no, h->max_fd_no);
441
0
    goto error0;
442
0
  }
443
0
  if (prio > h->max_prio) {
444
0
    LM_BUG("[%s] priority %d requested (max is %d)\n",
445
0
      h->name, prio, h->max_prio);
446
0
    goto error0;
447
0
  }
448
0
#if defined (HAVE_EPOLL)
449
0
  LM_DBG("[%s] io_watch_add op (%d on %d) (%p, %d, %d, %p,%d), fd_no=%d/%d\n",
450
0
      h->name,fd,h->epfd, h,fd,type,data,flags,h->fd_no,h->max_fd_no);
451
#else
452
  LM_DBG("[%s] io_watch_add op (%d) (%p, %d, %d, %p,%d), fd_no=%d/%d\n",
453
      h->name,fd, h,fd,type,data,flags,h->fd_no,h->max_fd_no);
454
#endif
455
  //fd_array_print;
456
  /*  hash sanity check */
457
0
  e=get_fd_map(h, fd);
458
459
0
  check_io_data();
460
0
  if (check_error) {
461
0
    LM_CRIT("[%s] check failed before fd add "
462
0
      "(fd=%d,type=%d,data=%p,flags=%x) already=%d\n",h->name,
463
0
      fd, type, data, flags, already);
464
0
  }
465
466
0
  if (e->flags & flags){
467
0
    if (e->data != data) {
468
0
      LM_BUG("[%s] BUG trying to overwrite entry %d"
469
0
          " in the hash(%d, %d, %p,%d) with (%d, %d, %p,%d)\n",
470
0
          h->name,fd, e->fd, e->type, e->data,e->flags, fd, type, data,flags);
471
0
      goto error0;
472
0
    }
473
0
    LM_DBG("[%s] Socket %d is already being listened on for flags %d\n",
474
0
         h->name,fd,flags);
475
0
    return 0;
476
0
  }
477
478
  /* convert timeout from seconds to miliseconds*/
479
0
  if (timeout)
480
0
    timeout = timeout*1000000 + get_uticks();
481
482
0
  if ((e=hash_fd_map(h, fd, type, data,flags, timeout, &already))==0){
483
0
    LM_ERR("[%s] failed to hash the fd %d\n",h->name, fd);
484
0
    goto error0;
485
0
  }
486
0
  switch(h->poll_method){ /* faster then pointer to functions */
487
0
    case POLL_POLL:
488
0
      set_fd_flags(O_NONBLOCK);
489
0
      break;
490
0
#ifdef HAVE_SELECT
491
0
    case POLL_SELECT:
492
0
      FD_SET(fd, &h->master_set);
493
0
      if (h->max_fd_select<fd) h->max_fd_select=fd;
494
0
      break;
495
0
#endif
496
0
#ifdef HAVE_SIGIO_RT
497
0
    case POLL_SIGIO_RT:
498
      /* re-set O_ASYNC might be needed, if not done from
499
       * io_watch_del (or if somebody wants to add a fd which has
500
       * already O_ASYNC/F_SETSIG set on a dupplicate)
501
       */
502
      /* set async & signal */
503
0
      if (fcntl(fd, F_SETOWN, my_pid())==-1){
504
0
        LM_ERR("[%s] fcntl: SETOWN"
505
0
        " failed: %s [%d]\n",h->name, strerror(errno), errno);
506
0
        goto error;
507
0
      }
508
0
      if (fcntl(fd, F_SETSIG, h->signo)==-1){
509
0
        LM_ERR("[%s] fcntl: SETSIG"
510
0
          " failed: %s [%d]\n",h->name, strerror(errno), errno);
511
0
        goto error;
512
0
      }
513
      /* set both non-blocking and async */
514
0
      set_fd_flags(O_ASYNC| O_NONBLOCK);
515
#ifdef EXTRA_DEBUG
516
      LM_DBG("[%s] sigio_rt on f %d, signal %d to pid %d\n",
517
          h->name,fd,  h->signo, my_pid());
518
#endif
519
      /* empty socket receive buffer, if buffer is already full
520
       * no more space to put packets
521
       * => no more signals are ever generated
522
       * also when moving fds, the freshly moved fd might have
523
       *  already some bytes queued, we want to get them now
524
       *  and not later -- andrei */
525
      //idx=h->fd_no;  FIXME
526
      //check_io=1;
527
0
      break;
528
0
#endif
529
0
#ifdef HAVE_EPOLL
530
0
    case POLL_EPOLL:
531
0
      ep_event.data.ptr=e;
532
0
      ep_event.events=0;
533
0
      if (e->flags & IO_WATCH_READ)
534
0
        ep_event.events|=EPOLLIN;
535
0
      if (e->flags & IO_WATCH_WRITE)
536
0
        ep_event.events|=EPOLLOUT;
537
0
      if (!already) {
538
0
again1:
539
#if 0
540
/* This is currently broken, because when using EPOLLEXCLUSIVE, the OS will
541
 * send sequential events to the same process - thus our pseudo-dispatcher
542
 * will no longer work, since events on a pipe will be queued by a single
543
 * process. - razvanc
544
 */
545
#if (defined __OS_linux) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 24)
546
        if (e->flags & IO_WATCH_READ)
547
          ep_event.events|=EPOLLEXCLUSIVE;
548
#endif
549
#endif
550
0
        n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event);
551
0
        if (n==-1){
552
0
          if (errno==EAGAIN) goto again1;
553
0
          LM_ERR("[%s] epoll_ctl ADD failed: %s [%d]\n",
554
0
            h->name,strerror(errno), errno);
555
0
          goto error;
556
0
        }
557
0
      } else {
558
0
again11:
559
0
        n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event);
560
0
        if (n==-1){
561
0
          if (errno==EAGAIN) goto again11;
562
0
          LM_ERR("[%s] epoll_ctl MOD failed: %s [%d]\n",
563
0
            h->name,strerror(errno), errno);
564
0
          goto error;
565
0
        }
566
0
      }
567
0
      break;
568
0
#endif
569
#ifdef HAVE_KQUEUE
570
    case POLL_KQUEUE:
571
      if (kq_ev_change(h, fd, EVFILT_READ, EV_ADD, e)==-1)
572
        goto error;
573
      break;
574
#endif
575
#ifdef HAVE_DEVPOLL
576
    case POLL_DEVPOLL:
577
      pfd.fd=fd;
578
      pfd.events=POLLIN;
579
      pfd.revents=0;
580
again_devpoll:
581
      if (write(h->dpoll_fd, &pfd, sizeof(pfd))==-1){
582
        if (errno==EAGAIN) goto again_devpoll;
583
        LM_ERR("[%s] /dev/poll write failed:"
584
          "%s [%d]\n",h->name, strerror(errno), errno);
585
        goto error;
586
      }
587
      break;
588
#endif
589
590
0
    default:
591
0
      LM_CRIT("[%s] no support for poll method "
592
0
        " %s (%d)\n",h->name, poll_method_str[h->poll_method],
593
0
        h->poll_method);
594
0
      goto error;
595
0
  }
596
597
0
  if (!already) {
598
0
    fd_array_setup;
599
0
  }
600
601
#if 0 //defined(HAVE_SIGIO_RT) || defined (HAVE_EPOLL) FIXME !!!
602
  if (check_io){
603
    /* handle possible pre-existing events */
604
    pf.fd=fd;
605
    pf.events=POLLIN;
606
check_io_again:
607
    while( ((n=poll(&pf, 1, 0))>0) && (handle_io(e, idx,IO_WATCH_READ)>0));
608
    if (n==-1){
609
      if (errno==EINTR) goto check_io_again;
610
      LM_ERR("check_io poll: %s [%d]\n",
611
            strerror(errno), errno);
612
    }
613
  }
614
#endif
615
  //fd_array_print;
616
0
  check_io_data();
617
0
  if (check_error) {
618
0
    LM_CRIT("[%s] check failed after successful fd add "
619
0
      "(fd=%d,type=%d,data=%p,flags=%x) already=%d\n",h->name,
620
0
      fd, type, data, flags, already);
621
0
  }
622
0
  return 0;
623
0
error:
624
0
  if (e) unhash_fd_map(e,0,flags,already);
625
0
error0:
626
0
  check_io_data();
627
0
  if (check_error) {
628
0
    LM_CRIT("[%s] check failed after failed fd add "
629
0
      "(fd=%d,type=%d,data=%p,flags=%x) already=%d\n",h->name,
630
0
      fd, type, data, flags, already);
631
0
  }
632
0
  return -1;
633
0
#undef fd_array_setup
634
0
#undef set_fd_flags
635
0
}
Unexecuted instantiation: net_tcp_proc.c:io_watch_add
Unexecuted instantiation: net_tcp.c:io_watch_add
Unexecuted instantiation: tcp_common.c:io_watch_add
Unexecuted instantiation: net_udp.c:io_watch_add
Unexecuted instantiation: async.c:io_watch_add
Unexecuted instantiation: timer.c:io_watch_add
Unexecuted instantiation: reactor.c:io_watch_add
Unexecuted instantiation: io_wait.c:io_watch_add
Unexecuted instantiation: cfg_reload.c:io_watch_add
Unexecuted instantiation: cfg.tab.c:io_watch_add
636
637
638
639
/*!
640
 * \brief
641
 * \param h handler
642
 * \param fd file descriptor
643
 * \param idx index in the fd_array if known, -1 if not
644
 *                    (if index==-1 fd_array will be searched for the
645
 *                     corresponding fd* entry -- slower but unavoidable in
646
 *                     some cases). index is not used (no fd_array) for epoll,
647
 *                     /dev/poll and kqueue
648
 * \param flags optimization flags, e.g. IO_FD_CLOSING, the fd was or will
649
 *                    shortly be closed, in some cases we can avoid extra
650
 *                    remove operations (e.g.: epoll, kqueue, sigio)
651
 * \return 0 if ok, -1 on error
652
 */
653
inline static int io_watch_del(io_wait_h* h, int fd, int idx,
654
          int flags,int sock_flags)
655
0
{
656
0
#define fix_fd_array \
657
0
  do{\
658
0
      if (idx==-1){ \
659
        /* fix idx if -1 and needed */ \
660
0
        for (idx=0; (idx<h->fd_no) && \
661
0
              (h->fd_array[idx].fd!=fd); idx++); \
662
0
      } \
663
0
      rla_log("fixing: final idx=%d out of %d, erase=%d\n",idx,idx<h->fd_no,erase); \
664
0
      if (idx<h->fd_no){ \
665
0
        if (erase) { \
666
0
          memmove(&h->fd_array[idx], &h->fd_array[idx+1], \
667
0
            (h->fd_no-(idx+1))*sizeof(*(h->fd_array))); \
668
0
          for( i=0 ; i<h->max_prio && h->prio_idx[i]<=idx ; i++ ); \
669
0
          for( ; i<h->max_prio ; i++ ) h->prio_idx[i]-- ; \
670
0
          h->fd_no--; \
671
0
        } else { \
672
0
          h->fd_array[idx].events = 0; \
673
0
          if (e->flags & IO_WATCH_READ) \
674
0
            h->fd_array[idx].events|=POLLIN; /* useless for select */ \
675
0
          if (flags & IO_WATCH_WRITE) \
676
0
            h->fd_array[idx].events|=POLLOUT; /* useless for select */ \
677
0
          h->fd_array[idx].revents = 0; \
678
0
        } \
679
0
      } \
680
0
  }while(0)
681
682
0
  struct fd_map* e;
683
0
#ifdef HAVE_EPOLL
684
0
  int n;
685
0
  struct epoll_event ep_event;
686
0
#endif
687
#ifdef HAVE_DEVPOLL
688
  struct pollfd pfd;
689
#endif
690
0
#ifdef HAVE_SIGIO_RT
691
0
  int fd_flags;
692
0
#endif
693
0
  int erase = 0;
694
0
  int check_error;
695
0
  int i;
696
697
0
  #define x_RL_NO  10
698
0
  #define x_RL_LEN 200
699
0
  static char rla[x_RL_NO][x_RL_LEN];
700
0
  int rla_idx=0;
701
0
  #define rla_log( _fmt, args...) \
702
0
    snprintf( rla[rla_idx++], x_RL_LEN, _fmt, ## args)
703
0
  #define rla_dump() \
704
0
    do { \
705
0
      int w; \
706
0
      for(w=0;w<rla_idx;w++) \
707
0
        LM_CRIT("[%d]-> [%s]\n",w,rla[w]); \
708
0
    } while(0)
709
710
0
  if ((fd<0) || (fd>=h->max_fd_no)){
711
0
    LM_CRIT("[%s] invalid fd %d, not in [0, %d)\n", h->name, fd, h->fd_no);
712
0
    goto error0;
713
0
  }
714
0
  LM_DBG("[%s] io_watch_del op on index %d %d (%p, %d, %d, 0x%x,0x%x) "
715
0
    "fd_no=%d called\n", h->name,idx,fd, h, fd, idx, flags,
716
0
    sock_flags,h->fd_no);
717
0
  rla_log("[%s] io_watch_del op on index %d %d (%p, %d, %d, 0x%x,0x%x) "
718
0
    "fd_no=%d called\n", h->name,idx,fd, h, fd, idx, flags,
719
0
    sock_flags,h->fd_no);
720
  //fd_array_print;
721
722
0
  e=get_fd_map(h, fd);
723
  /* more sanity checks */
724
0
  if (e==0){
725
0
    LM_CRIT("[%s] no corresponding hash entry for %d\n",h->name, fd);
726
0
    goto error0;
727
0
  }
728
0
  if (e->type==0 /*F_NONE*/){
729
0
    LM_ERR("[%s] trying to delete already erased"
730
0
        " entry %d in the hash(%d, %d, %p) )\n",
731
0
        h->name,fd, e->fd, e->type, e->data);
732
0
    goto error0;
733
0
  }
734
735
0
  if (idx != -1) {
736
0
    if (!(idx>=0 && idx<h->fd_no)) {
737
0
      LM_CRIT("[%s] FD index check failed, idx=%d, max=%d"
738
0
        " operating on %d\n",h->name, idx, h->fd_no, fd );
739
#ifdef EXTRA_DEBUG
740
      log_backtrace();
741
#endif
742
0
      rla_dump();
743
0
      idx = -1;
744
0
    } else if (h->fd_array[idx].fd!=fd) {
745
0
      LM_CRIT("[%s] FD consistency check failed, idx=%d points to fd=%d,"
746
0
        " but operating on %d\n",h->name, idx, h->fd_array[idx].fd, fd );
747
#ifdef EXTRA_DEBUG
748
      log_backtrace();
749
#endif
750
0
      rla_dump();
751
0
      idx = -1;
752
0
    }
753
0
  }
754
755
0
  if ((e->flags & sock_flags) == 0) {
756
0
    LM_ERR("BUG - [%s] trying to del fd %d with flags %d %d\n",
757
0
      h->name, fd, e->flags,sock_flags);
758
0
    goto error0;
759
0
  }
760
761
0
  unhash_fd_map2(e,flags,sock_flags,erase);
762
763
0
  switch(h->poll_method){
764
0
    case POLL_POLL:
765
0
      break;
766
0
#ifdef HAVE_SELECT
767
0
    case POLL_SELECT:
768
0
      FD_CLR(fd, &h->master_set);
769
0
      if (h->max_fd_select && (h->max_fd_select==fd))
770
        /* we don't know the prev. max, so we just decrement it */
771
0
        h->max_fd_select--;
772
0
      break;
773
0
#endif
774
0
#ifdef HAVE_SIGIO_RT
775
0
    case POLL_SIGIO_RT:
776
      /* the O_ASYNC flag must be reset all the time, the fd
777
       *  can be changed only if  O_ASYNC is reset (if not and
778
       *  the fd is a duplicate, you will get signals from the dup. fd
779
       *  and not from the original, even if the dup. fd was closed
780
       *  and the signals re-set on the original) -- andrei
781
       */
782
      /*if (!(flags & IO_FD_CLOSING)){*/
783
        /* reset ASYNC */
784
0
        fd_flags=fcntl(fd, F_GETFL);
785
0
        if (fd_flags==-1){
786
0
          LM_ERR("[%s] fcntl: GETFL failed:"
787
0
            " %s [%d]\n",h->name, strerror(errno), errno);
788
0
          goto error;
789
0
        }
790
0
        if (fcntl(fd, F_SETFL, fd_flags&(~O_ASYNC))==-1){
791
0
          LM_ERR("[%s] fcntl: SETFL"
792
0
            " failed: %s [%d]\n",h->name, strerror(errno), errno);
793
0
          goto error;
794
0
        }
795
0
      break;
796
0
#endif
797
0
#ifdef HAVE_EPOLL
798
0
    case POLL_EPOLL:
799
      /* epoll doesn't seem to automatically remove sockets,
800
       * if the socket is a dupplicate/moved and the original
801
       * is still open. The fd is removed from the epoll set
802
       * only when the original (and all the  copies?) is/are
803
       * closed. This is probably a bug in epoll. --andrei */
804
#ifdef EPOLL_NO_CLOSE_BUG
805
      if (!(flags & IO_FD_CLOSING)){
806
#endif
807
0
        if (erase) {
808
0
          n=epoll_ctl(h->epfd, EPOLL_CTL_DEL, fd, &ep_event);
809
          /*
810
           * in some cases (fds managed by external libraries),
811
           * the fd may have already been closed
812
           */
813
0
          if (n==-1 && errno != EBADF && errno != ENOENT) {
814
0
            LM_ERR("[%s] removing fd from epoll (%d from %d) "
815
0
              "list failed: %s [%d]\n",h->name, fd, h->epfd,
816
0
              strerror(errno), errno);
817
0
            goto error;
818
0
          }
819
0
        } else {
820
0
          ep_event.data.ptr=e;
821
0
          ep_event.events=0;
822
0
          if (e->flags & IO_WATCH_READ)
823
0
            ep_event.events|=EPOLLIN;
824
0
          if (e->flags & IO_WATCH_WRITE)
825
0
            ep_event.events|=EPOLLOUT;
826
0
          n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event);
827
0
          if (n==-1){
828
0
            LM_ERR("[%s] epoll_ctl failed: %s [%d]\n",
829
0
              h->name,strerror(errno), errno);
830
0
            goto error;
831
0
          }
832
0
        }
833
#ifdef EPOLL_NO_CLOSE_BUG
834
      }
835
#endif
836
0
      break;
837
0
#endif
838
#ifdef HAVE_KQUEUE
839
    case POLL_KQUEUE:
840
      if (!(flags & IO_FD_CLOSING)){
841
        if (kq_ev_change(h, fd, EVFILT_READ, EV_DELETE, 0)==-1)
842
          goto error;
843
      }
844
      break;
845
#endif
846
#ifdef HAVE_DEVPOLL
847
    case POLL_DEVPOLL:
848
        /* for /dev/poll the closed fds _must_ be removed
849
           (they are not removed automatically on close()) */
850
        pfd.fd=fd;
851
        pfd.events=POLLREMOVE;
852
        pfd.revents=0;
853
again_devpoll:
854
        if (write(h->dpoll_fd, &pfd, sizeof(pfd))==-1){
855
          if (errno==EINTR) goto again_devpoll;
856
          LM_ERR("[%s] removing fd from /dev/poll failed: "
857
            "%s [%d]\n",h->name, strerror(errno), errno);
858
          goto error;
859
        }
860
        break;
861
#endif
862
0
    default:
863
0
      LM_CRIT("[%s] no support for poll method %s (%d)\n",
864
0
        h->name,poll_method_str[h->poll_method], h->poll_method);
865
0
      goto error;
866
0
  }
867
0
  rla_log("fixing fd array, idx=%d\n",idx); \
868
0
869
0
  fix_fd_array;
870
  //fd_array_print;
871
872
0
  check_io_data();
873
0
  if (check_error) {
874
0
    LM_CRIT("[%s] check failed after successful fd del "
875
0
      "(fd=%d,flags=%d, sflags=%d) over map "
876
0
      "(fd=%d,type=%d,data=%p,flags=%d) erase=%d\n",h->name,
877
0
      fd, flags, sock_flags,
878
0
      e->fd, e->type, e->data, e->flags,
879
0
      erase);
880
0
    rla_dump();
881
0
  }
882
883
0
  return 0;
884
0
error:
885
  /*
886
   * although the DEL operation failed, both
887
   * "fd_hash" and "fd_array" must remain consistent
888
   */
889
0
  fix_fd_array;
890
891
0
  check_io_data();
892
0
  if (check_error) {
893
0
    LM_CRIT("[%s] check failed after failed fd del "
894
0
      "(fd=%d,flags=%d, sflags=%d) over map "
895
0
      "(fd=%d,type=%d,data=%p,flags=%d) erase=%d\n",h->name,
896
0
      fd, flags, sock_flags,
897
0
      e->fd, e->type, e->data, e->flags,
898
0
      erase);
899
0
    rla_dump();
900
0
  }
901
0
error0:
902
903
0
  return -1;
904
0
#undef fix_fd_array
905
0
}
Unexecuted instantiation: net_tcp_proc.c:io_watch_del
Unexecuted instantiation: net_tcp.c:io_watch_del
Unexecuted instantiation: tcp_common.c:io_watch_del
Unexecuted instantiation: net_udp.c:io_watch_del
Unexecuted instantiation: async.c:io_watch_del
Unexecuted instantiation: timer.c:io_watch_del
Unexecuted instantiation: reactor.c:io_watch_del
Unexecuted instantiation: io_wait.c:io_watch_del
Unexecuted instantiation: cfg_reload.c:io_watch_del
Unexecuted instantiation: cfg.tab.c:io_watch_del
906
907
908
/* init */
909
910
911
/*! \brief initializes the static vars/arrays
912
 * \param h pointer to the io_wait_h that will be initialized
913
 * \param max_fd maximum allowed fd number
914
 * \param poll_method poll method (0 for automatic best fit)
915
 */
916
int init_io_wait(io_wait_h* h, char *name, int max_fd,
917
                enum poll_types poll_method, int max_prio);
918
919
/*! \brief destroys everything init_io_wait allocated */
920
void destroy_io_wait(io_wait_h* h);
921
922
int io_set_app_flag( io_wait_h *h , int type, int app_flag);
923
924
int io_check_app_flag( io_wait_h *h , int app_flag);
925
926
927
#endif