Browse code

- tcp major changes part 1: support for >1024 connection, better io poll model (best poll method selected automatically, there is also an option to enforce it). So far support for epoll (linux >= 2.5.66), sigio + real time signals (linux), poll , select. kqueue (*bsd) and /dev/poll (solaris) comming soon. WARNING: this is still work in progress, the tcp reader part is still not converted to he new model (this means that while the tcp_main process supports > 1024 fds, the tcp childs don't), the main reason for leaving this out for now is debugging. Still to do: config options for poll_method (for now use -W method if you want to force one), config options for tcp timeouts a.s.o.

Andrei Pelinescu-Onciul authored on 16/06/2005 14:05:24
Showing 14 changed files
... ...
@@ -55,7 +55,7 @@ MAIN_NAME=ser
55 55
 VERSION = 0
56 56
 PATCHLEVEL = 10
57 57
 SUBLEVEL =   99
58
-EXTRAVERSION = -dev7
58
+EXTRAVERSION = -dev8-new_tcp
59 59
 
60 60
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
61 61
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
... ...
@@ -913,6 +913,18 @@ ifeq ($(OS), linux)
913 913
 		DEFS+= -DUSE_SYSV_SEM  # try posix sems
914 914
 		found_lock_method=yes
915 915
 	endif
916
+	# check for 2.6
917
+	ifneq ($(shell echo "$(OSREL)"|grep "^2\.6\."),)
918
+		ifeq ($(NO_EPOLL),)
919
+			DEFS+=-DHAVE_EPOLL
920
+		endif
921
+	endif
922
+	ifeq ($(NO_SIGIO),)
923
+		DEFS+=-DHAVE_SIGIO_RT
924
+	endif
925
+	ifeq ($(NO_SELECT),)
926
+		DEFS+=-DHAVE_SELECT
927
+	endif
916 928
 endif
917 929
 
918 930
 ifeq  ($(OS), solaris)
... ...
@@ -922,6 +934,9 @@ ifeq  ($(OS), solaris)
922 922
 		DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
923 923
 		found_lock_method=yes
924 924
 	endif
925
+	ifeq ($(NO_SELECT),)
926
+		DEFS+=-DHAVE_SELECT
927
+	endif
925 928
 	ifeq ($(mode), release)
926 929
 		#use these only if you're using gcc with Solaris ld
927 930
 		#LDFLAGS=-O2 $(PROFILE)
... ...
@@ -956,6 +971,9 @@ ifeq ($(OS), freebsd)
956 956
 	else
957 957
 		LIBS= -lfl  #dlopen is in libc
958 958
 	endif
959
+	ifeq ($(NO_SELECT),)
960
+		DEFS+=-DHAVE_SELECT
961
+	endif
959 962
 	YACC=yacc
960 963
 endif
961 964
 
... ...
@@ -966,6 +984,9 @@ ifeq ($(OS), openbsd)
966 966
 		DEFS+= -DUSE_PTHREAD_MUTEX  # try pthread sems
967 967
 		found_lock_method=yes
968 968
 	endif
969
+	ifeq ($(NO_SELECT),)
970
+		DEFS+=-DHAVE_SELECT
971
+	endif
969 972
 	# (symbols on openbsd are prefixed by "_")
970 973
 	YACC=yacc
971 974
 	# no sched_yield on openbsd unless linking with c_r (not recommended)
... ...
@@ -995,6 +1016,9 @@ ifeq ($(OS), netbsd)
995 995
 		DEFS+= -DUSE_SYSV_SEM  # try pthread sems
996 996
 		found_lock_method=yes
997 997
 	endif
998
+	ifeq ($(NO_SELECT),)
999
+		DEFS+=-DHAVE_SELECT
1000
+	endif
998 1001
 	YACC=yacc
999 1002
 	LIBS= -lfl 
1000 1003
 endif
... ...
@@ -1014,6 +1038,9 @@ ifeq ($(OS), darwin)
1014 1014
 	else
1015 1015
 		LIBS= -lfl -lresolv  #dlopen is in libc
1016 1016
 	endif
1017
+	ifeq ($(NO_SELECT),)
1018
+		DEFS+=-DHAVE_SELECT
1019
+	endif
1017 1020
 	LDFLAGS=        # darwin doesn't like -O2 or -E
1018 1021
 	MOD_LDFLAGS= -bundle -bundle_loader ../../$(MAIN_NAME)
1019 1022
 	YACC=yacc
... ...
@@ -672,6 +672,9 @@ int start_fifo_server()
672 672
 		return -1;
673 673
 	}
674 674
 	if (fifo_pid==0) { /* child == FIFO server */
675
+		/* record pid twice to avoid the child using it, before
676
+		 * parent gets a chance to set it*/
677
+		pt[process_no].pid=getpid();
675 678
 		LOG(L_INFO, "INFO: fifo process starting: %d\n", getpid());
676 679
 		/* call per-child module initialization too -- some
677 680
 		   FIFO commands may need it
... ...
@@ -36,6 +36,7 @@
36 36
 #include "types.h"
37 37
 #include "ip_addr.h"
38 38
 #include "str.h"
39
+#include "poll_types.h"
39 40
 
40 41
 #define NO_DNS     0
41 42
 #define DO_DNS     1
... ...
@@ -80,6 +81,8 @@ extern int tcp_disable;
80 80
 extern int tcp_accept_aliases;
81 81
 extern int tcp_connect_timeout;
82 82
 extern int tcp_send_timeout;
83
+extern enum poll_types tcp_poll_method;
84
+extern int tcp_max_fd_no;
83 85
 #endif
84 86
 #ifdef USE_TLS
85 87
 extern int tls_disable;
... ...
@@ -119,9 +122,9 @@ extern unsigned int msg_no;
119 119
 extern unsigned long shm_mem_size;
120 120
 
121 121
 /* FIFO server config */
122
-char extern *fifo; /* FIFO name */
122
+extern char *fifo; /* FIFO name */
123 123
 extern int fifo_mode;
124
-char extern *fifo_dir; /* dir. where  reply fifos are allowed */
124
+extern char *fifo_dir; /* dir. where  reply fifos are allowed */
125 125
 extern char *fifo_db_url;  /* db url used by db_fifo interface */
126 126
 
127 127
 /* UNIX domain socket configuration */
128 128
new file mode 100644
... ...
@@ -0,0 +1,492 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2005 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser 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
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+/* 
27
+ * tcp io wait common stuff used by tcp_main.c & tcp_read.c
28
+ * (see io_wait.h)
29
+ */
30
+/* 
31
+ * History:
32
+ * --------
33
+ *  2005-06-15  created by andrei
34
+ */
35
+
36
+
37
+
38
+#ifdef USE_TCP /* for now it make sense only with tcp */
39
+
40
+#ifdef HAVE_EPOLL
41
+#include <unistd.h> /* close() */
42
+#endif
43
+
44
+#include <sys/utsname.h> /* uname() */
45
+#include <stdlib.h> /* strtol() */
46
+#include "io_wait.h"
47
+
48
+
49
+#include "mem/mem.h"
50
+
51
+#ifndef local_malloc
52
+#define local_malloc pkg_malloc
53
+#endif
54
+#ifndef local_free
55
+#define local_free pkg_free
56
+#endif
57
+
58
+char* poll_support="poll"
59
+#ifdef HAVE_EPOLL
60
+", epoll_lt, epoll_et"
61
+#endif
62
+#ifdef HAVE_SIGIO_RT
63
+", sigio_rt"
64
+#endif
65
+#ifdef HAVE_SELECT
66
+", select"
67
+#endif
68
+#ifdef HAVE_KQUEUE
69
+", kqueue"
70
+#endif
71
+#ifdef HAVE_DEVPOLL
72
+", /dev/poll"
73
+#endif
74
+;
75
+
76
+
77
+char* poll_method_str[POLL_END]={ "none", "poll", "epoll_lt", "epoll_et", 
78
+								  "sigio_rt", "select", "kqueue",  "/dev/poll"
79
+								};
80
+
81
+#ifdef HAVE_SIGIO_RT
82
+static int _sigio_init=0;
83
+static int _sigio_crt_rtsig;
84
+static sigset_t _sigio_rtsig_used;
85
+#endif
86
+
87
+
88
+
89
+#ifdef HAVE_SIGIO_RT
90
+/* sigio specific init
91
+ * returns -1 on error, 0 on success */
92
+static int init_sigio(io_wait_h* h, int rsig)
93
+{
94
+	int r;
95
+	int n;
96
+	int signo;
97
+	int start_sig;
98
+	sigset_t oldset;
99
+	
100
+	if (!_sigio_init){
101
+		_sigio_init=1;
102
+		_sigio_crt_rtsig=SIGRTMIN;
103
+		sigemptyset(&_sigio_rtsig_used);
104
+	}
105
+	h->signo=0;
106
+	
107
+	if (rsig==0){
108
+		start_sig=_sigio_crt_rtsig;
109
+		n=SIGRTMAX-SIGRTMIN;
110
+	}else{
111
+		if ((rsig < SIGRTMIN) || (rsig >SIGRTMAX)){
112
+			LOG(L_CRIT, "ERROR: init_sigio: real time signal %d out of"
113
+					          " range  [%d, %d]\n", rsig, SIGRTMIN, SIGRTMAX);
114
+			goto error;
115
+		}
116
+		start_sig=rsig;
117
+		n=0;
118
+	}
119
+	
120
+	sigemptyset(&h->sset);
121
+	sigemptyset(&oldset);
122
+retry1:
123
+	/* get current block mask */
124
+	if (sigprocmask(SIG_BLOCK, &h->sset, &oldset )==-1){
125
+		if (errno==EINTR) goto retry1;
126
+		LOG(L_ERR, "ERROR: init_sigio: 1st sigprocmask failed: %s [%d]\n",
127
+				strerror(errno), errno);
128
+		/* try to continue */
129
+	}
130
+	
131
+	for (r=start_sig; r<=(n+start_sig); r++){
132
+		signo=(r>SIGRTMAX)?r-SIGRTMAX+SIGRTMIN:r;
133
+		if (! sigismember(&_sigio_rtsig_used, signo) &&
134
+			! sigismember(&oldset, signo)){
135
+			sigaddset(&_sigio_rtsig_used, signo);
136
+			h->signo=signo;
137
+			_sigio_crt_rtsig=(signo<SIGRTMAX)?signo+1:SIGRTMIN;
138
+			break;
139
+		}
140
+	}
141
+	
142
+	if (h->signo==0){
143
+			LOG(L_CRIT, "ERROR: init_sigio: %s\n",
144
+					rsig?"could not assign requested real-time signal":
145
+						 "out of real-time signals");
146
+			goto error;
147
+	}
148
+
149
+	DBG("init_sigio: trying signal %d... \n", h->signo);
150
+	
151
+	if (sigaddset(&h->sset, h->signo)==-1){
152
+		LOG(L_ERR, "ERROR: init_sigio: sigaddset failed for %d: %s [%d]\n",
153
+				h->signo, strerror(errno), errno);
154
+		goto error;
155
+	}
156
+	if (sigaddset(&h->sset, SIGIO)==-1){
157
+		LOG(L_ERR, "ERROR: init_sigio: sigaddset failed for %d: %s [%d]\n",
158
+				SIGIO, strerror(errno), errno);
159
+		goto error;
160
+	}
161
+retry:
162
+	if (sigprocmask(SIG_BLOCK, &h->sset, 0)==-1){
163
+		if (errno==EINTR) goto retry;
164
+		LOG(L_ERR, "ERROR: init_sigio: sigprocmask failed: %s [%d]\n",
165
+				strerror(errno), errno);
166
+		goto error;
167
+	}
168
+	return 0;
169
+error:
170
+	h->signo=0;
171
+	sigemptyset(&h->sset);
172
+	return -1;
173
+}
174
+
175
+
176
+
177
+/* sigio specific destroy */
178
+static void destroy_sigio(io_wait_h* h)
179
+{
180
+	if (h->signo){
181
+		sigprocmask(SIG_UNBLOCK, &h->sset, 0);
182
+		sigemptyset(&h->sset);
183
+		sigdelset(&_sigio_rtsig_used, h->signo);
184
+		h->signo=0;
185
+	}
186
+}
187
+#endif
188
+
189
+
190
+
191
+#ifdef HAVE_EPOLL
192
+/* epoll specific init
193
+ * returns -1 on error, 0 on success */
194
+static int init_epoll(io_wait_h* h)
195
+{
196
+	h->epfd=epoll_create(h->max_fd_no);
197
+	if (h->epfd==-1){
198
+		LOG(L_ERR, "ERROR: init_epoll: epoll_create: %s [%d]\n",
199
+				strerror(errno), errno);
200
+		return -1;
201
+	}
202
+	return 0;
203
+}
204
+
205
+
206
+
207
+static void destroy_epoll(io_wait_h* h)
208
+{
209
+	if (h->epfd!=-1){
210
+		close(h->epfd);
211
+		h->epfd=-1;
212
+	}
213
+}
214
+#endif
215
+
216
+
217
+
218
+#ifdef HAVE_SELECT
219
+static int init_select(io_wait_h* h)
220
+{
221
+	FD_ZERO(&h->master_set);
222
+	return 0;
223
+}
224
+#endif
225
+
226
+
227
+
228
+/* return system version (major.minor.minor2) as
229
+ *  (major<<16)|(minor)<<8|(minor2)
230
+ * (if some of them are missing, they are set to 0)
231
+ * if the parameters are not null they are set to the coresp. part 
232
+ */
233
+static unsigned int get_sys_version(int* major, int* minor, int* minor2)
234
+{
235
+	struct utsname un;
236
+	int m1;
237
+	int m2;
238
+	int m3;
239
+	char* p;
240
+	
241
+	memset (&un, 0, sizeof(un));
242
+	m1=m2=m3=0;
243
+	/* get sys version */
244
+	uname(&un);
245
+	m1=strtol(un.release, &p, 10);
246
+	if (*p=='.'){
247
+		p++;
248
+		m2=strtol(p, &p, 10);
249
+		if (*p=='.'){
250
+			p++;
251
+			m3=strtol(p, &p, 10);
252
+		}
253
+	}
254
+	if (major) *major=m1;
255
+	if (minor) *minor=m2;
256
+	if (minor2) *minor2=m3;
257
+	return ((m1<<16)|(m2<<8)|(m3));
258
+}
259
+
260
+
261
+
262
+/*
263
+ * returns 0 on success, and an error message on error
264
+ */
265
+char* check_poll_method(enum poll_types poll_method)
266
+{
267
+	char* ret;
268
+	ret=0;
269
+	
270
+	switch(poll_method){
271
+		case POLL_NONE:
272
+			break;
273
+		case POLL_POLL:
274
+			/* always supported */
275
+			break;
276
+		case POLL_SELECT:
277
+			/* should be always supported */
278
+#ifndef HAVE_SELECT
279
+			ret="select not supported, try re-compiling with -DHAVE_SELECT";
280
+#endif
281
+			break;
282
+		case POLL_EPOLL_LT:
283
+		case POLL_EPOLL_ET:
284
+			/* only on 2.6 + */
285
+#ifndef HAVE_EPOLL
286
+			ret="epoll not supported, try re-compiling with -DHAVE_EPOLL";
287
+#else
288
+			if (get_sys_version(0,0,0)<0x020542) /* if ver < 2.5.66 */
289
+			 	ret="epoll not supported on kernels < 2.6";
290
+#endif
291
+			break;
292
+		case POLL_SIGIO_RT:
293
+#ifndef HAVE_SIGIO_RT
294
+			ret="sigio_rt not supported, try re-compiling with"
295
+				" -DHAVE_SIGIO_RT";
296
+#endif
297
+			break;
298
+		default:
299
+			ret="unknown not supported method";
300
+	}
301
+	return ret;
302
+}
303
+
304
+
305
+
306
+enum poll_types choose_poll_method()
307
+{
308
+	enum poll_types poll_method;
309
+	
310
+	poll_method=0;
311
+#ifdef HAVE_EPOLL
312
+	if (get_sys_version(0,0,0)>=0x020542) /* if ver >= 2.5.66 */
313
+		poll_method=POLL_EPOLL_LT; /* or POLL_EPOLL_ET */
314
+		
315
+#endif
316
+#ifdef  HAVE_SIGIO_RT
317
+		if (poll_method==0) poll_method=POLL_SIGIO_RT;
318
+#endif
319
+		if (poll_method==0) poll_method=POLL_POLL;
320
+	return poll_method;
321
+}
322
+
323
+
324
+
325
+char* poll_method_name(enum poll_types poll_method)
326
+{
327
+	if ((poll_method>=POLL_NONE) && (poll_method<POLL_END))
328
+		return poll_method_str[poll_method];
329
+	else
330
+		return "invalid poll method";
331
+}
332
+
333
+
334
+
335
+
336
+/* converts a string into a poll_method
337
+ * returns POLL_NONE (0) on error, else the corresponding poll type */
338
+enum poll_types get_poll_type(char* s)
339
+{
340
+	int r;
341
+	int l;
342
+	
343
+	l=strlen(s);
344
+	for (r=POLL_END-1; r>POLL_NONE; r--)
345
+		if ((strlen(poll_method_str[r])==l) &&
346
+			(strncasecmp(poll_method_str[r], s, l)==0))
347
+			break;
348
+	return r; 
349
+}
350
+
351
+
352
+
353
+/* initializes the static vars/arrays
354
+ * params:      h - pointer to the io_wait_h that will be initialized
355
+ *         max_fd - maximum allowed fd number
356
+ *         poll_m - poll method (0 for automatic best fit)
357
+ */
358
+int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method)
359
+{
360
+	char * poll_err;
361
+	
362
+	memset(h, 0, sizeof(*h));
363
+	h->max_fd_no=max_fd;
364
+#ifdef HAVE_EPOLL
365
+	h->epfd=-1;
366
+#endif
367
+	
368
+	poll_err=check_poll_method(poll_method);
369
+	
370
+	/* set an appropiate poll method */
371
+	if (poll_err || (poll_method==0)){
372
+		poll_method=choose_poll_method();
373
+		if (poll_err){
374
+			LOG(L_ERR, "ERROR: init_io_wait: %s, using %s instead\n",
375
+					poll_err, poll_method_str[poll_method]);
376
+		}else{
377
+			LOG(L_INFO, "init_io_wait: using %s as the io watch method"
378
+					" (auto detected)\n", poll_method_str[poll_method]);
379
+		}
380
+	}else{
381
+			LOG(L_INFO, "init_io_wait: using %s io watch method (forced)\n",
382
+					poll_method_str[poll_method]);
383
+	}
384
+
385
+	
386
+	h->poll_method=poll_method;
387
+	
388
+	/* common stuff, evrybody has fd_hash */
389
+	h->fd_hash=local_malloc(sizeof(*(h->fd_hash))*h->max_fd_no);
390
+	if (h->fd_hash==0){
391
+		LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
392
+					" fd hashtable (%d bytes)\n",
393
+					sizeof(*(h->fd_hash))*h->max_fd_no );
394
+		goto error;
395
+	}
396
+	memset((void*)h->fd_hash, 0, sizeof(*(h->fd_hash))*h->max_fd_no);
397
+	
398
+	switch(poll_method){
399
+		case POLL_POLL:
400
+#ifdef HAVE_SELECT
401
+		case POLL_SELECT:
402
+#endif
403
+#ifdef HAVE_SIGIO_RT
404
+		case POLL_SIGIO_RT:
405
+#endif
406
+			h->fd_array=local_malloc(sizeof(*(h->fd_array))*h->max_fd_no);
407
+			if (h->fd_array==0){
408
+				LOG(L_CRIT, "ERROR: init_io_wait: could not"
409
+							" alloc fd array (%d bytes)\n",
410
+							sizeof(*(h->fd_hash))*h->max_fd_no);
411
+				goto error;
412
+			}
413
+			memset((void*)h->fd_array, 0, sizeof(*(h->fd_array))*h->max_fd_no);
414
+#ifdef HAVE_SIGIO_RT
415
+			if ((poll_method==POLL_SIGIO_RT) && (init_sigio(h, 0)<0)){
416
+				LOG(L_CRIT, "ERROR: init_io_wait: sigio init failed\n");
417
+				goto error;
418
+			}
419
+#endif
420
+#ifdef HAVE_SELECT
421
+			if ((poll_method==POLL_SELECT) && (init_select(h)<0)){
422
+				LOG(L_CRIT, "ERROR: init_io_wait: select init failed\n");
423
+				goto error;
424
+			}
425
+#endif
426
+			
427
+			break;
428
+#ifdef HAVE_EPOLL
429
+		case POLL_EPOLL_LT:
430
+		case POLL_EPOLL_ET:
431
+			h->ep_array=local_malloc(sizeof(*(h->ep_array))*h->max_fd_no);
432
+			if (h->ep_array==0){
433
+				LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
434
+							" epoll array\n");
435
+				goto error;
436
+			}
437
+			memset((void*)h->ep_array, 0, sizeof(*(h->ep_array))*h->max_fd_no);
438
+			if (init_epoll(h)<0){
439
+				LOG(L_CRIT, "ERROR: init_io_wait: epoll init failed\n");
440
+				goto error;
441
+			}
442
+			break;
443
+#endif
444
+		default:
445
+			LOG(L_CRIT, "BUG: init_io_wait: unknown/unsupported poll"
446
+						" method %s (%d)\n",
447
+						poll_method_str[poll_method], poll_method);
448
+			goto error;
449
+	}
450
+	return 0;
451
+error:
452
+	return -1;
453
+}
454
+
455
+
456
+
457
+/* destroys everything init_io_wait allocated */
458
+void destroy_io_wait(io_wait_h* h)
459
+{
460
+	switch(h->poll_method){
461
+#ifdef HAVE_EPOLL
462
+		case POLL_EPOLL_LT:
463
+		case POLL_EPOLL_ET:
464
+			destroy_epoll(h);
465
+			if (h->ep_array){
466
+				local_free(h->ep_array);
467
+				h->ep_array=0;
468
+			}
469
+		break;
470
+#endif
471
+#ifdef HAVE_SIGIO_RT
472
+		case POLL_SIGIO_RT:
473
+			destroy_sigio(h);
474
+			break;
475
+#endif
476
+		default: /*do  nothing*/
477
+			;
478
+	}
479
+		if (h->fd_array){
480
+			local_free(h->fd_array);
481
+			h->fd_array=0;
482
+		}
483
+		if (h->fd_hash){
484
+			local_free(h->fd_hash);
485
+			h->fd_hash=0;
486
+		}
487
+}
488
+
489
+
490
+
491
+#endif
0 492
new file mode 100644
... ...
@@ -0,0 +1,663 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2005 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser 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
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+/*
27
+ * tcp io wait common stuff used by tcp_main.c & tcp_read.c
28
+ * All the functions are inline because of speed reasons and because they are
29
+ * used only from 2 places.
30
+ * You also have to define:
31
+ *     int handle_io(struct fd_map* fm, int idx) (see below)
32
+ *     (this could be trivially replaced by a callback pointer entry attached
33
+ *      to the io_wait handler if more flexibility rather then performance
34
+ *      is needed)
35
+ *      fd_type - define to some enum of you choice and define also
36
+ *                FD_TYPE_DEFINED (if you don't do it fd_type will be defined
37
+ *                to int). 0 has a special not set/not init. meaning
38
+ *                (a lot of sanity checks and the sigio_rt code are based on
39
+ *                 this assumption)
40
+ *     local_malloc (defaults to pkg_malloc)
41
+ *     local_free   (defaults to pkg_free)
42
+ *  
43
+ */
44
+/* 
45
+ * History:
46
+ * --------
47
+ *  2005-06-13  created by andrei
48
+ */
49
+
50
+
51
+
52
+#ifndef _io_wait_h
53
+#define _io_wait_h
54
+
55
+#include <errno.h>
56
+#include <string.h>
57
+#ifdef HAVE_SIGIO_RT
58
+#define __USE_GNU /* or else F_SETSIG won't be included */
59
+#include <sys/types.h> /* recv */
60
+#include <sys/socket.h> /* recv */
61
+#include <signal.h> /* sigprocmask, sigwait a.s.o */
62
+#endif
63
+#ifdef HAVE_EPOLL
64
+#include <sys/epoll.h>
65
+#endif
66
+#ifdef HAVE_SELECT
67
+#include <sys/select.h>
68
+#endif
69
+#include <sys/poll.h>
70
+#include <fcntl.h>
71
+
72
+#include "dprint.h"
73
+
74
+#include "poll_types.h" /* poll_types*/
75
+#ifdef HAVE_SIGIO_RT
76
+#include "pt.h" /* mypid() */
77
+#endif
78
+
79
+
80
+#if 0
81
+enum fd_types; /* this should be defined from the including file,
82
+				  see tcp_main.c for an example, 
83
+				  0 has a special meaning: not used/empty*/
84
+#endif
85
+
86
+#ifndef FD_TYPE_DEFINED
87
+typedef int fd_type;
88
+#define FD_TYPE_DEFINED
89
+#endif
90
+
91
+/* maps a fd to some other structure; used in almost all cases
92
+ * except epoll and maybe kqueue or /dev/poll */
93
+struct fd_map{
94
+	int fd;               /* fd no */
95
+	fd_type type;         /* "data" type */
96
+	void* data;           /* pointer to the corresponding structure */
97
+};
98
+
99
+
100
+
101
+/* handler structure */
102
+struct io_wait_handler{
103
+#ifdef HAVE_EPOLL
104
+	struct epoll_event* ep_array;
105
+	int epfd; /* epoll ctrl fd */
106
+#endif
107
+#ifdef HAVE_SIGIO_RT
108
+	sigset_t sset; /* signal mask for sigio & sigrtmin */
109
+	int signo;     /* real time signal used */
110
+#endif
111
+#ifdef HAVE_SELECT
112
+	fd_set master_set;
113
+	int max_fd_select; /* maximum select used fd */
114
+#endif
115
+	/* common stuff for POLL, SIGIO_RT and SELECT
116
+	 * since poll support is always compiled => this will always be compiled */
117
+	struct fd_map* fd_hash;
118
+	struct pollfd* fd_array;
119
+	int fd_no; /*  current index used in fd_array */
120
+	int max_fd_no; /* maximum fd no, is also the size of fd_array,
121
+						       fd_hash  and ep_array*/
122
+	enum poll_types poll_method;
123
+	int flags;
124
+};
125
+
126
+typedef struct io_wait_handler io_wait_h;
127
+
128
+
129
+/* get the corresponding fd_map structure pointer */
130
+#define get_fd_map(h, fd)		(&(h)->fd_hash[(fd)])
131
+/* remove a fd_map structure from the hash; the pointer must be returned
132
+ * by get_fd_map or hash_fd_map*/
133
+#define unhash_fd_map(pfm)	\
134
+	do{ \
135
+		(pfm)->type=0 /*F_NONE */; \
136
+		(pfm)->fd=-1; \
137
+	}while(0)
138
+
139
+/* add a fd_map structure to the fd hash */
140
+static inline struct fd_map* hash_fd_map(	io_wait_h* h,
141
+											int fd,
142
+											fd_type type,
143
+											void* data)
144
+{
145
+	h->fd_hash[fd].fd=fd;
146
+	h->fd_hash[fd].type=type;
147
+	h->fd_hash[fd].data=data;
148
+	return &h->fd_hash[fd];
149
+}
150
+
151
+
152
+#ifdef HAVE_SIGIO_RT
153
+typedef unsigned int sigio_rtsig_mask_t;
154
+extern sigset_t _sigio_rtsig_used;
155
+extern int _sigio_crt_rtsig;
156
+extern int _sigio_init;
157
+#endif
158
+
159
+
160
+
161
+#ifdef HANDLE_IO_INLINE
162
+/* generic handle io routine, this must be defined in the including file
163
+ * (faster then registering a callback pointer)
164
+ *
165
+ * params:  fm  - pointer to a fd hash entry
166
+ *          idx - index in the fd_array (or -1 if not known)
167
+ * return: -1 on error
168
+ *          0 on EAGAIN or when by some other way it is known that no more 
169
+ *            io events are queued on the fd (the receive buffer is empty).
170
+ *            Usefull to detect when there are no more io events queued for
171
+ *            sigio_rt, epoll_et, kqueue.
172
+ *         >0 on successfull read from the fd (when there might be more io
173
+ *            queued -- the receive buffer might still be non-empty)
174
+ */
175
+inline static int handle_io(struct fd_map* fm, int idx);
176
+#else
177
+int handle_io(struct fd_map* fm, int idx);
178
+#endif
179
+
180
+
181
+
182
+/* generic io_watch_add function
183
+ * returns 0 on success, -1 on error
184
+ *
185
+ * this version should be faster than pointers to poll_method specific
186
+ * functions (it avoids functions calls, the overhead being only an extra
187
+ *  switch())*/
188
+inline static int io_watch_add(	io_wait_h* h,
189
+								int fd,
190
+								fd_type type,
191
+								void* data)
192
+{
193
+
194
+	/* helper macros */
195
+#define fd_array_setup \
196
+	do{ \
197
+		h->fd_array[h->fd_no].fd=fd; \
198
+		h->fd_array[h->fd_no].events=POLLIN; /* useless for select */ \
199
+		h->fd_array[h->fd_no].revents=0;     /* useless for select */ \
200
+	}while(0)
201
+	
202
+#define set_fd_flags(f) \
203
+	do{ \
204
+			flags=fcntl(fd, F_GETFL); \
205
+			if (flags==-1){ \
206
+				LOG(L_ERR, "ERROR: io_watch_add: fnctl: GETFL failed:" \
207
+						" %s [%d]\n", strerror(errno), errno); \
208
+				goto error; \
209
+			} \
210
+			if (fcntl(fd, F_SETFL, flags|(f))==-1){ \
211
+				LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETFL" \
212
+							" failed: %s [%d]\n", strerror(errno), errno); \
213
+				goto error; \
214
+			} \
215
+	}while(0)
216
+	
217
+	
218
+	struct fd_map* e;
219
+	int flags;
220
+#ifdef HAVE_EPOLL
221
+	int n;
222
+	struct epoll_event ep_event;
223
+#endif
224
+#ifdef HAVE_SIGIO_RT
225
+	static char buf[65536];
226
+#endif
227
+	
228
+	if (fd==-1){
229
+		LOG(L_CRIT, "BUG: io_watch_add: fd is -1!\n");
230
+		goto error;
231
+	}
232
+	/* add it to the poll fd array */
233
+	if (h->fd_no>=h->max_fd_no){
234
+		LOG(L_CRIT, "ERROR: io_watch_add: maximum fd number exceeded:"
235
+				" %d/%d\n", h->fd_no, h->max_fd_no);
236
+		goto error;
237
+	}
238
+	DBG("DBG: io_watch_add(%p, %d, %d, %p), fd_no=%d\n",
239
+			h, fd, type, data, h->fd_no);
240
+	/*  hash sanity check */
241
+	e=get_fd_map(h, fd);
242
+	if (e && (e->type!=0 /*F_NONE*/)){
243
+		LOG(L_ERR, "ERROR: io_watch_add: trying to overwrite entry %d"
244
+				" in the hash(%d, %d, %p) with (%d, %d, %p)\n",
245
+				fd, e->fd, e->type, e->data, fd, type, data);
246
+		goto error;
247
+	}
248
+	
249
+	if ((e=hash_fd_map(h, fd, type, data))==0){
250
+		LOG(L_ERR, "ERROR: io_watch_add: failed to hash the fd %d\n", fd);
251
+		goto error;
252
+	}
253
+	switch(h->poll_method){ /* faster then pointer to functions */
254
+		case POLL_POLL:
255
+			fd_array_setup;
256
+			set_fd_flags(O_NONBLOCK);
257
+			break;
258
+#ifdef HAVE_SELECT
259
+		case POLL_SELECT:
260
+			fd_array_setup;
261
+			FD_SET(fd, &h->master_set);
262
+			if (h->max_fd_select<fd) h->max_fd_select=fd;
263
+			break;
264
+#endif
265
+#ifdef HAVE_SIGIO_RT
266
+		case POLL_SIGIO_RT:
267
+			fd_array_setup;
268
+			/* set async & signal */
269
+			if (fcntl(fd, F_SETOWN, my_pid())==-1){
270
+				LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETOWN"
271
+				" failed: %s [%d]\n", strerror(errno), errno);
272
+				goto error;
273
+			}
274
+			if (fcntl(fd, F_SETSIG, h->signo)==-1){
275
+				LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETSIG"
276
+					" failed: %s [%d]\n", strerror(errno), errno);
277
+				goto error;
278
+			}
279
+			/* set both non-blocking and async */
280
+			set_fd_flags(O_ASYNC| O_NONBLOCK);
281
+#ifdef EXTRA_DEBUG
282
+			DBG("io_watch_add: sigio_rt on f %d, signal %d to pid %d\n",
283
+					fd,  h->signo, pid);
284
+#endif
285
+			/* empty socket receive buffer, if buffer is already full
286
+			 * (e.g. early media), no more space to put packets
287
+			 * => no more signals are ever generated -- andrei */
288
+			while(recv(fd, buf, sizeof(buf), 0)>=0);
289
+			break;
290
+#endif
291
+#ifdef HAVE_EPOLL
292
+		case POLL_EPOLL_LT:
293
+			ep_event.events=EPOLLIN;
294
+			ep_event.data.ptr=e;
295
+again1:
296
+			n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event);
297
+			if (n==-1){
298
+				if (errno==EAGAIN) goto again1;
299
+				LOG(L_ERR, "ERROR: io_watch_add: epoll_ctl failed: %s [%d]\n",
300
+					strerror(errno), errno);
301
+				goto error;
302
+			}
303
+			break;
304
+		case POLL_EPOLL_ET:
305
+			set_fd_flags(O_NONBLOCK);
306
+			ep_event.events=EPOLLIN|EPOLLET;
307
+			ep_event.data.ptr=e;
308
+again2:
309
+			n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event);
310
+			if (n==-1){
311
+				if (errno==EAGAIN) goto again2;
312
+				LOG(L_ERR, "ERROR: io_watch_add: epoll_ctl failed: %s [%d]\n",
313
+					strerror(errno), errno);
314
+				goto error;
315
+			}
316
+			break;
317
+#endif
318
+		default:
319
+			LOG(L_CRIT, "BUG: io_watch_add: no support for poll method "
320
+					" %s (%d)\n", poll_method_str[h->poll_method],
321
+					h->poll_method);
322
+			goto error;
323
+	}
324
+	
325
+	h->fd_no++; /* "activate" changes, for epoll it
326
+				   has only informative value */
327
+	return 0;
328
+error:
329
+	return -1;
330
+#undef fd_array_setup
331
+#undef set_fd_flags 
332
+}
333
+
334
+
335
+
336
+/* parameters: fd and index in the fd_array
337
+ * if index==-1, it fd_array will be searched for the corresponding fd
338
+ * entry (slower but unavoidable in some cases)
339
+ * index is not used (no fd_arry) for epoll, /dev/poll and kqueue
340
+ * returns 0 if ok, -1 on error */
341
+inline static int io_watch_del(io_wait_h* h, int fd, int idx)
342
+{
343
+	
344
+#define fix_fd_array \
345
+	do{\
346
+			if (idx==-1){ \
347
+				/* fix idx if -1 and needed */ \
348
+				for (idx=0; (idx<h->fd_no) && \
349
+							(h->fd_array[idx].fd!=fd); idx++); \
350
+			} \
351
+			if (idx<h->fd_no){ \
352
+				memmove(&h->fd_array[idx], &h->fd_array[idx+1], \
353
+					(h->fd_no-(idx+1))*sizeof(*(h->fd_array))); \
354
+			} \
355
+	}while(0)
356
+	
357
+	struct fd_map* e;
358
+#ifdef HAVE_EPOLL
359
+	int n;
360
+	struct epoll_event ep_event;
361
+#endif
362
+	
363
+	if ((fd<0) || (fd>=h->max_fd_no)){
364
+		LOG(L_CRIT, "BUG: io_watch_del: invalid fd %d, not in [0, %d) \n",
365
+						fd, h->fd_no);
366
+		goto error;
367
+	}
368
+	DBG("DBG: io_watch_del (%p, %d, %d) fd_no=%d called\n",
369
+			h, fd, idx, h->fd_no);
370
+	e=get_fd_map(h, fd);
371
+	/* more sanity checks */
372
+	if (e==0){
373
+		LOG(L_CRIT, "BUG: io_watch_del: no corresponding hash entry for %d\n",
374
+					fd);
375
+		goto error;
376
+	}
377
+	if (e->type==0 /*F_NONE*/){
378
+		LOG(L_ERR, "ERROR: io_watch_del: trying to delete already erased"
379
+				" entry %d in the hash(%d, %d, %p) )\n",
380
+				fd, e->fd, e->type, e->data);
381
+		goto error;
382
+	}
383
+	
384
+	unhash_fd_map(e);
385
+	
386
+	switch(h->poll_method){
387
+		case POLL_POLL:
388
+			fix_fd_array;
389
+			break;
390
+#ifdef HAVE_SELECT
391
+		case POLL_SELECT:
392
+			fix_fd_array;
393
+			FD_CLR(fd, &h->master_set);
394
+			if (h->max_fd_select && (h->max_fd_select==fd))
395
+				/* we don't know the prev. max, so we just decrement it */
396
+				h->max_fd_select--; 
397
+			break;
398
+#endif
399
+#ifdef HAVE_SIGIO_RT
400
+		case POLL_SIGIO_RT:
401
+			fix_fd_array;
402
+			/* FIXME: re-set ASYNC? (not needed if the fd is/will be closed
403
+			 *        but might cause problems if the fd is "moved")
404
+			 *        update: probably not needed, the fd_map type!=0
405
+			 *        check should catch old queued signals or in-transit fd
406
+			 *        (so making another syscall to reset ASYNC is not 
407
+			 *         necessary)*/
408
+			break;
409
+#endif
410
+#ifdef HAVE_EPOLL
411
+		case POLL_EPOLL_LT:
412
+		case POLL_EPOLL_ET:
413
+			n=epoll_ctl(h->epfd, EPOLL_CTL_DEL, fd, &ep_event);
414
+			if (n==-1){
415
+				LOG(L_ERR, "ERROR: io_watch_del: removing fd from"
416
+					" epoll list failed: %s [%d]\n", strerror(errno), errno);
417
+				goto error;
418
+			}
419
+			break;
420
+#endif
421
+		default:
422
+			LOG(L_CRIT, "BUG: io_watch_del: no support for poll method "
423
+					" %s (%d)\n", poll_method_str[h->poll_method], 
424
+					h->poll_method);
425
+			goto error;
426
+	}
427
+	h->fd_no--;
428
+	return 0;
429
+error:
430
+	return -1;
431
+#undef fix_fd_array
432
+}
433
+
434
+
435
+
436
+/* io_wait_loop_x style function 
437
+ * wait for io using poll()
438
+ * params: h      - io_wait handle
439
+ *         t      - timeout in s
440
+ *         repeat - if !=0 handle_io will be called until it returns <=0
441
+ * returns: 0 on success, -1 on err
442
+ */
443
+inline static int io_wait_loop_poll(io_wait_h* h, int t, int repeat)
444
+{
445
+	int n, r;
446
+	int ret;
447
+again:
448
+		ret=n=poll(h->fd_array, h->fd_no, t*1000);
449
+		if (n==-1){
450
+			if (errno==EINTR) goto again; /* signal, ignore it */
451
+			else{
452
+				LOG(L_ERR, "ERROR:io_wait_loop_poll: poll: %s [%d]\n",
453
+						strerror(errno), errno);
454
+				goto error;
455
+			}
456
+		}
457
+		for (r=0; (r<h->fd_no) && n; r++){
458
+			if (h->fd_array[r].revents & (POLLIN|POLLERR|POLLHUP)){
459
+				n--;
460
+				/* sanity checks */
461
+				if ((h->fd_array[r].fd >= h->max_fd_no)||
462
+						(h->fd_array[r].fd < 0)){
463
+					LOG(L_CRIT, "BUG: io_wait_loop_poll: bad fd %d "
464
+							"(no in the 0 - %d range)\n",
465
+							h->fd_array[r].fd, h->max_fd_no);
466
+					/* try to continue anyway */
467
+					h->fd_array[r].events=0; /* clear the events */
468
+					continue;
469
+				}
470
+				while((handle_io(get_fd_map(h, h->fd_array[r].fd), r) > 0)
471
+						 && repeat);
472
+			}
473
+		}
474
+error:
475
+	return ret;
476
+}
477
+
478
+
479
+
480
+#ifdef HAVE_SELECT
481
+/* wait for io using select */
482
+inline static int io_wait_loop_select(io_wait_h* h, int t, int repeat)
483
+{
484
+	fd_set sel_set;
485
+	int n, ret;
486
+	struct timeval timeout;
487
+	int r;
488
+	
489
+again:
490
+		sel_set=h->master_set;
491
+		timeout.tv_sec=t;
492
+		timeout.tv_usec=0;
493
+		ret=n=select(h->max_fd_select+1, &sel_set, 0, 0, &timeout);
494
+		if (n<0){
495
+			if (errno==EINTR) goto again; /* just a signal */
496
+			LOG(L_ERR, "ERROR: io_wait_loop_select: select: %s [%d]\n",
497
+					strerror(errno), errno);
498
+			n=0;
499
+			/* continue */
500
+		}
501
+		/* use poll fd array */
502
+		for(r=0; (r<h->max_fd_no) && n; r++){
503
+			if (FD_ISSET(h->fd_array[r].fd, &sel_set)){
504
+				while((handle_io(get_fd_map(h, h->fd_array[r].fd), r)>0)
505
+						&& repeat);
506
+				n--;
507
+			}
508
+		};
509
+	return ret;
510
+}
511
+#endif
512
+
513
+
514
+
515
+#ifdef HAVE_EPOLL
516
+inline static int io_wait_loop_epoll(io_wait_h* h, int t, int repeat)
517
+{
518
+	int n, r;
519
+	
520
+again:
521
+		n=epoll_wait(h->epfd, h->ep_array, h->fd_no, t*1000);
522
+		if (n==-1){
523
+			if (errno==EINTR) goto again; /* signal, ignore it */
524
+			else{
525
+				LOG(L_ERR, "ERROR:io_wait_loop_epoll_et: epoll_wait:"
526
+						" %s [%d]\n", strerror(errno), errno);
527
+				goto error;
528
+			}
529
+		}
530
+		for (r=0; r<n; r++){
531
+			while((handle_io((struct fd_map*)h->ep_array[r].data.ptr, -1)>0)
532
+					&& repeat);
533
+		}
534
+error:
535
+	return n;
536
+}
537
+#endif
538
+
539
+
540
+
541
+#ifdef HAVE_SIGIO_RT
542
+/* sigio rt version has no repeat (it doesn't make sense)*/
543
+inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t)
544
+{
545
+	int n;
546
+	int ret;
547
+	struct timespec ts;
548
+	siginfo_t siginfo;
549
+	int sigio_band;
550
+	int sigio_fd;
551
+	struct fd_map* fm;
552
+	
553
+	
554
+	ret=1; /* 1 event per call normally */
555
+	ts.tv_sec=t;
556
+	ts.tv_nsec=0;
557
+	if (!sigismember(&h->sset, h->signo) || !sigismember(&h->sset, SIGIO)){
558
+		LOG(L_CRIT, "BUG: io_wait_loop_sigio_rt: the signal mask"
559
+				" is not properly set!\n");
560
+		goto error;
561
+	}
562
+
563
+again:
564
+	n=sigtimedwait(&h->sset, &siginfo, &ts);
565
+	if (n==-1){
566
+		if (errno==EINTR) goto again; /* some other signal, ignore it */
567
+		else if (errno==EAGAIN){ /* timeout */
568
+			ret=0;
569
+			goto end;
570
+		}else{
571
+			LOG(L_ERR, "ERROR: io_wait_loop_sigio_rt: sigtimed_wait"
572
+					" %s [%d]\n", strerror(errno), errno);
573
+			goto error;
574
+		}
575
+	}
576
+	if (n!=SIGIO){
577
+#ifdef SIGINFO64_WORKARROUND
578
+		/* on linux siginfo.si_band is defined as long in userspace
579
+		 * and as int kernel => on 64 bits things will break!
580
+		 * (si_band will include si_fd, and si_fd will contain
581
+		 *  garbage)
582
+		 *  see /usr/src/linux/include/asm-generic/siginfo.h and
583
+		 *      /usr/include/bits/siginfo.h
584
+		 * -- andrei */
585
+		if (sizeof(siginfo.si_band)>sizeof(int)){
586
+			sigio_band=*((int*)&siginfo.si_band);
587
+			sigio_fd=*(((int*)&siginfo.si_band)+1);
588
+		}else
589
+#endif
590
+		{
591
+			sigio_band=siginfo.si_band;
592
+			sigio_fd=siginfo.si_fd;
593
+		}
594
+		if (siginfo.si_code==SI_SIGIO){
595
+			/* old style, we don't know the event (linux 2.2.?) */
596
+			LOG(L_WARN, "WARNING: io_wait_loop_sigio_rt: old style sigio"
597
+					" interface\n");
598
+			fm=get_fd_map(h, sigio_fd);
599
+			/* we can have queued signals generated by fds not watched
600
+			 * any more, or by fds in transition, to a child => ignore them*/
601
+			if (fm->type)
602
+				handle_io(fm, -1);
603
+		}else{
604
+#ifdef EXTRA_DEBUG
605
+			DBG("io_wait_loop_sigio_rt: siginfo: signal=%d (%d),"
606
+					" si_code=%d, si_band=0x%x,"
607
+					" si_fd=%d\n",
608
+					siginfo.si_signo, n, siginfo.si_code, 
609
+					(unsigned)sigio_band,
610
+					sigio_fd);
611
+#endif
612
+			if (sigio_band&(POLL_IN|POLL_ERR)){
613
+				fm=get_fd_map(h, sigio_fd);
614
+				/* we can have queued signals generated by fds not watched
615
+			 	 * any more, or by fds in transition, to a child 
616
+				 * => ignore them */
617
+				if (fm->type)
618
+					handle_io(fm, -1);
619
+			}
620
+		}
621
+	}else{
622
+		/* signal queue overflow 
623
+		 * TODO: increase signal queue size: 2.4x /proc/.., 2.6x -rlimits */
624
+		LOG(L_WARN, "WARNING: io_wait_loop_sigio_rt: signal queue overflowed"
625
+					"- falling back to poll\n");
626
+		/* clear real-time signal queue
627
+		 * both SIG_IGN and SIG_DFL are needed , it doesn't work
628
+		 * only with SIG_DFL  */
629
+		if (signal(h->signo, SIG_IGN)==SIG_ERR){
630
+			LOG(L_CRIT, "BUG: do_poll: couldn't reset signal to IGN\n");
631
+		}
632
+		
633
+		if (signal(h->signo, SIG_DFL)==SIG_ERR){
634
+			LOG(L_CRIT, "BUG: do_poll: couldn't reset signal to DFL\n");
635
+		}
636
+		/* falling back to normal poll */
637
+		ret=io_wait_loop_poll(h, -1, 1);
638
+	}
639
+end:
640
+	return ret;
641
+error:
642
+	return -1;
643
+}
644
+#endif
645
+
646
+
647
+
648
+/* init */
649
+
650
+
651
+/* initializes the static vars/arrays
652
+ * params:      h - pointer to the io_wait_h that will be initialized
653
+ *         max_fd - maximum allowed fd number
654
+ *         poll_m - poll method (0 for automatic best fit)
655
+ */
656
+int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method);
657
+
658
+/* destroys everything init_io_wait allocated */
659
+void destroy_io_wait(io_wait_h* h);
660
+
661
+
662
+#endif
... ...
@@ -56,6 +56,9 @@
56 56
  *               crashed childvwhich still holds the lock  (andrei)
57 57
  *  2004-12-02  removed -p, extended -l to support [proto:]address[:port],
58 58
  *               added parse_phostport, parse_proto (andrei)
59
+ *  2005-06-16  always record the pid in pt[process_no].pid twice: once in the
60
+ *               parent & once in the child to avoid a short window when one
61
+ *               of them might use it "unset" (andrei)
59 62
  */
60 63
 
61 64
 
... ...
@@ -111,6 +114,7 @@
111 111
 #include "script_cb.h"
112 112
 #include "ut.h"
113 113
 #ifdef USE_TCP
114
+#include "poll_types.h"
114 115
 #include "tcp_init.h"
115 116
 #ifdef USE_TLS
116 117
 #include "tls/tls_init.h"
... ...
@@ -155,7 +159,8 @@ Options:\n\
155 155
     -E           Log to stderr\n"
156 156
 #ifdef USE_TCP
157 157
 "    -T           Disable tcp\n\
158
-    -N           Number of tcp child processes (default: equal to `-n`)\n"
158
+    -N           Number of tcp child processes (default: equal to `-n`)\n\
159
+    -W           poll method\n"
159 160
 #endif
160 161
 "    -V           Version number\n\
161 162
     -h           This help message\n\
... ...
@@ -190,6 +195,9 @@ void print_ct_constants()
190 190
 			" MAX_URI_SIZE %d, BUF_SIZE %d\n",
191 191
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE, 
192 192
 		BUF_SIZE );
193
+#ifdef USE_TCP
194
+	printf("poll method support: %s.\n", poll_support);
195
+#endif
193 196
 }
194 197
 
195 198
 /* debugging function */
... ...
@@ -862,6 +870,9 @@ int main_loop()
862 862
 				
863 863
 				if (pid==0){
864 864
 					/* child */
865
+					/* record pid twice to avoid the child using it, before
866
+					 * parent gets a chance to set it*/
867
+					pt[process_no].pid=getpid();
865 868
 					/* timer!*/
866 869
 					/* process_bit = 0; */
867 870
 					if (init_child(PROC_TIMER) < 0) {
... ...
@@ -1021,6 +1032,9 @@ int main_loop()
1021 1021
 						unix_tcp_sock=sockfd[1];
1022 1022
 					}
1023 1023
 #endif
1024
+					/* record pid twice to avoid the child using it, before
1025
+					 * parent gets a chance to set it*/
1026
+					pt[process_no].pid=getpid();
1024 1027
 					bind_address=si; /* shortcut */
1025 1028
 					if (init_child(i + 1) < 0) {
1026 1029
 						LOG(L_ERR, "init_child failed\n");
... ...
@@ -1084,6 +1098,9 @@ int main_loop()
1084 1084
 				unix_tcp_sock=sockfd[1];
1085 1085
 			}
1086 1086
 #endif
1087
+			/* record pid twice to avoid the child using it, before
1088
+			 * parent gets a chance to set it*/
1089
+			pt[process_no].pid=getpid();
1087 1090
 			if (init_child(PROC_TIMER) < 0) {
1088 1091
 				LOG(L_ERR, "timer: init_child failed\n");
1089 1092
 				goto error;
... ...
@@ -1120,6 +1137,9 @@ int main_loop()
1120 1120
 			}else if (pid==0){
1121 1121
 				/* child */
1122 1122
 				/* is_main=0; */
1123
+				/* record pid twice to avoid the child using it, before
1124
+				 * parent gets a chance to set it*/
1125
+				pt[process_no].pid=getpid();
1123 1126
 				if (init_child(PROC_TCP_MAIN) < 0) {
1124 1127
 					LOG(L_ERR, "tcp_main: error in init_child\n");
1125 1128
 					goto error;
... ...
@@ -1215,7 +1235,7 @@ int main(int argc, char** argv)
1215 1215
 #ifdef STATS
1216 1216
 	"s:"
1217 1217
 #endif
1218
-	"f:cm:b:l:n:N:rRvdDETVhw:t:u:g:P:G:i:x:";
1218
+	"f:cm:b:l:n:N:rRvdDETVhw:t:u:g:P:G:i:x:W:";
1219 1219
 	
1220 1220
 	while((c=getopt(argc,argv,options))!=-1){
1221 1221
 		switch(c){
... ...
@@ -1308,6 +1328,18 @@ int main(int argc, char** argv)
1308 1308
 					fprintf(stderr,"WARNING: tcp support not compiled in\n");
1309 1309
 #endif
1310 1310
 					break;
1311
+			case 'W':
1312
+#ifdef USE_TCP
1313
+					tcp_poll_method=get_poll_type(optarg);
1314
+					if (tcp_poll_method==POLL_NONE){
1315
+						fprintf(stderr, "bad poll method name: -W %s\ntry "
1316
+										"one of %s.\n", optarg, poll_support);
1317
+						goto error;
1318
+					}
1319
+#else
1320
+					fprintf(stderr,"WARNING: tcp support not compiled in\n");
1321
+#endif
1322
+					break;
1311 1323
 			case 'V':
1312 1324
 					printf("version: %s\n", version);
1313 1325
 					printf("flags: %s\n", flags );
... ...
@@ -309,13 +309,13 @@ inline static int char_msg_val( struct sip_msg *msg, char *cv )
309 309
 inline static char* get_body(struct sip_msg *msg)
310 310
 {
311 311
 	int offset;
312
-	int len;
312
+	unsigned int len;
313 313
 
314 314
 	if ( parse_headers(msg, HDR_EOH_F, 0)==-1 )
315 315
 		return 0;
316 316
 
317 317
 	if (msg->unparsed){
318
-		len=(int)(msg->unparsed-msg->buf);
318
+		len=(unsigned int)(msg->unparsed-msg->buf);
319 319
 	}else return 0;
320 320
 	if ((len+2<=msg->len) && (strncmp(CRLF,msg->unparsed,CRLF_LEN)==0) )
321 321
 		offset = CRLF_LEN;
... ...
@@ -31,6 +31,8 @@
31 31
   *  2003-02-20  added solaris support (! HAVE_MSGHDR_MSG_CONTROL) (andrei)
32 32
   *  2003-11-03  added send_all, recv_all  and updated send/get_fd
33 33
   *               to handle signals  (andrei)
34
+  *  2005-06-13  added flags to recv_all & receive_fd, to allow full blocking
35
+  *              or semi-nonblocking mode (andrei)
34 36
   */
35 37
 
36 38
 #ifdef USE_TCP
... ...
@@ -47,29 +49,55 @@
47 47
 
48 48
 
49 49
 /* receive all the data or returns error (handles EINTR etc.)
50
+ * params: socket
51
+ *         data     - buffer for the results
52
+ *         data_len - 
53
+ *         flags    - recv flags for the first recv (see recv(2)), only
54
+ *                    0, MSG_WAITALL and MSG_DONTWAIT make sense
55
+ * if flags is set to MSG_DONWAIT (or to 0 and the socket fd is non-blocking),
56
+ * and if no data is queued on the fd, recv_all will not wait (it will 
57
+ * return error and set errno to EAGAIN/EWOULDBLOCK). However if even 1 byte
58
+ *  is queued, the call will block until the whole data_len was read or an
59
+ *  error or eof occured ("semi-nonblocking" behaviour,  some tcp code
60
+ *   counts on it).
61
+ * if flags is set to MSG_WAITALL it will block even if no byte is available.
62
+ *