pkg/kamailio/fedora/16: Updated rel in .spec to dev2
[sip-router] / io_wait.c
1 /* 
2  * $Id$
3  * 
4  * Copyright (C) 2005 iptelorg GmbH
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /* 
19  * tcp io wait common stuff used by tcp_main.c & tcp_read.c
20  * (see io_wait.h)
21  */
22 /* 
23  * History:
24  * --------
25  *  2005-06-15  created by andrei
26  *  2005-06-26  added kqueue (andrei)
27  *  2005-07-04  added /dev/poll (andrei)
28  */
29
30 /*!
31  * \file
32  * \brief SIP-router core :: 
33  * \ingroup core
34  * Module: \ref core
35  */
36
37
38
39 #ifndef NO_IO_WAIT
40
41 #ifdef HAVE_EPOLL
42 #include <unistd.h> /* close() */
43 #endif
44 #ifdef HAVE_DEVPOLL
45 #include <sys/types.h> /* open */
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <unistd.h> /* close, ioctl */
49 #endif
50
51 #include <stdlib.h> /* strtol() */
52 #include "io_wait.h"
53 #include "ut.h" /* get_sys_ver() */
54
55
56 #include "mem/mem.h"
57
58 #ifndef local_malloc
59 #define local_malloc pkg_malloc
60 #endif
61 #ifndef local_free
62 #define local_free pkg_free
63 #endif
64
65 char* poll_support="poll"
66 #ifdef HAVE_EPOLL
67 ", epoll_lt, epoll_et"
68 #endif
69 #ifdef HAVE_SIGIO_RT
70 ", sigio_rt"
71 #endif
72 #ifdef HAVE_SELECT
73 ", select"
74 #endif
75 #ifdef HAVE_KQUEUE
76 ", kqueue"
77 #endif
78 #ifdef HAVE_DEVPOLL
79 ", /dev/poll"
80 #endif
81 ;
82
83
84 char* poll_method_str[POLL_END]={ "none", "poll", "epoll_lt", "epoll_et", 
85                                                                   "sigio_rt", "select", "kqueue",  "/dev/poll"
86                                                                 };
87
88 int _os_ver=0; /* os version number */
89
90 #ifdef HAVE_SIGIO_RT
91 static int _sigio_init=0;
92 static int _sigio_crt_rtsig;
93 static sigset_t _sigio_rtsig_used;
94 #endif
95
96
97
98 #ifdef HAVE_SIGIO_RT
99 /* sigio specific init
100  * returns -1 on error, 0 on success */
101 static int init_sigio(io_wait_h* h, int rsig)
102 {
103         int r;
104         int n;
105         int signo;
106         int start_sig;
107         sigset_t oldset;
108         
109         if (!_sigio_init){
110                 _sigio_init=1;
111                 _sigio_crt_rtsig=SIGRTMIN;
112                 sigemptyset(&_sigio_rtsig_used);
113         }
114         h->signo=0;
115         
116         if (rsig==0){
117                 start_sig=_sigio_crt_rtsig;
118                 n=SIGRTMAX-SIGRTMIN;
119         }else{
120                 if ((rsig < SIGRTMIN) || (rsig >SIGRTMAX)){
121                         LOG(L_CRIT, "ERROR: init_sigio: real time signal %d out of"
122                                                   " range  [%d, %d]\n", rsig, SIGRTMIN, SIGRTMAX);
123                         goto error;
124                 }
125                 start_sig=rsig;
126                 n=0;
127         }
128         
129         sigemptyset(&h->sset);
130         sigemptyset(&oldset);
131 retry1:
132         /* get current block mask */
133         if (sigprocmask(SIG_BLOCK, &h->sset, &oldset )==-1){
134                 if (errno==EINTR) goto retry1;
135                 LOG(L_ERR, "ERROR: init_sigio: 1st sigprocmask failed: %s [%d]\n",
136                                 strerror(errno), errno);
137                 /* try to continue */
138         }
139         
140         for (r=start_sig; r<=(n+start_sig); r++){
141                 signo=(r>SIGRTMAX)?r-SIGRTMAX+SIGRTMIN:r;
142                 if (! sigismember(&_sigio_rtsig_used, signo) &&
143                         ! sigismember(&oldset, signo)){
144                         sigaddset(&_sigio_rtsig_used, signo);
145                         h->signo=signo;
146                         _sigio_crt_rtsig=(signo<SIGRTMAX)?signo+1:SIGRTMIN;
147                         break;
148                 }
149         }
150         
151         if (h->signo==0){
152                         LOG(L_CRIT, "ERROR: init_sigio: %s\n",
153                                         rsig?"could not assign requested real-time signal":
154                                                  "out of real-time signals");
155                         goto error;
156         }
157
158         DBG("init_sigio: trying signal %d... \n", h->signo);
159         
160         if (sigaddset(&h->sset, h->signo)==-1){
161                 LOG(L_ERR, "ERROR: init_sigio: sigaddset failed for %d: %s [%d]\n",
162                                 h->signo, strerror(errno), errno);
163                 goto error;
164         }
165         if (sigaddset(&h->sset, SIGIO)==-1){
166                 LOG(L_ERR, "ERROR: init_sigio: sigaddset failed for %d: %s [%d]\n",
167                                 SIGIO, strerror(errno), errno);
168                 goto error;
169         }
170 retry:
171         if (sigprocmask(SIG_BLOCK, &h->sset, 0)==-1){
172                 if (errno==EINTR) goto retry;
173                 LOG(L_ERR, "ERROR: init_sigio: sigprocmask failed: %s [%d]\n",
174                                 strerror(errno), errno);
175                 goto error;
176         }
177         return 0;
178 error:
179         h->signo=0;
180         sigemptyset(&h->sset);
181         return -1;
182 }
183
184
185
186 /* sigio specific destroy */
187 static void destroy_sigio(io_wait_h* h)
188 {
189         if (h->signo){
190                 sigprocmask(SIG_UNBLOCK, &h->sset, 0);
191                 sigemptyset(&h->sset);
192                 sigdelset(&_sigio_rtsig_used, h->signo);
193                 h->signo=0;
194         }
195 }
196 #endif
197
198
199
200 #ifdef HAVE_EPOLL
201 /* epoll specific init
202  * returns -1 on error, 0 on success */
203 static int init_epoll(io_wait_h* h)
204 {
205 again:
206         h->epfd=epoll_create(h->max_fd_no);
207         if (h->epfd==-1){
208                 if (errno==EINTR) goto again;
209                 LOG(L_ERR, "ERROR: init_epoll: epoll_create: %s [%d]\n",
210                                 strerror(errno), errno);
211                 return -1;
212         }
213         return 0;
214 }
215
216
217
218 static void destroy_epoll(io_wait_h* h)
219 {
220         if (h->epfd!=-1){
221                 close(h->epfd);
222                 h->epfd=-1;
223         }
224 }
225 #endif
226
227
228
229 #ifdef HAVE_KQUEUE
230 /* kqueue specific init
231  * returns -1 on error, 0 on success */
232 static int init_kqueue(io_wait_h* h)
233 {
234 again:
235         h->kq_fd=kqueue();
236         if (h->kq_fd==-1){
237                 if (errno==EINTR) goto again;
238                 LOG(L_ERR, "ERROR: init_kqueue: kqueue: %s [%d]\n",
239                                 strerror(errno), errno);
240                 return -1;
241         }
242         return 0;
243 }
244
245
246
247 static void destroy_kqueue(io_wait_h* h)
248 {
249         if (h->kq_fd!=-1){
250                 close(h->kq_fd);
251                 h->kq_fd=-1;
252         }
253 }
254 #endif
255
256
257
258 #ifdef HAVE_DEVPOLL
259 /* /dev/poll specific init
260  * returns -1 on error, 0 on success */
261 static int init_devpoll(io_wait_h* h)
262 {
263 again:
264         h->dpoll_fd=open("/dev/poll", O_RDWR);
265         if (h->dpoll_fd==-1){
266                 if (errno==EINTR) goto again;
267                 LOG(L_ERR, "ERROR: init_/dev/poll: open: %s [%d]\n",
268                                 strerror(errno), errno);
269                 return -1;
270         }
271         return 0;
272 }
273
274
275
276 static void destroy_devpoll(io_wait_h* h)
277 {
278         if (h->dpoll_fd!=-1){
279                 close(h->dpoll_fd);
280                 h->dpoll_fd=-1;
281         }
282 }
283 #endif
284
285
286
287 #ifdef HAVE_SELECT
288 static int init_select(io_wait_h* h)
289 {
290         FD_ZERO(&h->master_rset);
291         FD_ZERO(&h->master_wset);
292         return 0;
293 }
294 #endif
295
296
297 /*
298  * returns 0 on success, and an error message on error
299  */
300 char* check_poll_method(enum poll_types poll_method)
301 {
302         char* ret;
303
304         ret=0;
305         if (_os_ver==0) 
306                 _os_ver=get_sys_version(0,0,0);
307         switch(poll_method){
308                 case POLL_NONE:
309                         break;
310                 case POLL_POLL:
311                         /* always supported */
312                         break;
313                 case POLL_SELECT:
314                         /* should be always supported */
315 #ifndef HAVE_SELECT
316                         ret="select not supported, try re-compiling with -DHAVE_SELECT";
317 #endif
318                         break;
319                 case POLL_EPOLL_LT:
320                 case POLL_EPOLL_ET:
321 #ifndef HAVE_EPOLL
322                         ret="epoll not supported, try re-compiling with -DHAVE_EPOLL";
323 #else
324                         /* only on 2.6 + */
325                         if (_os_ver<0x020542) /* if ver < 2.5.66 */
326                                 ret="epoll not supported on kernels < 2.6";
327 #endif
328                         break;
329                 case POLL_SIGIO_RT:
330 #ifndef HAVE_SIGIO_RT
331                         ret="sigio_rt not supported, try re-compiling with"
332                                 " -DHAVE_SIGIO_RT";
333 #else
334                         /* only on 2.2 +  ?? */
335                         if (_os_ver<0x020200) /* if ver < 2.2.0 */
336                                 ret="epoll not supported on kernels < 2.2 (?)";
337 #endif
338                         break;
339                 case POLL_KQUEUE:
340 #ifndef HAVE_KQUEUE
341                         ret="kqueue not supported, try re-compiling with -DHAVE_KQUEUE";
342 #else
343                 /* only in FreeBSD 4.1, NETBSD 2.0, OpenBSD 2.9, Darwin, DragonFly */
344         #ifdef __OS_freebsd
345                 /* all DragonFly versions have kqueque */
346                 #ifndef __OS_dragonfly
347                         if (_os_ver<0x0401) /* if ver < 4.1 */
348                                 ret="kqueue not supported on FreeBSD < 4.1";
349                 #endif /* __OS_dragonfly */
350         #elif defined (__OS_netbsd)
351                         if (_os_ver<0x020000) /* if ver < 2.0 */
352                                 ret="kqueue not supported on NetBSD < 2.0";
353         #elif defined (__OS_openbsd)
354                         if (_os_ver<0x0209) /* if ver < 2.9 ? */
355                                 ret="kqueue not supported on OpenBSD < 2.9 (?)";
356         #endif /* assume that the rest support kqueue ifdef HAVE_KQUEUE */
357 #endif
358                         break;
359                 case POLL_DEVPOLL:
360 #ifndef HAVE_DEVPOLL
361                         ret="/dev/poll not supported, try re-compiling with"
362                                         " -DHAVE_DEVPOLL";
363 #else
364         /* only in Solaris >= 7.0 (?) */
365         #ifdef __OS_solaris
366                 if (_os_ver<0x0507) /* ver < 5.7 */
367                         ret="/dev/poll not supported on Solaris < 7.0 (SunOS 5.7)";
368         #endif
369 #endif
370                         break;
371
372                 default:
373                         ret="unknown not supported method";
374         }
375         return ret;
376 }
377
378
379
380 enum poll_types choose_poll_method()
381 {
382         enum poll_types poll_method;
383
384         if (_os_ver==0)
385                 _os_ver=get_sys_version(0,0,0); 
386         poll_method=0;
387 #ifdef HAVE_EPOLL
388         if (_os_ver>=0x020542) /* if ver >= 2.5.66 */
389                 poll_method=POLL_EPOLL_LT; /* or POLL_EPOLL_ET */
390                 
391 #endif
392 #ifdef HAVE_KQUEUE
393         if (poll_method==0)
394                 /* only in FreeBSD 4.1, NETBSD 2.0, OpenBSD 2.9, Darwin, DragonFly */
395         #ifdef __OS_freebsd
396                 /* all DragonFly versions have kqueque */
397                 #ifndef __OS_dragonfly
398                 if (_os_ver>=0x0401) /* if ver >= 4.1 */
399                 #endif /**__OS_dragonfly */
400         #elif defined (__OS_netbsd)
401                 if (_os_ver>=0x020000) /* if ver >= 2.0 */
402         #elif defined (__OS_openbsd)
403                 if (_os_ver>=0x0209) /* if ver >= 2.9 (?) */
404         #endif /* assume that the rest support kqueue ifdef HAVE_KQUEUE */
405                         poll_method=POLL_KQUEUE;
406 #endif
407 #ifdef HAVE_DEVPOLL
408         #ifdef __OS_solaris
409         if (poll_method==0)
410                 /* only in Solaris >= 7.0 (?) */
411                 if (_os_ver>=0x0507) /* if ver >=SunOS 5.7 */
412                         poll_method=POLL_DEVPOLL;
413         #endif
414 #endif
415 #ifdef  HAVE_SIGIO_RT
416                 if (poll_method==0) 
417                         if (_os_ver>=0x020200) /* if ver >= 2.2.0 */
418                                 poll_method=POLL_SIGIO_RT;
419 #endif
420                 if (poll_method==0) poll_method=POLL_POLL;
421         return poll_method;
422 }
423
424
425
426 char* poll_method_name(enum poll_types poll_method)
427 {
428         if ((poll_method>=POLL_NONE) && (poll_method<POLL_END))
429                 return poll_method_str[poll_method];
430         else
431                 return "invalid poll method";
432 }
433
434
435
436
437 /* converts a string into a poll_method
438  * returns POLL_NONE (0) on error, else the corresponding poll type */
439 enum poll_types get_poll_type(char* s)
440 {
441         int r;
442         int l;
443         
444         l=strlen(s);
445         for (r=POLL_END-1; r>POLL_NONE; r--)
446                 if ((strlen(poll_method_str[r])==l) &&
447                         (strncasecmp(poll_method_str[r], s, l)==0))
448                         break;
449         return r; 
450 }
451
452
453
454 /* initializes the static vars/arrays
455  * params:      h - pointer to the io_wait_h that will be initialized
456  *         max_fd - maximum allowed fd number
457  *         poll_m - poll method (0 for automatic best fit)
458  */
459 int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method)
460 {
461         char * poll_err;
462         
463         if (_os_ver==0) _os_ver=get_sys_version(0,0,0);
464         memset(h, 0, sizeof(*h));
465         h->max_fd_no=max_fd;
466 #ifdef HAVE_EPOLL
467         h->epfd=-1;
468 #endif
469 #ifdef HAVE_KQUEUE
470         h->kq_fd=-1;
471 #endif
472 #ifdef HAVE_DEVPOLL
473         h->dpoll_fd=-1;
474 #endif
475         poll_err=check_poll_method(poll_method);
476         
477         /* set an appropiate poll method */
478         if (poll_err || (poll_method==0)){
479                 poll_method=choose_poll_method();
480                 if (poll_err){
481                         LOG(L_ERR, "ERROR: init_io_wait: %s, using %s instead\n",
482                                         poll_err, poll_method_str[poll_method]);
483                 }else{
484                         LOG(L_INFO, "init_io_wait: using %s as the io watch method"
485                                         " (auto detected)\n", poll_method_str[poll_method]);
486                 }
487         }
488         
489         h->poll_method=poll_method;
490         
491         /* common stuff, everybody has fd_hash */
492         h->fd_hash=local_malloc(sizeof(*(h->fd_hash))*h->max_fd_no);
493         if (h->fd_hash==0){
494                 LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
495                                         " fd hashtable (%ld bytes)\n",
496                                         (long)sizeof(*(h->fd_hash))*h->max_fd_no );
497                 goto error;
498         }
499         memset((void*)h->fd_hash, 0, sizeof(*(h->fd_hash))*h->max_fd_no);
500         
501         switch(poll_method){
502                 case POLL_POLL:
503 #ifdef HAVE_SELECT
504                 case POLL_SELECT:
505 #endif
506 #ifdef HAVE_SIGIO_RT
507                 case POLL_SIGIO_RT:
508 #endif
509 #ifdef HAVE_DEVPOLL
510                 case POLL_DEVPOLL:
511 #endif
512                         h->fd_array=local_malloc(sizeof(*(h->fd_array))*h->max_fd_no);
513                         if (h->fd_array==0){
514                                 LOG(L_CRIT, "ERROR: init_io_wait: could not"
515                                                         " alloc fd array (%ld bytes)\n",
516                                                         (long)sizeof(*(h->fd_hash))*h->max_fd_no);
517                                 goto error;
518                         }
519                         memset((void*)h->fd_array, 0, sizeof(*(h->fd_array))*h->max_fd_no);
520 #ifdef HAVE_SIGIO_RT
521                         if ((poll_method==POLL_SIGIO_RT) && (init_sigio(h, 0)<0)){
522                                 LOG(L_CRIT, "ERROR: init_io_wait: sigio init failed\n");
523                                 goto error;
524                         }
525 #endif
526 #ifdef HAVE_DEVPOLL
527                         if ((poll_method==POLL_DEVPOLL) && (init_devpoll(h)<0)){
528                                 LOG(L_CRIT, "ERROR: init_io_wait: /dev/poll init failed\n");
529                                 goto error;
530                         }
531 #endif
532 #ifdef HAVE_SELECT
533                         if ((poll_method==POLL_SELECT) && (init_select(h)<0)){
534                                 LOG(L_CRIT, "ERROR: init_io_wait: select init failed\n");
535                                 goto error;
536                         }
537 #endif
538                         
539                         break;
540 #ifdef HAVE_EPOLL
541                 case POLL_EPOLL_LT:
542                 case POLL_EPOLL_ET:
543                         h->ep_array=local_malloc(sizeof(*(h->ep_array))*h->max_fd_no);
544                         if (h->ep_array==0){
545                                 LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
546                                                         " epoll array\n");
547                                 goto error;
548                         }
549                         memset((void*)h->ep_array, 0, sizeof(*(h->ep_array))*h->max_fd_no);
550                         if (init_epoll(h)<0){
551                                 LOG(L_CRIT, "ERROR: init_io_wait: epoll init failed\n");
552                                 goto error;
553                         }
554                         break;
555 #endif
556 #ifdef HAVE_KQUEUE
557                 case POLL_KQUEUE:
558                         h->kq_changes_size=KQ_CHANGES_ARRAY_SIZE;
559                         /* kevent returns different events for read & write
560                            => to get all the possible events in one call we
561                            need twice the number of added fds + space
562                            for possible changelist errors.
563                            OTOH if memory is to be saved at all costs, one can
564                            decrease the array size.
565                          */
566                         h->kq_array_size=2 * h->max_fd_no + h->kq_changes_size;
567                         h->kq_array=local_malloc(sizeof(*(h->kq_array))*h->kq_array_size);
568                         if (h->kq_array==0){
569                                 LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
570                                                         " kqueue event array\n");
571                                 goto error;
572                         }
573                         h->kq_changes=local_malloc(sizeof(*(h->kq_changes))*
574                                                                                 h->kq_changes_size);
575                         if (h->kq_changes==0){
576                                 LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
577                                                         " kqueue changes array\n");
578                                 goto error;
579                         }
580                         h->kq_nchanges=0;
581                         memset((void*)h->kq_array, 0,
582                                                 sizeof(*(h->kq_array))*h->kq_array_size);
583                         memset((void*)h->kq_changes, 0,
584                                                 sizeof(*(h->kq_changes))* h->kq_changes_size);
585                         if (init_kqueue(h)<0){
586                                 LOG(L_CRIT, "ERROR: init_io_wait: kqueue init failed\n");
587                                 goto error;
588                         }
589                         break;
590 #endif
591                 default:
592                         LOG(L_CRIT, "BUG: init_io_wait: unknown/unsupported poll"
593                                                 " method %s (%d)\n",
594                                                 poll_method_str[poll_method], poll_method);
595                         goto error;
596         }
597         return 0;
598 error:
599         return -1;
600 }
601
602
603
604 /* destroys everything init_io_wait allocated */
605 void destroy_io_wait(io_wait_h* h)
606 {
607         switch(h->poll_method){
608 #ifdef HAVE_EPOLL
609                 case POLL_EPOLL_LT:
610                 case POLL_EPOLL_ET:
611                         destroy_epoll(h);
612                         if (h->ep_array){
613                                 local_free(h->ep_array);
614                                 h->ep_array=0;
615                         }
616                 break;
617 #endif
618 #ifdef HAVE_KQUEUE
619                 case POLL_KQUEUE:
620                         destroy_kqueue(h);
621                         if (h->kq_array){
622                                 local_free(h->kq_array);
623                                 h->kq_array=0;
624                         }
625                         if (h->kq_changes){
626                                 local_free(h->kq_changes);
627                                 h->kq_changes=0;
628                         }
629                         break;
630 #endif
631 #ifdef HAVE_SIGIO_RT
632                 case POLL_SIGIO_RT:
633                         destroy_sigio(h);
634                         break;
635 #endif
636 #ifdef HAVE_DEVPOLL
637                 case POLL_DEVPOLL:
638                         destroy_devpoll(h);
639                         break;
640 #endif
641                 default: /*do  nothing*/
642                         ;
643         }
644                 if (h->fd_array){
645                         local_free(h->fd_array);
646                         h->fd_array=0;
647                 }
648                 if (h->fd_hash){
649                         local_free(h->fd_hash);
650                         h->fd_hash=0;
651                 }
652 }
653
654
655
656 #endif /*ifndef NO_IO_WAIT */