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