Browse code

added CRLF ping/pong keepalives aka SIP outbound

Alfred E. Heggestad authored on 24/04/2008 13:51:26
Showing 8 changed files
... ...
@@ -189,6 +189,8 @@ new config variables:
189 189
          keepalive probes, when the previous probe failed. Linux only.
190 190
   tcp_keepcnt = number (not set by default) - number of keepalives sent before
191 191
          dropping the connection. Linux only.
192
+  tcp_crlf_ping = yes | no (set by default) - enable CRLF keepalives aka
193
+         SIP outbound.
192 194
   pmtu_discovery = 0 | 1 (default 0) - set DF bit in outbound IP if enabled
193 195
   dns_srv_lb = yes | no (default no) - enable dns srv weight based load 
194 196
     balancing (see doc/dns.txt)
... ...
@@ -308,6 +308,7 @@ TCP_OPT_KEEPALIVE	"tcp_keepalive"
308 308
 TCP_OPT_KEEPIDLE	"tcp_keepidle"
309 309
 TCP_OPT_KEEPINTVL	"tcp_keepintvl"
310 310
 TCP_OPT_KEEPCNT		"tcp_keepcnt"
311
+TCP_OPT_CRLF_PING	"tcp_crlf_ping"
311 312
 DISABLE_TLS		"disable_tls"|"tls_disable"
312 313
 ENABLE_TLS		"enable_tls"|"tls_enable"
313 314
 TLSLOG			"tlslog"|"tls_log"
... ...
@@ -600,6 +601,8 @@ EAT_ABLE	[\ \t\b\r]
600 600
 									return TCP_OPT_KEEPINTVL; }
601 601
 <INITIAL>{TCP_OPT_KEEPCNT}	{ count(); yylval.strval=yytext;
602 602
 									return TCP_OPT_KEEPCNT; }
603
+<INITIAL>{TCP_OPT_CRLF_PING}	{ count(); yylval.strval=yytext;
604
+									return TCP_OPT_CRLF_PING; }
603 605
 <INITIAL>{DISABLE_TLS}	{ count(); yylval.strval=yytext; return DISABLE_TLS; }
604 606
 <INITIAL>{ENABLE_TLS}	{ count(); yylval.strval=yytext; return ENABLE_TLS; }
605 607
 <INITIAL>{TLSLOG}		{ count(); yylval.strval=yytext; return TLS_PORT_NO; }
... ...
@@ -352,6 +352,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
352 352
 %token TCP_OPT_KEEPIDLE
353 353
 %token TCP_OPT_KEEPINTVL
354 354
 %token TCP_OPT_KEEPCNT
355
+%token TCP_OPT_CRLF_PING
355 356
 %token DISABLE_TLS
356 357
 %token ENABLE_TLS
357 358
 %token TLSLOG
... ...
@@ -907,6 +908,14 @@ assign_stm:
907 907
 		#endif
908 908
 	}
909 909
 	| TCP_OPT_KEEPCNT EQUAL error { yyerror("number expected"); }
910
+	| TCP_OPT_CRLF_PING EQUAL NUMBER {
911
+		#ifdef USE_TCP
912
+			tcp_options.crlf_ping=$3;
913
+		#else
914
+			warn("tcp support not compiled in");
915
+		#endif
916
+	}
917
+	| TCP_OPT_CRLF_PING EQUAL error { yyerror("boolean value expected"); }
910 918
 	| DISABLE_TLS EQUAL NUMBER {
911 919
 		#ifdef USE_TLS
912 920
 			tls_disable=$3;
... ...
@@ -562,7 +562,7 @@ static void core_tcp_options(rpc_t* rpc, void* c)
562 562
 	if (!tcp_disable){
563 563
 		tcp_options_get(&t);
564 564
 		rpc->add(c, "{", &handle);
565
-		rpc->struct_add(handle, "dddddddddddddd",
565
+		rpc->struct_add(handle, "ddddddddddddddd",
566 566
 			"fd_cache",		t.fd_cache,
567 567
 			"tcp_buf_write",	t.tcp_buf_write,
568 568
 			"tcp_connect_wait",	t.tcp_connect_wait,
... ...
@@ -577,7 +577,8 @@ static void core_tcp_options(rpc_t* rpc, void* c)
577 577
 			"keepalive",	t.keepalive,
578 578
 			"keepidle",		t.keepidle,
579 579
 			"keepintvl",	t.keepintvl,
580
-			"keepcnt",		t.keepcnt
580
+			"keepcnt",		t.keepcnt,
581
+			"crlf_ping",	t.crlf_ping
581 582
 		);
582 583
 	}else{
583 584
 		rpc->fault(c, 500, "tcp support disabled");
... ...
@@ -83,12 +83,13 @@
83 83
 
84 84
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
85 85
 						TCP_REQ_OVERRUN, TCP_REQ_BAD_LEN };
86
-enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
86
+enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP_EMPTY_CR_FOUND, H_SKIP_EMPTY_CRLF_FOUND, H_SKIP_EMPTY_CRLFCR_FOUND,
87
+			H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
87 88
 		H_CONT_LEN1, H_CONT_LEN2, H_CONT_LEN3, H_CONT_LEN4, H_CONT_LEN5,
88 89
 		H_CONT_LEN6, H_CONT_LEN7, H_CONT_LEN8, H_CONT_LEN9, H_CONT_LEN10,
89 90
 		H_CONT_LEN11, H_CONT_LEN12, H_CONT_LEN13, H_L_COLON, 
90 91
 		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE,
91
-		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END 
92
+		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END, H_PING_CRLF
92 93
 	};
93 94
 
94 95
 enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 
... ...
@@ -58,6 +58,7 @@ void init_tcp_options()
58 58
 #ifdef HAVE_TCP_QUICKACK
59 59
 	tcp_options.delayed_ack=1;
60 60
 #endif
61
+	tcp_options.crlf_ping=1;
61 62
 }
62 63
 
63 64
 
... ...
@@ -126,6 +126,7 @@ struct tcp_cfg_options{
126 126
 	int keepidle;   /* idle time (s) before tcp starts sending keepalives */
127 127
 	int keepintvl;  /* interval between keep alives */
128 128
 	int keepcnt;    /* maximum no. of keepalives before giving up */
129
+	int crlf_ping;  /* on/off - reply to double CRLF keepalives */
129 130
 };
130 131
 
131 132
 
... ...
@@ -78,6 +78,7 @@
78 78
 #include "io_wait.h"
79 79
 #include <fcntl.h> /* must be included after io_wait.h if SIGIO_RT is used */
80 80
 #include "tsend.h"
81
+#include "forward.h"
81 82
 
82 83
 #ifdef USE_STUN
83 84
 #include "ser_stun.h"
... ...
@@ -325,7 +326,13 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
325 325
 			case H_SKIP_EMPTY:
326 326
 				switch (*p){
327 327
 					case '\n':
328
+						break;
328 329
 					case '\r':
330
+						if (tcp_options.crlf_ping) {
331
+							r->state=H_SKIP_EMPTY_CR_FOUND;
332
+							r->start=p;
333
+						}
334
+						break;
329 335
 					case ' ':
330 336
 					case '\t':
331 337
 						/* skip empty lines */
... ...
@@ -358,6 +365,36 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
358 358
 				};
359 359
 				p++;
360 360
 				break;
361
+
362
+			case H_SKIP_EMPTY_CR_FOUND:
363
+				if (*p=='\n'){
364
+					r->state=H_SKIP_EMPTY_CRLF_FOUND;
365
+					p++;
366
+				}else{
367
+					r->state=H_SKIP_EMPTY;
368
+				}
369
+				break;
370
+
371
+			case H_SKIP_EMPTY_CRLF_FOUND:
372
+				if (*p=='\r'){
373
+					r->state = H_SKIP_EMPTY_CRLFCR_FOUND;
374
+					p++;
375
+				}else{
376
+					r->state = H_SKIP_EMPTY;
377
+				}
378
+				break;
379
+
380
+			case H_SKIP_EMPTY_CRLFCR_FOUND:
381
+				if (*p=='\n'){
382
+					r->state = H_PING_CRLF;
383
+					r->complete = 1;
384
+					r->has_content_len = 1; /* hack to avoid error check */
385
+					p++;
386
+					goto skip;
387
+				}else{
388
+					r->state = H_SKIP_EMPTY;
389
+				}
390
+				break;
361 391
 #ifdef USE_STUN
362 392
 			case H_STUN_MSG:
363 393
 				if ((r->pos - r->body) >= sizeof(struct stun_hdr)) {
... ...
@@ -539,6 +576,7 @@ int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
539 539
 	int resp;
540 540
 	long size;
541 541
 	struct tcp_req* req;
542
+	struct dest_info dst;
542 543
 	int s;
543 544
 	char c;
544 545
 	int ret;
... ...
@@ -639,6 +677,15 @@ again:
639 639
 							   previous char, req->parsed should be ok
640 640
 							   because we always alloc BUF_SIZE+1 */
641 641
 			*req->parsed=0;
642
+
643
+			if (req->state==H_PING_CRLF) {
644
+				init_dst_from_rcv(&dst, &con->rcv);
645
+
646
+				if (tcp_send(&dst, 0, CRLF, CRLF_LEN) < 0) {
647
+					LOG(L_ERR, "CRLF ping: tcp_send() failed\n");
648
+				}
649
+				ret = 0;
650
+			}else
642 651
 #ifdef USE_STUN
643 652
 			if (unlikely(req->state==H_STUN_END)){
644 653
 				/* stun request */