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 42
 #common
41 43
 CC=gcc
42 44
 LD=gcc
43
-CFLAGS=-O2 -Wcast-align $(PROFILE) -Winline#-Wmissing-prototypes 
44
-LDFLAGS=-Wl,-O2 -Wl,-E $(PROFILE)
45
+
46
+ifeq ( mode, release )
47
+	CFLAGS=-O2 -Wcast-align $(PROFILE) -Winline#-Wmissing-prototypes 
48
+	LDFLAGS=-Wl,-O2 -Wl,-E $(PROFILE)
49
+else
50
+	CFLAGS=-g
51
+	LDFLAGS=-g
52
+endif
53
+
45 54
 LEX=flex
46 55
 YACC=bison
47 56
 YACC_FLAGS=-d -b cfg
... ...
@@ -127,3 +136,5 @@ proper: clean
127 136
 
128 137
 include $(depends)
129 138
 
139
+dbg: ser
140
+	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 155
 <INITIAL>{DNS}	{ count(); yylval.strval=yytext; return DNS; }
155 156
 <INITIAL>{REV_DNS}	{ count(); yylval.strval=yytext; return REV_DNS; }
156 157
 <INITIAL>{PORT}	{ count(); yylval.strval=yytext; return PORT; }
158
+<INITIAL>{STAT}	{ count(); yylval.strval=yytext; return STAT; }
157 159
 <INITIAL>{MAXBUFFER}	{ count(); yylval.strval=yytext; return MAXBUFFER; }
158 160
 <INITIAL>{CHILDREN}	{ count(); yylval.strval=yytext; return CHILDREN; }
159 161
 <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 74
 %token DNS
74 75
 %token REV_DNS
75 76
 %token PORT
77
+%token STAT
76 78
 %token CHILDREN
77 79
 %token CHECK_VIA
78 80
 %token LOADMODULE
... ...
@@ -147,6 +149,7 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
147 149
 		| REV_DNS EQUAL NUMBER { received_dns|= ($3)?DO_REV_DNS:0; }
148 150
 		| REV_DNS EQUAL error { yyerror("boolean value expected"); }
149 151
 		| PORT EQUAL NUMBER   { port_no=$3; }
152
+		| STAT EQUAL STRING { stat_file=$3; }
150 153
 		| MAXBUFFER EQUAL NUMBER { maxbuffer=$3; }
151 154
 		| MAXBUFFER EQUAL error { yyerror("number expected"); }
152 155
 		| 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 30
 #include "stats.h"
27 31
 #endif
28 32
 
29
-
30
-
31 33
 #ifdef DEBUG_DMALLOC
32 34
 #include <dmalloc.h>
33 35
 #endif
... ...
@@ -94,8 +96,11 @@ Options:\n\
94 96
     -V           Version number\n\
95 97
     -h           This help message\n\
96 98
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
97
-                 auto-probing procedure even if  OS allows\n\
98
-";
99
+                 auto-probing procedure even if  OS allows\n"
100
+#ifdef STATS
101
+"    -s file	 File to which statistics is dumped (disabled otherwise)\n"
102
+#endif
103
+;
99 104
 
100 105
 /* print compile-time constants */
101 106
 void print_ct_constants()
... ...
@@ -127,9 +132,9 @@ char* cfg_file = 0;
127 132
 unsigned short port_no = 0; /* port on which we listen */
128 133
 char port_no_str[MAX_PORT_LEN];
129 134
 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 */
135
+unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do not want to exceed
136
+				      		durig the auto-probing procedure; may be
137
+				      		re-configured */
133 138
 int children_no = 0;           /* number of children processing requests */
134 139
 int debug = 0;
135 140
 int dont_fork = 0;
... ...
@@ -151,11 +156,6 @@ int process_no = 0;
151 156
 /* cfg parsing */
152 157
 int cfg_errors=0;
153 158
 
154
-#ifdef STATS
155
-/* jku: RX/TX statistics -- remember, they are process specific */
156
-struct stats_s stats;
157
-#endif
158
-
159 159
 
160 160
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
161 161
 		    (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 244
 				}
242 245
 				if (pid==0){
243 246
 					/* child */
247
+#ifdef STATS
248
+					setstats( i );
249
+#endif
244 250
 					return udp_rcv_loop();
245 251
 				}
246 252
 			}
... ...
@@ -260,6 +266,7 @@ int main_loop()
260 266
 
261 267
 }
262 268
 
269
+
263 270
 /* added by jku; allows for regular exit on a specific signal;
264 271
    good for profiling which only works if exited regularly and
265 272
    not by default signal handlers
... ...
@@ -267,17 +274,25 @@ int main_loop()
267 274
 
268 275
 static void sig_usr(int signo)
269 276
 {
270
-	DPrint("INT received, program terminates\n");
277
+	if (signo==SIGINT) {	/* exit gracefuly */
271 278
 #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");
279
+		/* print statistics on exit only for the first process */
280
+
281
+		if (stats->process_index==0 && stat_file )
282
+			if (dump_all_statistic()==0)
283
+				printf("statistic dumped to %s\n", stat_file );
284
+			else
285
+				printf("statistics dump to %s failed\n", stat_file );
275 286
 #endif
276
-	exit(0);
287
+		DPrint("INT received, program terminates\n");
288
+		DPrint("Thank you for flying ser\n");
289
+		exit(0);
290
+	} else if (signo==SIGUSR1) { /* statistic */
291
+		dump_all_statistic();
292
+	}
277 293
 }
278 294
 	
279 295
 	
280
-	
281 296
 int main(int argc, char** argv)
282 297
 {
283 298
 
... ...
@@ -286,20 +301,36 @@ int main(int argc, char** argv)
286 301
 	int c,r;
287 302
 	char *tmp;
288 303
 	struct utsname myname;
304
+	char *options;
289 305
 
290 306
 	/* added by jku: add exit handler */
291 307
         if (signal(SIGINT, sig_usr) == SIG_ERR ) {
292
- 		DPrint("ERROR: no signal handler can be installed\n");
308
+ 		DPrint("ERROR: no SIGINT signal handler can be installed\n");
309
+                goto error;
310
+        }
311
+#ifdef STATS
312
+	if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
313
+                DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
293 314
                 goto error;
294 315
         }
316
+#endif
295 317
 
296 318
 	/* process command line (get port no, cfg. file path etc) */
297 319
 	opterr=0;
298
-	while((c=getopt(argc,argv,"f:p:b:l:n:rRvdDEVh"))!=-1){
320
+	options=
321
+#ifdef STATS
322
+	"s:"
323
+#endif
324
+	"f:p:b:l:n:rRvdDEVh";
325
+	
326
+	while((c=getopt(argc,argv,options))!=-1){
299 327
 		switch(c){
300 328
 			case 'f':
301 329
 					cfg_file=optarg;
302 330
 					break;
331
+			case 's':
332
+					stat_file=optarg;
333
+					break;
303 334
 			case 'p':
304 335
 					port_no=strtol(optarg, &tmp, 10);
305 336
 					if (tmp &&(*tmp)){
... ...
@@ -448,10 +479,6 @@ int main(int argc, char** argv)
448 479
 		names_len[r]=strlen(names[r]);
449 480
 	}
450 481
 
451
-#ifdef STATS
452
-	/* jku: initialize statistic */
453
- 	memset(&stats,0,sizeof(struct stats_s));
454
-#endif
455 482
 	
456 483
 	/* get ips */
457 484
 	printf("Listening on ");
... ...
@@ -467,6 +494,10 @@ int main(int argc, char** argv)
467 494
 				(unsigned short)port_no);
468 495
 	}
469 496
 
497
+#ifdef STATS
498
+	if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
499
+#endif
500
+
470 501
 	/* init_daemon? */
471 502
 	if (!dont_fork){
472 503
 		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 47
 
47 48
 	end=buffer+len;
48 49
 	/* 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");
50
+
51
+	/* jku  -- parse well-known methods */
52
+
53
+	/* drop messages which are so short they are for sure useless;
54
+           utilize knowledge of minimum size in parsing the first
55
+	   token 
56
+        */
57
+	if (len <=16 ) {
58
+		LOG(L_INFO, "ERROR: parse_first_line: message too short\n");
52 59
 		goto error1;
53 60
 	}
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{
61
+
62
+	tmp=buffer;
63
+  	/* is it perhaps a reply, ie does it start with "SIP...." ? */
64
+	if ( 	(*tmp=='S' || *tmp=='s') && 
65
+		strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
66
+		(*(tmp+SIP_VERSION_LEN)==' ')) {
67
+			fl->type=SIP_REPLY;
68
+			fl->u.reply.version.len=SIP_VERSION_LEN;
69
+			tmp=buffer+SIP_VERSION_LEN;
70
+	} else IFISMETHOD( INVITE, 'I' )
71
+	else IFISMETHOD( CANCEL, 'C')
72
+	else IFISMETHOD( ACK, 'A' )
73
+	else IFISMETHOD( BYE, 'B' )
74
+	/* if you want to add another method XXX, include METHOD_XXX in
75
+           H-file (this is the value which you will take later in
76
+           processing and define XXX_LEN as length of method name;
77
+	   then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
78
+	   latter; everything must be capitals
79
+	*/
80
+	else {
81
+		/* neither reply, nor any of known method requests, 
82
+		   let's believe it is an unknown method request
83
+        	*/
84
+		tmp=eat_token_end(buffer,buffer+len);
85
+		if ((tmp==buffer)||(tmp>=end)){
86
+			LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
87
+			goto error1;
88
+		}
89
+		if (*tmp!=' ') {
90
+			LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
91
+			goto error1;
92
+		}
60 93
 		fl->type=SIP_REQUEST;
94
+		fl->u.request.method_value=METHOD_OTHER;
95
+		fl->u.request.method.len=tmp-buffer;
61 96
 	}
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;
97
+
98
+
99
+	/* identifying type of message over now; 
100
+	   tmp points at space after; go ahead */
101
+
102
+	fl->u.request.method.s=buffer;  /* store ptr to first token */
103
+	(*tmp)=0;			/* mark the 1st token end */
104
+	second=tmp+1;			/* jump to second token */
105
+	offset=second-buffer;
106
+
107
+/* EoJku */
72 108
 	
73 109
 	/* next element */
74
-	tmp=eat_token(second, len-offset);
110
+	tmp=eat_token_end(second, second+len-offset);
75 111
 	if (tmp>=end){
76 112
 		goto error;
77 113
 	}
78 114
 	offset+=tmp-second;
79
-	third=eat_space(tmp, len-offset);
115
+	third=eat_space_end(tmp, tmp+len-offset);
80 116
 	offset+=third-tmp;
81 117
 	if ((third==tmp)||(tmp>=end)){
82 118
 		goto error;
... ...
@@ -85,20 +121,41 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
85 121
 	fl->u.request.uri.s=second;
86 122
 	fl->u.request.uri.len=tmp-second;
87 123
 
124
+	/* jku: parse status code */
125
+	if (fl->type==SIP_REPLY) {
126
+		if (fl->u.request.uri.len!=3) {
127
+			LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %s\n",
128
+				second );
129
+			goto error;
130
+		}
131
+		s1=*second; s2=*(second+1);s3=*(second+2);
132
+		if (s1>='0' && s1<='9' && 
133
+		    s2>='0' && s2<='9' &&
134
+		    s3>='0' && s3<='9' ) {
135
+			fl->u.reply.statusclass=s1-'0';
136
+			fl->u.reply.statuscode=fl->u.reply.statusclass*100+10*(s2-'0')+(s3-'0');
137
+		} else {
138
+			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
139
+				second );
140
+			goto error;
141
+		}
142
+	}
143
+	/* EoJku */
144
+
88 145
 	/*  last part: for a request it must be the version, for a reply
89 146
 	 *  it can contain almost anything, including spaces, so we don't care
90 147
 	 *  about it*/
91 148
 	if (fl->type==SIP_REQUEST){
92
-		tmp=eat_token(third,len-offset);
149
+		tmp=eat_token_end(third,third+len-offset);
93 150
 		offset+=tmp-third;
94 151
 		if ((tmp==third)||(tmp>=end)){
95 152
 			goto error;
96 153
 		}
97
-		if (! is_empty(tmp, len-offset)){
154
+		if (! is_empty_end(tmp, tmp+len-offset)){
98 155
 			goto error;
99 156
 		}
100 157
 	}else{
101
-		tmp=eat_token2(third,len-offset,'\r'); /* find end of line 
158
+		tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
102 159
 												  ('\n' or '\r') */
103 160
 		if (tmp>=end){ /* no crlf in packet => invalid */
104 161
 			goto error;
... ...
@@ -240,22 +297,22 @@ char* get_hdr_field(char *buffer, unsigned int len, struct hdr_field*  hdr_f)
240 297
 		return tmp;
241 298
 	}
242 299
 	
243
-	tmp=eat_token2(buffer, len, ':');
300
+	tmp=eat_token2_end(buffer, buffer+len, ':');
244 301
 	if ((tmp==buffer) || (tmp-buffer==len) ||
245
-		(is_empty(buffer, tmp-buffer))|| (*tmp!=':')){
302
+		(is_empty_end(buffer, tmp))|| (*tmp!=':')){
246 303
 		hdr_f->type=HDR_ERROR;
247 304
 		goto error;
248 305
 	}
249 306
 	*tmp=0;
250 307
 	/* take care of possible spaces (e.g: "Via  :") */
251
-	tmp2=eat_token(buffer, tmp-buffer);
308
+	tmp2=eat_token_end(buffer, tmp);
252 309
 	/* in the worst case tmp2=buffer+tmp-buffer=tmp */
253 310
 	*tmp2=0;
254 311
 	l=tmp2-buffer;
255 312
 	if (tmp2<tmp){
256 313
 		tmp2++;
257 314
 		/* catch things like: "Via foo bar:" */
258
-		tmp2=eat_space(tmp2, tmp-tmp2);
315
+		tmp2=eat_space_end(tmp2, tmp);
259 316
 		if (tmp2!=tmp){
260 317
 			hdr_f->type=HDR_ERROR;
261 318
 			goto error;
... ...
@@ -492,33 +549,33 @@ char* parse_via_body(char* buffer,unsigned int len, struct via_body * vb)
492 549
 
493 550
 	name=version=transport=comment=params=hostport=next_via=host.s=0;
494 551
 	name_len=version_len=transport_len=comment_len=params_len=host.len=0;
495
-	name=eat_space(buffer, len);
552
+	name=eat_space_end(buffer, buffer+len);
496 553
 	if (name-buffer==len) goto error;
497 554
 	offset=name-buffer;
498 555
 	tmp=name;
499 556
 
500
-	version=eat_token2(tmp,len-offset,'/');
557
+	version=eat_token2_end(tmp,tmp+len-offset,'/');
501 558
 	if (version+1-buffer>=len) goto error;
502 559
 	*version=0;
503 560
 	name_len=version-name;
504 561
 	version++;
505 562
 	offset+=version-tmp;
506 563
 	
507
-	transport=eat_token2(tmp,len-offset,'/');
564
+	transport=eat_token2_end(tmp,tmp+len-offset,'/');
508 565
 	if (transport+1-buffer>=len) goto error;
509 566
 	*transport=0;
510 567
 	version_len=transport-version;
511 568
 	transport++;
512 569
 	offset+=transport-tmp;
513 570
 	
514
-	tmp=eat_token(transport,len-offset);
571
+	tmp=eat_token_end(transport,transport+len-offset);
515 572
 	if (tmp+1-buffer>=len) goto error;
516 573
 	*tmp=0;
517 574
 	transport_len=tmp-transport;
518 575
 	tmp++;
519 576
 	offset+=tmp-transport;
520 577
 	
521
-	hostport=eat_space(tmp,len-offset);
578
+	hostport=eat_space_end(tmp,tmp+len-offset);
522 579
 	if (hostport+1-buffer>=len) goto error;
523 580
 	offset+=hostport-tmp;
524 581
 
... ...
@@ -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 49
 			str method;
36 50
 			str uri;
37 51
 			str version;
52
+			short method_value;
38 53
 		}request;
39 54
 		struct {
40 55
 			str version;
41 56
 			str status;
42 57
 			str reason;
58
+			unsigned short statusclass, statuscode;
43 59
 		}reply;
44 60
 	}u;
45 61
 };
... ...
@@ -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 55
 }
53 56
 
54 57
 
55
-/* returns pointer after the token (first whitespace char or CR/LF) */
58
+// returns pointer after the token (first whitespace char or CR/LF) 
56 59
 char* eat_token(char* buffer, unsigned int len)
57 60
 {
58 61
 	char *p;
... ...
@@ -65,7 +68,7 @@ char* eat_token(char* buffer, unsigned int len)
65 68
 
66 69
 
67 70
 
68
-/* returns pointer after the token (first delim char or CR/LF) */
71
+// returns pointer after the token (first delim char or CR/LF)
69 72
 char* eat_token2(char* buffer, unsigned int len, char delim)
70 73
 {
71 74
 	char *p;
... ...
@@ -75,18 +78,8 @@ char* eat_token2(char* buffer, unsigned int len, char delim)
75 78
 		p++);
76 79
 	return p;
77 80
 }
78
-
79
-/* EoMACROEATER */
80 81
 #endif
82
+*/
81 83
 
84
+/* EoMACROEATER */
82 85
 
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 54
 char* eat_token(char* buffer, unsigned int len);
44 55
 char* eat_token2(char* buffer, unsigned int len, char delim);
45 56
 
46
-/* EoMACROEATER */
47 57
 #endif
58
+*/
59
+/* EoMACROEATER */
48 60
 
49 61
 #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 64
 			goto error;
66 65
 		}
67 66
 #ifdef STATS
68
-		/* jku -- update statistics  */
69
-		else stats.ok_rx_rq++;	
67
+		/* jku -- update request statistics  */
68
+		else update_received_request(  msg.first_line.u.request.method_value );
70 69
 #endif
71 70
 	}else if (msg.first_line.type==SIP_REPLY){
72 71
 		DBG("msg= reply\n");
... ...
@@ -83,7 +82,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
83 82
 
84 83
 #ifdef STATS
85 84
 		/* jku -- update statistics  */
86
-		stats.ok_rx_rs++;	
85
+		update_received_response(  msg.first_line.u.reply.statusclass );
87 86
 #endif
88 87
 		
89 88
 		/* send the msg */
... ...
@@ -93,11 +92,17 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
93 92
 						(unsigned short) msg.via2.port);
94 93
 		}
95 94
 	}
95
+#ifdef STATS
96
+	skipped = 0;
97
+#endif
96 98
 skip:
97 99
 	if (msg.new_uri.s) { free(msg.new_uri.s); msg.new_uri.len=0; }
98 100
 	if (msg.add_rm) free_lump_list(msg.add_rm);
99 101
 	if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
100 102
 	free(msg.orig);
103
+#ifdef STATS
104
+	if (skipped) update_received_drops;
105
+#endif
101 106
 	return 0;
102 107
 error:
103 108
 	if (msg.new_uri.s) free(msg.new_uri.s);
... ...
@@ -105,6 +110,9 @@ error:
105 110
 	if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
106 111
 	free(msg.orig);
107 112
 error1:
113
+#ifdef STATS
114
+	update_received_drops;
115
+#endif
108 116
 	return -1;
109 117
 }
110 118
 
... ...
@@ -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 45
 {
68 46
 	int i, dotcount=0;
69 47
 	char *p = host;
70
-	struct hostent		*pent;
71
-	/* struct sockaddr_in	addr; */ /* see the note on portabilit at the end of the routine */
48
+	struct hostent* pent;
49
+	long l, *lp;
72 50
 
73 51
 	/*try understanding if this is a valid ip address
74 52
 	we are skipping the values of the octets specified here.
... ...
@@ -106,11 +84,9 @@ long getaddress(char *host)
106 84
 		exit(2);
107 85
 	}
108 86
 
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));
87
+	lp = (long *) (pent->h_addr);
88
+	l = *lp;
89
+	return l;
114 90
 }
115 91
 
116 92
 
... ...
@@ -129,18 +105,20 @@ at 5 seconds (5000 milliseconds).
129 105
 we are detecting the final response without a '1' as the first
130 106
 letter.
131 107
 */
132
-void shoot(char *buff, long address, int port)
108
+void shoot(char *buff, long address, int lport, int rport )
133 109
 {
134 110
 	struct sockaddr_in	addr;
135 111
 	/* jku - b  server structures */
136 112
 	struct sockaddr_in	sockname;
137 113
 	int ssock;
114
+	/*
138 115
 	char compiledre[ RESIZE ];
116
+	*/
139 117
 	/* jku - e */
140 118
 	int retryAfter = 500, i, len, ret;
141 119
 	int	nretries = 10;
142 120
 	int	sock;
143
-	timeval	tv;
121
+	struct timeval	tv;
144 122
 	fd_set	fd;
145 123
 	char	reply[1600];
146 124
 
... ...
@@ -160,26 +138,28 @@ void shoot(char *buff, long address, int port)
160 138
 
161 139
 	sockname.sin_family=AF_INET;
162 140
 	sockname.sin_addr.s_addr = htonl( INADDR_ANY );
163
-	sockname.sin_port = htons((short)port);
164
-	if (bind( ssock, (sockaddr *) &sockname, sizeof(sockname) )==-1) {
141
+	sockname.sin_port = htons((short)lport);
142
+	if (bind( ssock, (struct sockaddr *) &sockname, sizeof(sockname) )==-1) {
165 143
 		perror("no bind");
166 144
 		exit(2);
167 145
 	}
168 146
 
169 147
 	/* should capture: SIP/2.0 100 Trying */
170
-	compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0');
148
+	/* compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0'); */
149
+	regexp=(regex_t*)malloc(sizeof(regex_t));
150
+	regcomp(regexp, "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", REG_EXTENDED|REG_NOSUB|REG_ICASE); 
171 151
 	
172 152
 
173 153
 	/* jku - e */
174 154
 
175 155
 	addr.sin_addr.s_addr = address;
176
-	addr.sin_port = htons((short)port);
156
+	addr.sin_port = htons((short)rport);
177 157
 	addr.sin_family = AF_INET;
178 158
 	
179 159
 	/* we connect as per the RFC 2543 recommendations
180 160
 	modified from sendto/recvfrom */
181 161
 
182
-	ret = connect(sock, (sockaddr *)&addr, sizeof(addr));
162
+	ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
183 163
 	if (ret==-1) {
184 164
 		perror("no connect");
185 165
 		exit(2);
... ...
@@ -241,7 +221,8 @@ void shoot(char *buff, long address, int port)
241 221
 			puts("/* reply */");
242 222
 			puts(reply);
243 223
 			putchar('\n');
244
-			if (step( reply, compiledre )) {
224
+			/* if (step( reply, compiledre )) { */
225
+			if (regexec((regex_t*)regexp, reply, 0, 0, 0)==0) {
245 226
 				puts(" provisional received; still waiting for a final response\n ");
246 227
 				continue;
247 228
 			} else {
... ...
@@ -266,21 +247,12 @@ int main(int argc, char *argv[])
266 247
 	FILE	*pf;
267 248
 	char	buff[1600];
268 249
 	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
250
+	int	lport=0;
251
+	int	rport=5060;
279 252
 
280
-
281
-	if (argc != 3 && argc != 4)
253
+	if (! (argc >= 3 && argc <= 5))
282 254
 	{
283
-		puts("usage: shoot file host [port]");
255
+		puts("usage: shoot file host [rport] [lport]");
284 256
 		exit(2);
285 257
 	}
286 258
 
... ...
@@ -292,14 +264,21 @@ int main(int argc, char *argv[])
292 264
 	}
293 265
 
294 266
 	/* take the port as 5060 even if it is incorrectly specified */
295
-	if (argc == 4)
267
+	if (argc >= 4)
296 268
 	{
297
-		port = atoi(argv[3]);
298
-		if (!port)
299
-			port = 5060;
269
+		rport = atoi(argv[3]);
270
+		if (!rport) {
271
+			puts("error: non-numerical remote port number");
272
+			exit(1);
273
+		}
274
+		if (argc==5) {
275
+			lport=atoi(argv[4]);
276
+			if (!lport) {
277
+				puts("error: non-numerical local port number");
278
+				exit(1);
279
+			}
280
+		}
300 281
 	}
301
-	else
302
-		port = 5060;
303 282
 
304 283
 	/* file is opened in binary mode so that the cr-lf is preserved */
305 284
 	pf = fopen(argv[1], "rb");
... ...
@@ -317,7 +296,7 @@ int main(int argc, char *argv[])
317 296
 	fclose(pf);
318 297
 	buff[length] = 0;
319 298
 
320
-	shoot(buff, address, port);
299
+	shoot(buff, address, lport, rport );
321 300
 
322 301
 	/* visual studio closes the debug console as soon as the 
323 302
 	program terminates. this is to hold the window from collapsing