Browse code

port numbers different now for remote and local

Jiri Kuthan authored on 20/11/2001 06:26:49
Showing 14 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
new file mode 100644
... ...
@@ -0,0 +1,324 @@
0
+/*
1
+shot written by ashhar farhan, is not bound by any licensing at all.
2
+you are free to use this code as you deem fit. just dont blame the author
3
+for any problems you may have using it.
4
+bouquets and brickbats to farhan@hotfoon.com
5
+*/
6
+
7
+/* changes by jiri@iptel.org; now messages can be really received;
8
+   status code returned is 2 for some local errors , 0 for success
9
+   and 1 for remote error -- ICMP/timeout; can be used to test if
10
+   a server is alive; 1xx messages are now ignored; windows support
11
+   dropped
12
+*/
13
+
14
+#include <stdlib.h>
15
+#include <stdio.h>
16
+#include <sys/types.h>
17
+#include <sys/time.h>
18
+#include <string.h>
19
+#include <ctype.h>
20
+#include <time.h>
21
+#include <unistd.h>
22
+#include <netdb.h>
23
+#include <sys/socket.h>
24
+
25
+#include <regex.h>
26
+regex_t* regexp;
27
+
28
+#define RESIZE		1024
29
+
30
+/* take either a dot.decimal string of ip address or a 
31
+domain name and returns a NETWORK ordered long int containing
32
+the address. i chose to internally represent the address as long for speedier
33
+comparisions.
34
+
35
+any changes to getaddress have to be patched back to the net library.
36
+contact: farhan@hotfoon.com
37
+
38
+  returns zero if there is an error.
39
+  this is convenient as 0 means 'this' host and the traffic of
40
+  a badly behaving dns system remains inside (you send to 0.0.0.0)
41
+*/
42
+
43
+long getaddress(char *host)
44
+{
45
+	int i, dotcount=0;
46
+	char *p = host;
47
+	struct hostent* pent;
48
+	long l, *lp;
49
+
50
+	/*try understanding if this is a valid ip address
51
+	we are skipping the values of the octets specified here.
52
+	for instance, this code will allow 952.0.320.567 through*/
53
+	while (*p)
54
+	{
55
+		for (i = 0; i < 3; i++, p++)
56
+			if (!isdigit(*p))
57
+				break;
58
+		if (*p != '.')
59
+			break;
60
+		p++;
61
+		dotcount++;
62
+	}
63
+
64
+	/* three dots with upto three digits in before, between and after ? */
65
+	if (dotcount == 3 && i > 0 && i <= 3)
66
+		return inet_addr(host);
67
+
68
+	/* try the system's own resolution mechanism for dns lookup:
69
+	 required only for domain names.
70
+	 inspite of what the rfc2543 :D Using SRV DNS Records recommends,
71
+	 we are leaving it to the operating system to do the name caching.
72
+
73
+	 this is an important implementational issue especially in the light
74
+	 dynamic dns servers like dynip.com or dyndns.com where a dial
75
+	 ip address is dynamically assigned a sub domain like farhan.dynip.com
76
+
77
+	 although expensive, this is a must to allow OS to take
78
+	 the decision to expire the DNS records as it deems fit.
79
+	*/
80
+	pent = gethostbyname(host);
81
+	if (!pent) {
82
+		perror("no gethostbyname");
83
+		exit(2);
84
+	}
85
+
86
+	lp = (long *) (pent->h_addr);
87
+	l = *lp;
88
+	return l;
89
+}
90
+
91
+
92
+/*
93
+shoot:
94
+takes:
95
+	1. the text message of buff to 
96
+	2. the address (network orderd byte order)
97
+	3. and port (not network byte ordered).
98
+
99
+starting from half a second, times-out on replies and
100
+keeps retrying with exponential back-off that flattens out
101
+at 5 seconds (5000 milliseconds).
102
+
103
+* Does not stop sending unless a final response is received.
104
+we are detecting the final response without a '1' as the first
105
+letter.
106
+*/
107
+void shoot(char *buff, long address, int lport, int rport )
108
+{
109
+	struct sockaddr_in	addr;
110
+	/* jku - b  server structures */
111
+	struct sockaddr_in	sockname;
112
+	int ssock;
113
+	/*
114
+	char compiledre[ RESIZE ];
115
+	*/
116
+	/* jku - e */
117
+	int retryAfter = 500, i, len, ret;
118
+	int	nretries = 10;
119
+	int	sock;
120
+	struct timeval	tv;
121
+	fd_set	fd;
122
+	char	reply[1600];
123
+
124
+	/* create a socket */
125
+	sock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
126
+	if (sock==-1) {
127
+		perror("no client socket");
128
+		exit(2);
129
+	}
130
+
131
+	/* jku - b */
132
+	ssock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
133
+	if (sock==-1) {
134
+		perror("no server socket");
135
+		exit(2);
136
+	}
137
+
138
+	sockname.sin_family=AF_INET;
139
+	sockname.sin_addr.s_addr = htonl( INADDR_ANY );
140
+	sockname.sin_port = htons((short)lport);
141
+	if (bind( ssock, (struct sockaddr *) &sockname, sizeof(sockname) )==-1) {
142
+		perror("no bind");
143
+		exit(2);
144
+	}
145
+
146
+	/* should capture: SIP/2.0 100 Trying */
147
+	/* compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0'); */
148
+	regexp=(regex_t*)malloc(sizeof(regex_t));
149
+	regcomp(regexp, "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", REG_EXTENDED|REG_NOSUB|REG_ICASE); 
150
+	
151
+
152
+	/* jku - e */
153
+
154
+	addr.sin_addr.s_addr = address;
155
+	addr.sin_port = htons((short)rport);
156
+	addr.sin_family = AF_INET;
157
+	
158
+	/* we connect as per the RFC 2543 recommendations
159
+	modified from sendto/recvfrom */
160
+
161
+	ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
162
+	if (ret==-1) {
163
+		perror("no connect");
164
+		exit(2);
165
+	}
166
+	/* jku - e */
167
+
168
+	for (i = 0; i < nretries; i++)
169
+	{
170
+		puts("/* request */");
171
+		puts(buff);
172
+		putchar('\n');
173
+
174
+		ret = send(sock, buff, strlen(buff), 0);
175
+		if (ret==-1) {
176
+			perror("send failure");
177
+			exit( 1 );
178
+		}
179
+		
180
+
181
+		tv.tv_sec = retryAfter/1000;
182
+		tv.tv_usec = (retryAfter % 1000) * 1000;
183
+
184
+		FD_ZERO(&fd);
185
+		FD_SET(ssock, &fd); 
186
+
187
+		/* TO-DO: there does appear to be a problem with this select returning a zero
188
+		even when there is data pending in the recv queue. 
189
+		please help, someone! */
190
+
191
+		ret = select(6, &fd, NULL, NULL, &tv);
192
+		if (ret == 0)
193
+		{
194
+			puts("\n/* timeout */\n");
195
+			retryAfter = retryAfter * 2;
196
+			if (retryAfter > 5000)
197
+				retryAfter = 5000;
198
+			/* we should have retrieved the error code and displayed
199
+			we are not doing that because there is a great variation
200
+			in the process of retrieveing error codes between
201
+			micro$oft and *nix world*/
202
+			continue;
203
+		} else if ( ret == -1 ) {
204
+			perror("select error");
205
+			exit(2);
206
+		} /* no timeout, no error ... something has happened :-) */
207
+                 else if (FD_ISSET(ssock, &fd)) {
208
+			puts ("\nmessage received\n");
209
+		} else {
210
+			puts("\nselect returned succesfuly, nothing received\n");
211
+			continue;
212
+		}
213
+
214
+		/* we are retrieving only the extend of a decent MSS = 1500 bytes */
215
+		len = sizeof(addr);
216
+		ret = recv(ssock, reply, 1500, 0);
217
+		if(ret > 0)
218
+		{
219
+			reply[ret] = 0;
220
+			puts("/* reply */");
221
+			puts(reply);
222
+			putchar('\n');
223
+			/* if (step( reply, compiledre )) { */
224
+			if (regexec((regex_t*)regexp, reply, 0, 0, 0)==0) {
225
+				puts(" provisional received; still waiting for a final response\n ");
226
+				continue;
227
+			} else {
228
+				puts(" final received; congratulations!\n ");
229
+				exit(0);
230
+			}
231
+		
232
+		} 
233
+		else	{
234
+			perror("recv error");
235
+			exit(2);
236
+			}
237
+	}
238
+	/* after all the retries, nothing has come back :-( */
239
+	puts("/* I give up retransmission....");
240
+	exit(1);
241
+}
242
+
243
+int main(int argc, char *argv[])
244
+{
245
+	long	address;
246
+	FILE	*pf;
247
+	char	buff[1600];
248
+	int		length;
249
+	int	lport=0;
250
+	int	rport=5060;
251
+
252
+	if (! (argc >= 3 && argc <= 5))
253
+	{
254
+		puts("usage: shoot file host [rport] [lport]");
255
+		exit(2);
256
+	}
257
+
258
+	address = getaddress(argv[2]);
259
+	if (!address)
260
+	{
261
+		puts("error:unable to determine the remote host address.");
262
+		exit(2);
263
+	}
264
+
265
+	/* take the port as 5060 even if it is incorrectly specified */
266
+	if (argc >= 4)
267
+	{
268
+		rport = atoi(argv[3]);
269
+		if (!rport) {
270
+			puts("error: non-numerical remote port number");
271
+			exit(1);
272
+		}
273
+		if (argc==5) {
274
+			lport=atoi(argv[4]);
275
+			if (!lport) {
276
+				puts("error: non-numerical local port number");
277
+				exit(1);
278
+			}
279
+		}
280
+	}
281
+
282
+	/* file is opened in binary mode so that the cr-lf is preserved */
283
+	pf = fopen(argv[1], "rb");
284
+	if (!pf)
285
+	{
286
+		puts("unable to open the file.\n");
287
+		return 1;
288
+	}
289
+	length  = fread(buff, 1, sizeof(buff), pf);
290
+	if (length >= sizeof(buff))
291
+	{
292
+		puts("error:the file is too big. try files of less than 1500 bytes.");
293
+		return 1;
294
+	}
295
+	fclose(pf);
296
+	buff[length] = 0;
297
+
298
+	shoot(buff, address, lport, rport );
299
+
300
+	/* visual studio closes the debug console as soon as the 
301
+	program terminates. this is to hold the window from collapsing
302
+	Uncomment it if needed.
303
+	getchar();*/
304
+	
305
+
306
+	return 0;
307
+}
308
+
309
+
310
+/*
311
+shoot will exercise the all types of sip servers.
312
+it is not to be used to measure round-trips and general connectivity.
313
+use ping for that. 
314
+written by farhan on 10th august, 2000.
315
+
316
+TO-DO:
317
+1. replace the command line arguments with just a sip url like this:
318
+	shoot invite.txt sip:farhan@sip.hotfoon.com:5060
319
+
320
+2. understand redirect response and retransmit to the redirected server.
321
+
322
+*/
323
+
0 324
deleted file mode 100644
... ...
@@ -1,345 +0,0 @@
1
-/*
2
-shot written by ashhar farhan, is not bound by any licensing at all.
3
-you are free to use this code as you deem fit. just dont blame the author
4
-for any problems you may have using it.
5
-bouquets and brickbats to farhan@hotfoon.com
6
-*/
7
-
8
-/* changes by jiri@iptel.org; now messages can be really received;
9
-   status code returned is 2 for some local errors , 0 for success
10
-   and 1 for remote error -- ICMP/timeout; can be used to test if
11
-   a server is alive; 1xx messages are now ignored
12
-*/
13
-
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
-
30
-#include <stdio.h>
31
-#include <string.h>
32
-#include <ctype.h>
33
-#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
-#include <unistd.h>
45
-#include <netdb.h>
46
-#include <arpa/inet.h>
47
-#include <sys/socket.h>
48
-#include <netinet/in.h>
49
-#endif
50
-
51
-#define RESIZE		1024
52
-
53
-/* take either a dot.decimal string of ip address or a 
54
-domain name and returns a NETWORK ordered long int containing
55
-the address. i chose to internally represent the address as long for speedier
56
-comparisions.
57
-
58
-any changes to getaddress have to be patched back to the net library.
59
-contact: farhan@hotfoon.com
60
-
61
-  returns zero if there is an error.
62
-  this is convenient as 0 means 'this' host and the traffic of
63
-  a badly behaving dns system remains inside (you send to 0.0.0.0)
64
-*/
65
-
66
-long getaddress(char *host)
67
-{
68
-	int i, dotcount=0;
69
-	char *p = host;
70
-	struct hostent		*pent;
71
-	/* struct sockaddr_in	addr; */ /* see the note on portabilit at the end of the routine */
72
-
73
-	/*try understanding if this is a valid ip address
74
-	we are skipping the values of the octets specified here.
75
-	for instance, this code will allow 952.0.320.567 through*/
76
-	while (*p)
77
-	{
78
-		for (i = 0; i < 3; i++, p++)
79
-			if (!isdigit(*p))
80
-				break;
81
-		if (*p != '.')
82
-			break;
83
-		p++;
84
-		dotcount++;
85
-	}
86
-
87
-	/* three dots with upto three digits in before, between and after ? */
88
-	if (dotcount == 3 && i > 0 && i <= 3)
89
-		return inet_addr(host);
90
-
91
-	/* try the system's own resolution mechanism for dns lookup:
92
-	 required only for domain names.
93
-	 inspite of what the rfc2543 :D Using SRV DNS Records recommends,
94
-	 we are leaving it to the operating system to do the name caching.
95
-
96
-	 this is an important implementational issue especially in the light
97
-	 dynamic dns servers like dynip.com or dyndns.com where a dial
98
-	 ip address is dynamically assigned a sub domain like farhan.dynip.com
99
-
100
-	 although expensive, this is a must to allow OS to take
101
-	 the decision to expire the DNS records as it deems fit.
102
-	*/
103
-	pent = gethostbyname(host);
104
-	if (!pent) {
105
-		perror("no gethostbyname");
106
-		exit(2);
107
-	}
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));
114
-}
115
-
116
-
117
-/*
118
-shoot:
119
-takes:
120
-	1. the text message of buff to 
121
-	2. the address (network orderd byte order)
122
-	3. and port (not network byte ordered).
123
-
124
-starting from half a second, times-out on replies and
125
-keeps retrying with exponential back-off that flattens out
126
-at 5 seconds (5000 milliseconds).
127
-
128
-* Does not stop sending unless a final response is received.
129
-we are detecting the final response without a '1' as the first
130
-letter.
131
-*/
132
-void shoot(char *buff, long address, int port)
133
-{
134
-	struct sockaddr_in	addr;
135
-	/* jku - b  server structures */
136
-	struct sockaddr_in	sockname;
137
-	int ssock;
138
-	char compiledre[ RESIZE ];
139
-	/* jku - e */
140
-	int retryAfter = 500, i, len, ret;
141
-	int	nretries = 10;
142
-	int	sock;
143
-	timeval	tv;
144
-	fd_set	fd;
145
-	char	reply[1600];
146
-
147
-	/* create a socket */
148
-	sock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
149
-	if (sock==-1) {
150
-		perror("no client socket");
151
-		exit(2);
152
-	}
153
-
154
-	/* jku - b */
155
-	ssock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
156
-	if (sock==-1) {
157
-		perror("no server socket");
158
-		exit(2);
159
-	}
160
-
161
-	sockname.sin_family=AF_INET;
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) {
165
-		perror("no bind");
166
-		exit(2);
167
-	}
168
-
169
-	/* should capture: SIP/2.0 100 Trying */
170
-	compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0');
171
-	
172
-
173
-	/* jku - e */
174
-
175
-	addr.sin_addr.s_addr = address;
176
-	addr.sin_port = htons((short)port);
177
-	addr.sin_family = AF_INET;
178
-	
179
-	/* we connect as per the RFC 2543 recommendations
180
-	modified from sendto/recvfrom */
181
-
182
-	ret = connect(sock, (sockaddr *)&addr, sizeof(addr));
183
-	if (ret==-1) {
184
-		perror("no connect");
185
-		exit(2);
186
-	}
187
-	/* jku - e */
188
-
189
-	for (i = 0; i < nretries; i++)
190
-	{
191
-		puts("/* request */");
192
-		puts(buff);
193
-		putchar('\n');
194
-
195
-		ret = send(sock, buff, strlen(buff), 0);
196
-		if (ret==-1) {
197
-			perror("send failure");
198
-			exit( 1 );
199
-		}
200
-		
201
-
202
-		tv.tv_sec = retryAfter/1000;
203
-		tv.tv_usec = (retryAfter % 1000) * 1000;
204
-
205
-		FD_ZERO(&fd);
206
-		FD_SET(ssock, &fd); 
207
-
208
-		/* TO-DO: there does appear to be a problem with this select returning a zero
209
-		even when there is data pending in the recv queue. 
210
-		please help, someone! */
211
-
212
-		ret = select(6, &fd, NULL, NULL, &tv);
213
-		if (ret == 0)
214
-		{
215
-			puts("\n/* timeout */\n");
216
-			retryAfter = retryAfter * 2;
217
-			if (retryAfter > 5000)
218
-				retryAfter = 5000;
219
-			/* we should have retrieved the error code and displayed
220
-			we are not doing that because there is a great variation
221
-			in the process of retrieveing error codes between
222
-			micro$oft and *nix world*/
223
-			continue;
224
-		} else if ( ret == -1 ) {
225
-			perror("select error");
226
-			exit(2);
227
-		} /* no timeout, no error ... something has happened :-) */
228
-                 else if (FD_ISSET(ssock, &fd)) {
229
-			puts ("\nmessage received\n");
230
-		} else {
231
-			puts("\nselect returned succesfuly, nothing received\n");
232
-			continue;
233
-		}