Browse code

port numbers different now for remote and local

Jiri Kuthan authored on 20/11/2001 06:26:49
Showing 13 changed files
... ...
@@ -32,6 +32,8 @@ DEFS=-DNOCR -DMACROEATER -DSTATS -DOLD_PARSER -DDNS_IP_HACK #-DNO_DEBUG
32 32
 #-DNO_LOG
33 33
 
34 34
 PROFILE=  # -pg #set this if you want profiling
35
+#mode=release
36
+mode=debug
35 37
 
36 38
 # platform dependent settings
37 39
 
... ...
@@ -40,8 +42,15 @@ ARCH = $(shell uname -s)
40 40
 #common
41 41
 CC=gcc
42 42
 LD=gcc
43
-CFLAGS=-O2 -Wcast-align $(PROFILE) -Winline#-Wmissing-prototypes 
44
-LDFLAGS=-Wl,-O2 -Wl,-E $(PROFILE)
43
+
44
+ifeq ( mode, release )
45
+	CFLAGS=-O2 -Wcast-align $(PROFILE) -Winline#-Wmissing-prototypes 
46
+	LDFLAGS=-Wl,-O2 -Wl,-E $(PROFILE)
47
+else
48
+	CFLAGS=-g
49
+	LDFLAGS=-g
50
+endif
51
+
45 52
 LEX=flex
46 53
 YACC=bison
47 54
 YACC_FLAGS=-d -b cfg
... ...
@@ -127,3 +136,5 @@ proper: clean
127 127
 
128 128
 include $(depends)
129 129
 
130
+dbg: ser
131
+	gdb -command debug.gdb
... ...
@@ -81,6 +81,7 @@ LISTEN		listen
81 81
 DNS		 dns
82 82
 REV_DNS	 rev_dns
83 83
 PORT	port
84
+STAT	statistics
84 85
 MAXBUFFER maxbuffer
85 86
 CHILDREN children
86 87
 CHECK_VIA	check_via
... ...
@@ -154,6 +155,7 @@ EAT_ABLE	[\ \t\b\r]
154 154
 <INITIAL>{DNS}	{ count(); yylval.strval=yytext; return DNS; }
155 155
 <INITIAL>{REV_DNS}	{ count(); yylval.strval=yytext; return REV_DNS; }
156 156
 <INITIAL>{PORT}	{ count(); yylval.strval=yytext; return PORT; }
157
+<INITIAL>{STAT}	{ count(); yylval.strval=yytext; return STAT; }
157 158
 <INITIAL>{MAXBUFFER}	{ count(); yylval.strval=yytext; return MAXBUFFER; }
158 159
 <INITIAL>{CHILDREN}	{ count(); yylval.strval=yytext; return CHILDREN; }
159 160
 <INITIAL>{CHECK_VIA}	{ count(); yylval.strval=yytext; return CHECK_VIA; }
... ...
@@ -19,6 +19,7 @@
19 19
 #include "dprint.h"
20 20
 #include "sr_module.h"
21 21
 
22
+
22 23
 #ifdef DEBUG_DMALLOC
23 24
 #include <dmalloc.h>
24 25
 #endif
... ...
@@ -73,6 +74,7 @@ void* f_tmp;
73 73
 %token DNS
74 74
 %token REV_DNS
75 75
 %token PORT
76
+%token STAT
76 77
 %token CHILDREN
77 78
 %token CHECK_VIA
78 79
 %token LOADMODULE
... ...
@@ -147,6 +149,7 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
147 147
 		| REV_DNS EQUAL NUMBER { received_dns|= ($3)?DO_REV_DNS:0; }
148 148
 		| REV_DNS EQUAL error { yyerror("boolean value expected"); }
149 149
 		| PORT EQUAL NUMBER   { port_no=$3; }
150
+		| STAT EQUAL STRING { stat_file=$3; }
150 151
 		| MAXBUFFER EQUAL NUMBER { maxbuffer=$3; }
151 152
 		| MAXBUFFER EQUAL error { yyerror("number expected"); }
152 153
 		| PORT EQUAL error    { yyerror("number expected"); } 
... ...
@@ -431,20 +431,20 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
431 431
 
432 432
 	p->tx++;
433 433
 	p->tx_bytes+=new_len;
434
-#ifdef STATS
435
-	stats.total_tx++;
436
-#endif
437 434
 
438 435
 	if (udp_send(new_buf, new_len, (struct sockaddr*) to,
439 436
 				sizeof(struct sockaddr_in))==-1){
440 437
 			p->errors++;
441 438
 			p->ok=0;
439
+#ifdef STATS
440
+			update_fail_on_send;
441
+#endif
442 442
 			goto error;
443 443
 	} 
444 444
 #ifdef STATS
445
-	else stats.ok_tx_rq++;
445
+	/* sent requests stats */
446
+	else update_sent_request( msg->first_line.u.request.method_value );
446 447
 #endif
447
-
448 448
 	free(new_buf);
449 449
 	free(to);
450 450
 	/* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
... ...
@@ -552,17 +552,19 @@ int forward_reply(struct sip_msg* msg)
552 552
 		to->sin_port = (msg->via2.port)?htons(msg->via2.port):htons(SIP_PORT);
553 553
 		to->sin_addr.s_addr=*((long*)he->h_addr_list[0]);
554 554
 
555
-#ifdef STATS
556
-		stats.total_tx++;
557
-#endif
558 555
 #ifdef DNS_IP_HACK
559 556
 	}
560 557
 #endif
561 558
 	if (udp_send(new_buf,new_len, (struct sockaddr*) to, 
562
-					sizeof(struct sockaddr_in))==-1)
559
+					sizeof(struct sockaddr_in))==-1) 
560
+	{
561
+#ifdef STATS
562
+		update_fail_on_send;
563
+#endif
563 564
 		goto error;
565
+	}
564 566
 #ifdef STATS
565
-	else stats.ok_tx_rs++;
567
+	else update_sent_response(  msg->first_line.u.reply.statusclass );
566 568
 #endif
567 569
 	
568 570
 	free(new_buf);
... ...
@@ -15,6 +15,7 @@
15 15
 
16 16
 
17 17
 extern char * cfg_file;
18
+extern char *stat_file;
18 19
 extern unsigned short port_no;
19 20
 extern char port_no_str[];
20 21
 extern int port_no_str_len;
... ...
@@ -13,6 +13,10 @@
13 13
 #include <netinet/in.h>
14 14
 #include <arpa/inet.h>
15 15
 #include <sys/utsname.h>
16
+#include <sys/types.h>
17
+#include <sys/mman.h>
18
+#include <sys/fcntl.h>
19
+#include <sys/time.h>
16 20
 
17 21
 #include "config.h"
18 22
 #include "dprint.h"
... ...
@@ -26,8 +30,6 @@
26 26
 #include "stats.h"
27 27
 #endif
28 28
 
29
-
30
-
31 29
 #ifdef DEBUG_DMALLOC
32 30
 #include <dmalloc.h>
33 31
 #endif
... ...
@@ -94,8 +96,11 @@ Options:\n\
94 94
     -V           Version number\n\
95 95
     -h           This help message\n\
96 96
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
97
-                 auto-probing procedure even if  OS allows\n\
98
-";
97
+                 auto-probing procedure even if  OS allows\n"
98
+#ifdef STATS
99
+"    -s file	 File to which statistics is dumped (disabled otherwise)\n"
100
+#endif
101
+;
99 102
 
100 103
 /* print compile-time constants */
101 104
 void print_ct_constants()
... ...
@@ -127,9 +132,9 @@ char* cfg_file = 0;
127 127
 unsigned short port_no = 0; /* port on which we listen */
128 128
 char port_no_str[MAX_PORT_LEN];
129 129
 int port_no_str_len=0;
130
-unsigned int maxbuffer = 128*1024; /* maximum buffer size we do not want to exceed
131
-				      durig the auto-probing procedure; may be
132
-				      re-configured */
130
+unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do not want to exceed
131
+				      		durig the auto-probing procedure; may be
132
+				      		re-configured */
133 133
 int children_no = 0;           /* number of children processing requests */
134 134
 int debug = 0;
135 135
 int dont_fork = 0;
... ...
@@ -151,11 +156,6 @@ int process_no = 0;
151 151
 /* cfg parsing */
152 152
 int cfg_errors=0;
153 153
 
154
-#ifdef STATS
155
-/* jku: RX/TX statistics -- remember, they are process specific */
156
-struct stats_s stats;
157
-#endif
158
-
159 154
 
160 155
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
161 156
 		    (normally it shouldn't  be bigger  than 3) */
... ...
@@ -226,6 +226,9 @@ int main_loop()
226 226
 
227 227
 
228 228
 	if (dont_fork){
229
+#ifdef STATS
230
+		setstats( 0 );
231
+#endif
229 232
 		/* only one address */
230 233
 		if (udp_init(addresses[0],port_no)==-1) goto error;
231 234
 		/* receive loop */
... ...
@@ -241,6 +244,9 @@ int main_loop()
241 241
 				}
242 242
 				if (pid==0){
243 243
 					/* child */
244
+#ifdef STATS
245
+					setstats( i );
246
+#endif
244 247
 					return udp_rcv_loop();
245 248
 				}
246 249
 			}
... ...
@@ -260,6 +266,7 @@ int main_loop()
260 260
 
261 261
 }
262 262
 
263
+
263 264
 /* added by jku; allows for regular exit on a specific signal;
264 265
    good for profiling which only works if exited regularly and
265 266
    not by default signal handlers
... ...
@@ -267,17 +274,25 @@ int main_loop()
267 267
 
268 268
 static void sig_usr(int signo)
269 269
 {
270
-	DPrint("INT received, program terminates\n");
270
+	if (signo==SIGINT) {	/* exit gracefuly */
271 271
 #ifdef STATS
272
-	DPrint("ok_rx_rq\t%d\nok_rx_rs\t%d\nok_tx_rq\t%d\nok_tx_rs\t%d\ntotal_rx\t%d\ntotal_tx\t%d\n\n",
273
-		stats.ok_rx_rq, stats.ok_rx_rs, stats.ok_tx_rq, stats.ok_tx_rs, stats.total_rx, stats.total_tx );
274
-	DPrint("Thank you for flying ser\n");
272
+		/* print statistics on exit only for the first process */
273
+
274
+		if (stats->process_index==0 && stat_file )
275
+			if (dump_all_statistic()==0)
276
+				printf("statistic dumped to %s\n", stat_file );
277
+			else
278
+				printf("statistics dump to %s failed\n", stat_file );
275 279
 #endif
276
-	exit(0);
280
+		DPrint("INT received, program terminates\n");
281
+		DPrint("Thank you for flying ser\n");
282
+		exit(0);
283
+	} else if (signo==SIGUSR1) { /* statistic */
284
+		dump_all_statistic();
285
+	}
277 286
 }
278 287
 	
279 288
 	
280
-	
281 289
 int main(int argc, char** argv)
282 290
 {
283 291
 
... ...
@@ -286,20 +301,36 @@ int main(int argc, char** argv)
286 286
 	int c,r;
287 287
 	char *tmp;
288 288
 	struct utsname myname;
289
+	char *options;
289 290
 
290 291
 	/* added by jku: add exit handler */
291 292
         if (signal(SIGINT, sig_usr) == SIG_ERR ) {
292
- 		DPrint("ERROR: no signal handler can be installed\n");
293
+ 		DPrint("ERROR: no SIGINT signal handler can be installed\n");
294
+                goto error;
295
+        }
296
+#ifdef STATS
297
+	if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
298
+                DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
293 299
                 goto error;
294 300
         }
301
+#endif
295 302
 
296 303
 	/* process command line (get port no, cfg. file path etc) */
297 304
 	opterr=0;
298
-	while((c=getopt(argc,argv,"f:p:b:l:n:rRvdDEVh"))!=-1){
305
+	options=
306
+#ifdef STATS
307
+	"s:"
308
+#endif
309
+	"f:p:b:l:n:rRvdDEVh";
310
+	
311
+	while((c=getopt(argc,argv,options))!=-1){
299 312
 		switch(c){
300 313
 			case 'f':
301 314
 					cfg_file=optarg;
302 315
 					break;
316
+			case 's':
317
+					stat_file=optarg;
318
+					break;
303 319
 			case 'p':
304 320
 					port_no=strtol(optarg, &tmp, 10);
305 321
 					if (tmp &&(*tmp)){
... ...
@@ -448,10 +479,6 @@ int main(int argc, char** argv)
448 448
 		names_len[r]=strlen(names[r]);
449 449
 	}
450 450
 
451
-#ifdef STATS
452
-	/* jku: initialize statistic */
453
- 	memset(&stats,0,sizeof(struct stats_s));
454
-#endif
455 451
 	
456 452
 	/* get ips */
457 453
 	printf("Listening on ");
... ...
@@ -467,6 +494,10 @@ int main(int argc, char** argv)
467 467
 				(unsigned short)port_no);
468 468
 	}
469 469
 
470
+#ifdef STATS
471
+	if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
472
+#endif
473
+
470 474
 	/* init_daemon? */
471 475
 	if (!dont_fork){
472 476
 		if ( daemonize(argv[0]) <0 ) goto error;
... ...
@@ -34,8 +34,9 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
34 34
 	char* third;
35 35
 	char* nl;
36 36
 	int offset;
37
-	int l;
37
+	/* int l; */
38 38
 	char* end;
39
+	char s1,s2,s3;
39 40
 	
40 41
 	/* grammar:
41 42
 		request  =  method SP uri SP version CRLF
... ...
@@ -46,37 +47,72 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
46 46
 
47 47
 	end=buffer+len;
48 48
 	/* see if it's a reply (status) */
49
-	tmp=eat_token(buffer, len);
50
-	if ((tmp==buffer)||(tmp>=end)){
51
-		LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
49
+
50
+	/* jku  -- parse well-known methods */
51
+
52
+	/* drop messages which are so short they are for sure useless;
53
+           utilize knowledge of minimum size in parsing the first
54
+	   token 
55
+        */
56
+	if (len <=16 ) {
57
+		LOG(L_INFO, "ERROR: parse_first_line: message too short\n");
52 58
 		goto error1;
53 59
 	}
54
-	l=tmp-buffer;
55
-	if ((SIP_VERSION_LEN==l) &&
56
-		(memcmp(buffer,SIP_VERSION,l)==0)){
57
-		
58
-		fl->type=SIP_REPLY;
59
-	}else{
60
+
61
+	tmp=buffer;
62
+  	/* is it perhaps a reply, ie does it start with "SIP...." ? */
63
+	if ( 	(*tmp=='S' || *tmp=='s') && 
64
+		strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
65
+		(*(tmp+SIP_VERSION_LEN)==' ')) {
66
+			fl->type=SIP_REPLY;
67
+			fl->u.reply.version.len=SIP_VERSION_LEN;
68
+			tmp=buffer+SIP_VERSION_LEN;
69
+	} else IFISMETHOD( INVITE, 'I' )
70
+	else IFISMETHOD( CANCEL, 'C')
71
+	else IFISMETHOD( ACK, 'A' )
72
+	else IFISMETHOD( BYE, 'B' )
73
+	/* if you want to add another method XXX, include METHOD_XXX in
74
+           H-file (this is the value which you will take later in
75
+           processing and define XXX_LEN as length of method name;
76
+	   then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
77
+	   latter; everything must be capitals
78
+	*/
79
+	else {
80
+		/* neither reply, nor any of known method requests, 
81
+		   let's believe it is an unknown method request
82
+        	*/
83
+		tmp=eat_token_end(buffer,buffer+len);
84
+		if ((tmp==buffer)||(tmp>=end)){
85
+			LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
86
+			goto error1;
87
+		}
88
+		if (*tmp!=' ') {
89
+			LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
90
+			goto error1;
91
+		}
60 92
 		fl->type=SIP_REQUEST;
93
+		fl->u.request.method_value=METHOD_OTHER;
94
+		fl->u.request.method.len=tmp-buffer;
61 95
 	}
62
-	
63
-	offset=l;
64
-	second=eat_space(tmp, len-offset);
65
-	offset+=second-tmp;
66
-	if ((second==tmp)||(tmp>=end)){
67
-		goto error;
68
-	}
69
-	*tmp=0; /* mark the end of the token */
70
-	fl->u.request.method.s=buffer;
71
-	fl->u.request.method.len=l;
96
+
97
+
98
+	/* identifying type of message over now; 
99
+	   tmp points at space after; go ahead */
100
+
101
+	fl->u.request.method.s=buffer;  /* store ptr to first token */
102
+	(*tmp)=0;			/* mark the 1st token end */
103
+	second=tmp+1;			/* jump to second token */
104
+	offset=second-buffer;
105
+
106
+/* EoJku */
72 107
 	
73 108
 	/* next element */
74
-	tmp=eat_token(second, len-offset);
109
+	tmp=eat_token_end(second, second+len-offset);
75 110
 	if (tmp>=end){
76 111
 		goto error;
77 112
 	}
78 113
 	offset+=tmp-second;
79
-	third=eat_space(tmp, len-offset);
114
+	third=eat_space_end(tmp, tmp+len-offset);
80 115
 	offset+=third-tmp;
81 116
 	if ((third==tmp)||(tmp>=end)){
82 117
 		goto error;
... ...
@@ -85,20 +121,41 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
85 85
 	fl->u.request.uri.s=second;
86 86
 	fl->u.request.uri.len=tmp-second;
87 87
 
88
+	/* jku: parse status code */
89
+	if (fl->type==SIP_REPLY) {
90
+		if (fl->u.request.uri.len!=3) {
91
+			LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %s\n",
92
+				second );
93
+			goto error;
94
+		}
95
+		s1=*second; s2=*(second+1);s3=*(second+2);
96
+		if (s1>='0' && s1<='9' && 
97
+		    s2>='0' && s2<='9' &&
98
+		    s3>='0' && s3<='9' ) {
99
+			fl->u.reply.statusclass=s1-'0';
100
+			fl->u.reply.statuscode=fl->u.reply.statusclass*100+10*(s2-'0')+(s3-'0');
101
+		} else {
102
+			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
103
+				second );
104
+			goto error;
105
+		}
106
+	}
107
+	/* EoJku */
108
+
88 109
 	/*  last part: for a request it must be the version, for a reply
89 110
 	 *  it can contain almost anything, including spaces, so we don't care
90 111
 	 *  about it*/
91 112
 	if (fl->type==SIP_REQUEST){
92
-		tmp=eat_token(third,len-offset);
113
+		tmp=eat_token_end(third,third+len-offset);
93 114
 		offset+=tmp-third;
94 115
 		if ((tmp==third)||(tmp>=end)){
95 116
 			goto error;
96 117
 		}
97
-		if (! is_empty(tmp, len-offset)){
118
+		if (! is_empty_end(tmp, tmp+len-offset)){
98 119
 			goto error;
99 120
 		}
100 121
 	}else{
101
-		tmp=eat_token2(third,len-offset,'\r'); /* find end of line 
122
+		tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
102 123
 												  ('\n' or '\r') */
103 124
 		if (tmp>=end){ /* no crlf in packet => invalid */
104 125
 			goto error;
... ...
@@ -240,22 +297,22 @@ char* get_hdr_field(char *buffer, unsigned int len, struct hdr_field*  hdr_f)
240 240
 		return tmp;
241 241
 	}
242 242
 	
243
-	tmp=eat_token2(buffer, len, ':');
243
+	tmp=eat_token2_end(buffer, buffer+len, ':');
244 244
 	if ((tmp==buffer) || (tmp-buffer==len) ||
245
-		(is_empty(buffer, tmp-buffer))|| (*tmp!=':')){
245
+		(is_empty_end(buffer, tmp))|| (*tmp!=':')){
246 246
 		hdr_f->type=HDR_ERROR;
247 247
 		goto error;
248 248
 	}
249 249
 	*tmp=0;
250 250
 	/* take care of possible spaces (e.g: "Via  :") */
251
-	tmp2=eat_token(buffer, tmp-buffer);
251
+	tmp2=eat_token_end(buffer, tmp);
252 252
 	/* in the worst case tmp2=buffer+tmp-buffer=tmp */
253 253
 	*tmp2=0;
254 254
 	l=tmp2-buffer;
255 255
 	if (tmp2<tmp){
256 256
 		tmp2++;
257 257
 		/* catch things like: "Via foo bar:" */
258
-		tmp2=eat_space(tmp2, tmp-tmp2);
258
+		tmp2=eat_space_end(tmp2, tmp);
259 259
 		if (tmp2!=tmp){
260 260
 			hdr_f->type=HDR_ERROR;
261 261
 			goto error;
... ...
@@ -492,33 +549,33 @@ char* parse_via_body(char* buffer,unsigned int len, struct via_body * vb)
492 492
 
493 493
 	name=version=transport=comment=params=hostport=next_via=host.s=0;
494 494
 	name_len=version_len=transport_len=comment_len=params_len=host.len=0;
495
-	name=eat_space(buffer, len);
495
+	name=eat_space_end(buffer, buffer+len);
496 496
 	if (name-buffer==len) goto error;
497 497
 	offset=name-buffer;
498 498
 	tmp=name;
499 499
 
500
-	version=eat_token2(tmp,len-offset,'/');
500
+	version=eat_token2_end(tmp,tmp+len-offset,'/');
501 501
 	if (version+1-buffer>=len) goto error;
502 502
 	*version=0;
503 503
 	name_len=version-name;
504 504
 	version++;
505 505
 	offset+=version-tmp;
506 506
 	
507
-	transport=eat_token2(tmp,len-offset,'/');
507
+	transport=eat_token2_end(tmp,tmp+len-offset,'/');
508 508
 	if (transport+1-buffer>=len) goto error;
509 509
 	*transport=0;
510 510
 	version_len=transport-version;
511 511
 	transport++;
512 512
 	offset+=transport-tmp;
513 513
 	
514
-	tmp=eat_token(transport,len-offset);
514
+	tmp=eat_token_end(transport,transport+len-offset);
515 515
 	if (tmp+1-buffer>=len) goto error;
516 516
 	*tmp=0;
517 517
 	transport_len=tmp-transport;
518 518
 	tmp++;
519 519
 	offset+=tmp-transport;
520 520
 	
521
-	hostport=eat_space(tmp,len-offset);
521
+	hostport=eat_space_end(tmp,tmp+len-offset);
522 522
 	if (hostport+1-buffer>=len) goto error;
523 523
 	offset+=hostport-tmp;
524 524
 
... ...
@@ -18,7 +18,21 @@ enum {	HDR_EOH=-1, HDR_ERROR=0, HDR_OTHER,
18 18
 		HDR_MAXFORWARDS, HDR_ROUTE
19 19
 	};
20 20
 
21
-
21
+#define INVITE_LEN	6
22
+#define ACK_LEN		3
23
+#define CANCEL_LEN	6
24
+#define BYE_LEN		3
25
+enum { METHOD_OTHER, METHOD_INVITE, METHOD_CANCEL, METHOD_ACK, METHOD_BYE };
26
+
27
+#define IFISMETHOD(methodname,firstchar)                                  \
28
+if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
29
+        strncasecmp( tmp+1, #methodname +1, methodname##_LEN-1)==0 &&     \
30
+        *(tmp+methodname##_LEN)==' ') {                                   \
31
+                fl->type=SIP_REQUEST;                                     \
32
+                fl->u.request.method.len=methodname##_LEN;                \
33
+                fl->u.request.method_value=METHOD_##methodname;           \
34
+                tmp=buffer+methodname##_LEN;                              \
35
+}
22 36
 
23 37
 
24 38
 #define VIA_PARSE_OK	1
... ...
@@ -35,11 +49,13 @@ struct msg_start{
35 35
 			str method;
36 36
 			str uri;
37 37
 			str version;
38
+			short method_value;
38 39
 		}request;
39 40
 		struct {
40 41
 			str version;
41 42
 			str status;
42 43
 			str reason;
44
+			unsigned short statusclass, statuscode;
43 45
 		}reply;
44 46
 	}u;
45 47
 };
... ...
@@ -41,6 +41,9 @@ char* eat_line(char* buffer, unsigned int len)
41 41
 
42 42
 /* returns pointer to first non  white char or after the end  of the buffer */
43 43
 
44
+/* MACROEATER no more optional */
45
+
46
+/*
44 47
 #ifndef MACROEATER
45 48
 
46 49
 char* eat_space(char* buffer, unsigned int len)
... ...
@@ -52,7 +55,7 @@ char* eat_space(char* buffer, unsigned int len)
52 52
 }
53 53
 
54 54
 
55
-/* returns pointer after the token (first whitespace char or CR/LF) */
55
+// returns pointer after the token (first whitespace char or CR/LF) 
56 56
 char* eat_token(char* buffer, unsigned int len)
57 57
 {
58 58
 	char *p;
... ...
@@ -65,7 +68,7 @@ char* eat_token(char* buffer, unsigned int len)
65 65
 
66 66
 
67 67
 
68
-/* returns pointer after the token (first delim char or CR/LF) */
68
+// returns pointer after the token (first delim char or CR/LF)
69 69
 char* eat_token2(char* buffer, unsigned int len, char delim)
70 70
 {
71 71
 	char *p;
... ...
@@ -75,18 +78,8 @@ char* eat_token2(char* buffer, unsigned int len, char delim)
75 75
 		p++);
76 76
 	return p;
77 77
 }
78
-
79
-/* EoMACROEATER */
80 78
 #endif
79
+*/
81 80
 
81
+/* EoMACROEATER */
82 82
 
83
-
84
-/* returns true if line started  at buffer contains only white space */
85
-int is_empty(char* buffer, unsigned int len)
86
-{
87
-	char *p;
88
-	
89
-	p=eat_space(buffer, len);
90
-	if ((p < buffer+len ) && (*p=='\r' || *p=='\n')) return 1;
91
-	return 0;
92
-}
... ...
@@ -6,36 +6,47 @@
6 6
 #define parser_f_h
7 7
 
8 8
 char* eat_line(char* buffer, unsigned int len);
9
+
10
+/* macro now
9 11
 int is_empty(char* buffer, unsigned int len);
12
+*/
10 13
 
11
-#ifdef MACROEATER
14
+/* MACROEATER no more optional */
15
+/* #ifdef MACROEATER */
12 16
 
13 17
 /* turn the most frequently called functions into macros */
14 18
 
15 19
 
16
-#define eat_space(buffer,len)                                          \
17
-  ( {   char *p;                                                     	\
18
-        for(p=(buffer);(p<(buffer)+(len))&& (*p==' ' || *p=='\t') ;p++);\
20
+#define eat_space_end(buffer,pend)                                       \
21
+  ( {   char *p;                                                 	\
22
+        for(p=(buffer);(p<pend)&& (*p==' ' || *p=='\t') ;p++);		\
19 23
         p;                                                              \
20 24
   } )
21 25
 
22
-#define eat_token(buffer,len)						\
23
-  ( { char *p;								\
24
-      for (p=(buffer);(p<(buffer)+(len))&&				\
26
+#define eat_token_end(buffer,pend)					\
27
+  ( { char *p       ;							\
28
+      for (p=(buffer);(p<pend)&&					\
25 29
                         (*p!=' ')&&(*p!='\t')&&(*p!='\n')&&(*p!='\r');	\
26 30
                 p++);							\
27 31
       p;								\
28 32
   } )
29 33
 
30
-#define eat_token2(buffer,len,delim)					\
31
-  ( { char *p;								\
32
-      for (p=(buffer);(p<(buffer)+(len))&&				\
34
+#define eat_token2_end(buffer,pend,delim)					\
35
+  ( { char *p       ;							\
36
+      for (p=(buffer);(p<pend)&&					\
33 37
                         (*p!=(delim))&&(*p!='\n')&&(*p!='\r');		\
34 38
                 p++);							\
35 39
       p;								\
36 40
   } )
37 41
 
42
+#define is_empty_end(buffer, pend )					\
43
+  ( { char *p;								\
44
+      p=eat_space_end( buffer, pend );					\
45
+      ((p<pend ) && (*p=='\r' || *p=='\n')) ? 1 : 0;			\
46
+  } )
47
+
38 48
 
49
+/*
39 50
 #else
40 51
 
41 52
 
... ...
@@ -43,7 +54,8 @@ char* eat_space(char* buffer, unsigned int len);
43 43
 char* eat_token(char* buffer, unsigned int len);
44 44
 char* eat_token2(char* buffer, unsigned int len, char delim);
45 45
 
46
-/* EoMACROEATER */
47 46
 #endif
47
+*/
48
+/* EoMACROEATER */
48 49
 
49 50
 #endif
... ...
@@ -24,9 +24,8 @@
24 24
 int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
25 25
 {
26 26
 	struct sip_msg msg;
27
-
28 27
 #ifdef STATS
29
-	stats.total_rx++;	
28
+	int skipped = 1;
30 29
 #endif
31 30
 
32 31
 	memset(&msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
... ...
@@ -65,8 +64,8 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
65 65
 			goto error;
66 66
 		}
67 67
 #ifdef STATS
68
-		/* jku -- update statistics  */
69
-		else stats.ok_rx_rq++;	
68
+		/* jku -- update request statistics  */
69
+		else update_received_request(  msg.first_line.u.request.method_value );
70 70
 #endif
71 71
 	}else if (msg.first_line.type==SIP_REPLY){
72 72
 		DBG("msg= reply\n");
... ...
@@ -83,7 +82,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
83 83
 
84 84
 #ifdef STATS
85 85
 		/* jku -- update statistics  */
86
-		stats.ok_rx_rs++;	
86
+		update_received_response(  msg.first_line.u.reply.statusclass );
87 87
 #endif
88 88
 		
89 89
 		/* send the msg */
... ...
@@ -93,11 +92,17 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
93 93
 						(unsigned short) msg.via2.port);
94 94
 		}
95 95
 	}
96
+#ifdef STATS
97
+	skipped = 0;
98
+#endif
96 99
 skip:
97 100
 	if (msg.new_uri.s) { free(msg.new_uri.s); msg.new_uri.len=0; }
98 101
 	if (msg.add_rm) free_lump_list(msg.add_rm);
99 102
 	if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
100 103
 	free(msg.orig);
104
+#ifdef STATS
105
+	if (skipped) update_received_drops;
106
+#endif
101 107
 	return 0;
102 108
 error:
103 109
 	if (msg.new_uri.s) free(msg.new_uri.s);
... ...
@@ -105,6 +110,9 @@ error:
105 105
 	if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
106 106
 	free(msg.orig);
107 107
 error1:
108
+#ifdef STATS
109
+	update_received_drops;
110
+#endif
108 111
 	return -1;
109 112
 }
110 113
 
... ...
@@ -1,22 +1,120 @@
1 1
 #ifndef stats_h
2 2
 #define stats_h
3 3
 
4
+#include <ctype.h>
5
+#include <sys/mman.h>
6
+#include <sys/fcntl.h>
7
+#include <sys/time.h>
8
+#include <time.h>
9
+#include <sys/utsname.h>
10
+#include <stdio.h>
11
+#include <stdlib.h>
12
+#include <errno.h>
13
+
14
+
15
+
4 16
 #ifdef STATS
5 17
 
18
+
6 19
 struct stats_s {
7 20
 
8
-	/* total/valid, received/sent, request/response */
9
-	unsigned long 	ok_rx_rq,
10
-			ok_rx_rs,
11
-			ok_tx_rq,
12
-			ok_tx_rs,
13
-			total_rx,
14
-			total_tx;
21
+	unsigned int	process_index;
22
+	pid_t		pid;
23
+	time_t		start_time;
24
+
25
+	unsigned long 
26
+
27
+	/* received packets */
28
+
29
+	received_requests_inv, 		/* received_requests */
30
+	received_requests_ack,
31
+	received_requests_cnc,
32
+	received_requests_bye,
33
+	received_requests_other,
34
+
35
+	received_responses_1, 		/* received_requests */
36
+	received_responses_2,
37
+	received_responses_3,
38
+	received_responses_4,
39
+	received_responses_5,
40
+	received_responses_6,
41
+	received_responses_other,
42
+
43
+	received_drops, 		/* all messages we received and did not process
44
+					   successfully; reasons include SIP sanity checks 
45
+					   (missing Vias, neither request nor response, 
46
+					   failed parsing), ser errors (malloc, action
47
+					   failure)
48
+					*/
49
+
50
+	/* sent */
51
+
52
+	/* sent_requests */
53
+	sent_requests_inv,
54
+	sent_requests_ack,
55
+	sent_requests_cnc,
56
+	sent_requests_bye,
57
+	sent_requests_other,
58
+
59
+	/* sent responses */
60
+	sent_responses_1,
61
+	sent_responses_2,
62
+	sent_responses_3,
63
+	sent_responses_4,
64
+	sent_responses_5,
65
+	sent_responses_6,
66
+
67
+	failed_on_send;			
68
+			  
15 69
 };
16 70
 
17 71
 
18
-extern struct stats_s stats;
72
+extern struct stats_s *stats;
19 73
 
20
-#endif
74
+void setstats( int child_index );
75
+void dump_statistic( FILE *fp, struct stats_s *istats );
76
+int dump_all_statistic();
77
+int init_stats( int nr_of_processes );
78
+
79
+#define _update_request( method, dir )			\
80
+	{ if (stat_file!=NULL) switch( method ) {	\
81
+          	case METHOD_INVITE: stats->dir##_requests_inv++; break;	\
82
+          	case METHOD_ACK: stats->dir##_requests_ack++; break;		\
83
+          	case METHOD_CANCEL: stats->dir##_requests_cnc++; break;	\
84
+          	case METHOD_BYE: stats->dir##_requests_bye++; break;		\
85
+          	case METHOD_OTHER: stats->dir##_requests_other++; break;	\
86
+          	default: LOG(L_ERR, "ERROR: unknown method in rq stats (%s)\n", #dir);	\
87
+		}	\
88
+        }
89
+
90
+#define update_received_request( method ) _update_request( method, received )
91
+#define update_sent_request( method ) _update_request( method, sent )
92
+
93
+#define         _statusline(class, dir )       case class: stats->dir##_responses_##class++; break;
94
+/*
95
+#define		statusline( class )	_statusline( class, received )
96
+#define		statusline2( class )	_statusline( class, sent )
97
+*/
21 98
 
99
+#define _update_response( statusclass, dir )		\
100
+        { if (stat_file!=NULL)                          \
101
+                switch( statusclass ) {                 \
102
+                        _statusline(1, dir)                   \
103
+                        _statusline(2, dir)                   \
104
+                        _statusline(3, dir)                   \
105
+                        _statusline(4, dir)                   \
106
+                        _statusline(5, dir)                   \
107
+                        _statusline(6, dir)                   \
108
+                        default: LOG(L_INFO, "ERROR: unusual status code received in stats (%s)\n", #dir);    \
109
+                }       \
110
+        }
111
+
112
+#define update_received_response( statusclass ) _update_response( statusclass, received )
113
+#define update_sent_response( statusclass ) _update_response( statusclass, sent )
114
+
115
+#define update_received_drops	{  stats->received_drops++; }
116
+#define update_fail_on_send	{  stats->failed_on_send++; }
117
+
118
+
119
+#endif
22 120
 #endif
23 121
similarity index 78%
24 122
rename from test/shoot.cpp
25 123
rename to test/shoot.c
... ...
@@ -8,45 +8,23 @@ bouquets and brickbats to farhan@hotfoon.com
8 8
 /* changes by jiri@iptel.org; now messages can be really received;
9 9
    status code returned is 2 for some local errors , 0 for success
10 10
    and 1 for remote error -- ICMP/timeout; can be used to test if
11
-   a server is alive; 1xx messages are now ignored
11
+   a server is alive; 1xx messages are now ignored; windows support
12
+   dropped
12 13
 */
13 14
 
14
-/* currently, compiles only for Solaris; Linux returns
15
- /usr/include/regexp.h:131: cannot convert `char *' to `unsigned char *' 
16
-*/
17
-
18
-int 		regerr;
19
-
20
-#define INIT         register char *sp = instring;
21
-#define GETC()       (*sp++)
22
-#define PEEKC()      (*sp)
23
-#define UNGETC(c)    (--sp)
24
-/*#define RETURN(*c)    return; */
25
-#define RETURN(c)    return c;
26
-#define ERROR(c)     regerr
27
-#include <regexp.h>
28
-
29
-
15
+#include <stdlib.h>
30 16
 #include <stdio.h>
17
+#include <sys/types.h>
18
+#include <sys/time.h>
31 19
 #include <string.h>
32 20
 #include <ctype.h>
33 21
 #include <time.h>
34
-#include <sys/types.h>
35
-#include <stdlib.h>
36
-/* windows specific headers */
37
-#ifdef WIN32
38
-#include <windows.h>
39
-#include <winsock.h>
40
-#define close(a) closesocket(a)
41
-#else
42
-/* *nix specific networking headers */
43
-#include <sys/time.h>
44 22
 #include <unistd.h>
45 23
 #include <netdb.h>
46
-#include <arpa/inet.h>
47 24
 #include <sys/socket.h>
48
-#include <netinet/in.h>
49
-#endif
25
+
26
+#include <regex.h>
27
+regex_t* regexp;
50 28
 
51 29
 #define RESIZE		1024
52 30
 
... ...
@@ -67,8 +45,8 @@ long getaddress(char *host)
67 67
 {
68 68
 	int i, dotcount=0;
69 69
 	char *p = host;
70
-	struct hostent		*pent;
71
-	/* struct sockaddr_in	addr; */ /* see the note on portabilit at the end of the routine */
70
+	struct hostent* pent;
71
+	long l, *lp;
72 72
 
73 73
 	/*try understanding if this is a valid ip address
74 74
 	we are skipping the values of the octets specified here.
... ...
@@ -106,11 +84,9 @@ long getaddress(char *host)
106 106
 		exit(2);
107 107
 	}
108 108
 
109
-	/* PORTABILITY-ISSUE: replacing a costly memcpy call with a hack, may not work on 
110
-	some systems.  
111
-	memcpy(&addr.sin_addr, (pent->h_addr), pent->h_length);
112
-	return addr.sin_addr.s_addr; */
113
-	return *((long *)(pent->h_addr));
109
+	lp = (long *) (pent->h_addr);
110
+	l = *lp;
111
+	return l;
114 112
 }
115 113
 
116 114
 
... ...
@@ -129,18 +105,20 @@ at 5 seconds (5000 milliseconds).
129 129
 we are detecting the final response without a '1' as the first
130 130
 letter.
131 131
 */
132
-void shoot(char *buff, long address, int port)
132
+void shoot(char *buff, long address, int lport, int rport )
133 133
 {
134 134
 	struct sockaddr_in	addr;
135 135
 	/* jku - b  server structures */
136 136
 	struct sockaddr_in	sockname;
137 137
 	int ssock;
138
+	/*
138 139
 	char compiledre[ RESIZE ];
140
+	*/
139 141
 	/* jku - e */
140 142
 	int retryAfter = 500, i, len, ret;
141 143
 	int	nretries = 10;
142 144
 	int	sock;
143
-	timeval	tv;
145
+	struct timeval	tv;
144 146
 	fd_set	fd;
145 147
 	char	reply[1600];
146 148
 
... ...
@@ -160,26 +138,28 @@ void shoot(char *buff, long address, int port)
160 160
 
161 161
 	sockname.sin_family=AF_INET;
162 162
 	sockname.sin_addr.s_addr = htonl( INADDR_ANY );
163
-	sockname.sin_port = htons((short)port);
164
-	if (bind( ssock, (sockaddr *) &sockname, sizeof(sockname) )==-1) {
163
+	sockname.sin_port = htons((short)lport);
164
+	if (bind( ssock, (struct sockaddr *) &sockname, sizeof(sockname) )==-1) {
165 165
 		perror("no bind");
166 166
 		exit(2);
167 167
 	}
168 168
 
169 169
 	/* should capture: SIP/2.0 100 Trying */
170
-	compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0');
170
+	/* compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0'); */
171
+	regexp=(regex_t*)malloc(sizeof(regex_t));
172
+	regcomp(regexp, "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", REG_EXTENDED|REG_NOSUB|REG_ICASE); 
171 173
 	
172 174
 
173 175
 	/* jku - e */
174 176
 
175 177
 	addr.sin_addr.s_addr = address;
176
-	addr.sin_port = htons((short)port);
178
+	addr.sin_port = htons((short)rport);
177 179
 	addr.sin_family = AF_INET;
178 180
 	
179 181
 	/* we connect as per the RFC 2543 recommendations
180 182
 	modified from sendto/recvfrom */
181 183
 
182
-	ret = connect(sock, (sockaddr *)&addr, sizeof(addr));
184
+	ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
183 185
 	if (ret==-1) {
184 186
 		perror("no connect");
185 187
 		exit(2);
... ...
@@ -241,7 +221,8 @@ void shoot(char *buff, long address, int port)
241 241
 			puts("/* reply */");
242 242
 			puts(reply);
243 243
 			putchar('\n');
244
-			if (step( reply, compiledre )) {
244
+			/* if (step( reply, compiledre )) { */
245
+			if (regexec((regex_t*)regexp, reply, 0, 0, 0)==0) {
245 246
 				puts(" provisional received; still waiting for a final response\n ");
246 247
 				continue;
247 248
 			} else {
... ...
@@ -266,21 +247,12 @@ int main(int argc, char *argv[])
266 266
 	FILE	*pf;
267 267
 	char	buff[1600];
268 268
 	int		length;
269
-	int		port;
270
-#ifdef WIN32
271
-	WSADATA	wsadata;
272
-	int err = WSAStartup(0x0101, &wsadata);
273
-	if (err != 0)
274
-	{
275
-		printf("shoot cannot be used as TCP/IP is not available.\n");
276
-		exit(0);
277
-	}
278
-#endif
269
+	int	lport=0;
270
+	int	rport=5060;
279 271
 
280
-
281
-	if (argc != 3 && argc != 4)
272
+	if (! (argc >= 3 && argc <= 5))
282 273
 	{
283
-		puts("usage: shoot file host [port]");
274
+		puts("usage: shoot file host [rport] [lport]");
284 275
 		exit(2);
285 276
 	}
286 277
 
... ...
@@ -292,14 +264,21 @@ int main(int argc, char *argv[])
292 292
 	}
293 293
 
294 294
 	/* take the port as 5060 even if it is incorrectly specified */
295
-	if (argc == 4)
295
+	if (argc >= 4)
296 296
 	{
297
-		port = atoi(argv[3]);
298
-		if (!port)
299
-			port = 5060;
297
+		rport = atoi(argv[3]);
298
+		if (!rport) {
299
+			puts("error: non-numerical remote port number");
300
+			exit(1);
301
+		}
302
+		if (argc==5) {
303
+			lport=atoi(argv[4]);
304
+			if (!lport) {
305
+				puts("error: non-numerical local port number");
306
+				exit(1);
307
+			}
308
+		}
300 309
 	}
301
-	else
302
-		port = 5060;
303 310
 
304 311
 	/* file is opened in binary mode so that the cr-lf is preserved */
305 312
 	pf = fopen(argv[1], "rb");
... ...
@@ -317,7 +296,7 @@ int main(int argc, char *argv[])
317 317
 	fclose(pf);
318 318
 	buff[length] = 0;
319 319
 
320
-	shoot(buff, address, port);
320
+	shoot(buff, address, lport, rport );
321 321
 
322 322
 	/* visual studio closes the debug console as soon as the 
323 323
 	program terminates. this is to hold the window from collapsing