Browse Source

added CRLF ping/pong keepalives aka SIP outbound

Alfred E. Heggestad 17 years ago
parent
commit
c7337a2747
8 changed files with 69 additions and 4 deletions
  1. 2 0
      NEWS
  2. 3 0
      cfg.lex
  3. 9 0
      cfg.y
  4. 3 2
      core_cmd.c
  5. 3 2
      tcp_conn.h
  6. 1 0
      tcp_options.c
  7. 1 0
      tcp_options.h
  8. 47 0
      tcp_read.c

+ 2 - 0
NEWS

@@ -189,6 +189,8 @@ new config variables:
          keepalive probes, when the previous probe failed. Linux only.
   tcp_keepcnt = number (not set by default) - number of keepalives sent before
          dropping the connection. Linux only.
+  tcp_crlf_ping = yes | no (set by default) - enable CRLF keepalives aka
+         SIP outbound.
   pmtu_discovery = 0 | 1 (default 0) - set DF bit in outbound IP if enabled
   dns_srv_lb = yes | no (default no) - enable dns srv weight based load 
     balancing (see doc/dns.txt)

+ 3 - 0
cfg.lex

@@ -308,6 +308,7 @@ TCP_OPT_KEEPALIVE	"tcp_keepalive"
 TCP_OPT_KEEPIDLE	"tcp_keepidle"
 TCP_OPT_KEEPINTVL	"tcp_keepintvl"
 TCP_OPT_KEEPCNT		"tcp_keepcnt"
+TCP_OPT_CRLF_PING	"tcp_crlf_ping"
 DISABLE_TLS		"disable_tls"|"tls_disable"
 ENABLE_TLS		"enable_tls"|"tls_enable"
 TLSLOG			"tlslog"|"tls_log"
@@ -600,6 +601,8 @@ EAT_ABLE	[\ \t\b\r]
 									return TCP_OPT_KEEPINTVL; }
 <INITIAL>{TCP_OPT_KEEPCNT}	{ count(); yylval.strval=yytext;
 									return TCP_OPT_KEEPCNT; }
+<INITIAL>{TCP_OPT_CRLF_PING}	{ count(); yylval.strval=yytext;
+									return TCP_OPT_CRLF_PING; }
 <INITIAL>{DISABLE_TLS}	{ count(); yylval.strval=yytext; return DISABLE_TLS; }
 <INITIAL>{ENABLE_TLS}	{ count(); yylval.strval=yytext; return ENABLE_TLS; }
 <INITIAL>{TLSLOG}		{ count(); yylval.strval=yytext; return TLS_PORT_NO; }

+ 9 - 0
cfg.y

@@ -352,6 +352,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token TCP_OPT_KEEPIDLE
 %token TCP_OPT_KEEPINTVL
 %token TCP_OPT_KEEPCNT
+%token TCP_OPT_CRLF_PING
 %token DISABLE_TLS
 %token ENABLE_TLS
 %token TLSLOG
@@ -907,6 +908,14 @@ assign_stm:
 		#endif
 	}
 	| TCP_OPT_KEEPCNT EQUAL error { yyerror("number expected"); }
+	| TCP_OPT_CRLF_PING EQUAL NUMBER {
+		#ifdef USE_TCP
+			tcp_options.crlf_ping=$3;
+		#else
+			warn("tcp support not compiled in");
+		#endif
+	}
+	| TCP_OPT_CRLF_PING EQUAL error { yyerror("boolean value expected"); }
 	| DISABLE_TLS EQUAL NUMBER {
 		#ifdef USE_TLS
 			tls_disable=$3;

+ 3 - 2
core_cmd.c

@@ -562,7 +562,7 @@ static void core_tcp_options(rpc_t* rpc, void* c)
 	if (!tcp_disable){
 		tcp_options_get(&t);
 		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "dddddddddddddd",
+		rpc->struct_add(handle, "ddddddddddddddd",
 			"fd_cache",		t.fd_cache,
 			"tcp_buf_write",	t.tcp_buf_write,
 			"tcp_connect_wait",	t.tcp_connect_wait,
@@ -577,7 +577,8 @@ static void core_tcp_options(rpc_t* rpc, void* c)
 			"keepalive",	t.keepalive,
 			"keepidle",		t.keepidle,
 			"keepintvl",	t.keepintvl,
-			"keepcnt",		t.keepcnt
+			"keepcnt",		t.keepcnt,
+			"crlf_ping",	t.crlf_ping
 		);
 	}else{
 		rpc->fault(c, 500, "tcp support disabled");

+ 3 - 2
tcp_conn.h

@@ -83,12 +83,13 @@
 
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
 						TCP_REQ_OVERRUN, TCP_REQ_BAD_LEN };
-enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
+enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP_EMPTY_CR_FOUND, H_SKIP_EMPTY_CRLF_FOUND, H_SKIP_EMPTY_CRLFCR_FOUND,
+			H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
 		H_CONT_LEN1, H_CONT_LEN2, H_CONT_LEN3, H_CONT_LEN4, H_CONT_LEN5,
 		H_CONT_LEN6, H_CONT_LEN7, H_CONT_LEN8, H_CONT_LEN9, H_CONT_LEN10,
 		H_CONT_LEN11, H_CONT_LEN12, H_CONT_LEN13, H_L_COLON, 
 		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE,
-		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END 
+		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END, H_PING_CRLF
 	};
 
 enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 

+ 1 - 0
tcp_options.c

@@ -58,6 +58,7 @@ void init_tcp_options()
 #ifdef HAVE_TCP_QUICKACK
 	tcp_options.delayed_ack=1;
 #endif
+	tcp_options.crlf_ping=1;
 }
 
 

+ 1 - 0
tcp_options.h

@@ -126,6 +126,7 @@ struct tcp_cfg_options{
 	int keepidle;   /* idle time (s) before tcp starts sending keepalives */
 	int keepintvl;  /* interval between keep alives */
 	int keepcnt;    /* maximum no. of keepalives before giving up */
+	int crlf_ping;  /* on/off - reply to double CRLF keepalives */
 };
 
 

+ 47 - 0
tcp_read.c

@@ -78,6 +78,7 @@
 #include "io_wait.h"
 #include <fcntl.h> /* must be included after io_wait.h if SIGIO_RT is used */
 #include "tsend.h"
+#include "forward.h"
 
 #ifdef USE_STUN
 #include "ser_stun.h"
@@ -325,7 +326,13 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 			case H_SKIP_EMPTY:
 				switch (*p){
 					case '\n':
+						break;
 					case '\r':
+						if (tcp_options.crlf_ping) {
+							r->state=H_SKIP_EMPTY_CR_FOUND;
+							r->start=p;
+						}
+						break;
 					case ' ':
 					case '\t':
 						/* skip empty lines */
@@ -358,6 +365,36 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 				};
 				p++;
 				break;
+
+			case H_SKIP_EMPTY_CR_FOUND:
+				if (*p=='\n'){
+					r->state=H_SKIP_EMPTY_CRLF_FOUND;
+					p++;
+				}else{
+					r->state=H_SKIP_EMPTY;
+				}
+				break;
+
+			case H_SKIP_EMPTY_CRLF_FOUND:
+				if (*p=='\r'){
+					r->state = H_SKIP_EMPTY_CRLFCR_FOUND;
+					p++;
+				}else{
+					r->state = H_SKIP_EMPTY;
+				}
+				break;
+
+			case H_SKIP_EMPTY_CRLFCR_FOUND:
+				if (*p=='\n'){
+					r->state = H_PING_CRLF;
+					r->complete = 1;
+					r->has_content_len = 1; /* hack to avoid error check */
+					p++;
+					goto skip;
+				}else{
+					r->state = H_SKIP_EMPTY;
+				}
+				break;
 #ifdef USE_STUN
 			case H_STUN_MSG:
 				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)
 	int resp;
 	long size;
 	struct tcp_req* req;
+	struct dest_info dst;
 	int s;
 	char c;
 	int ret;
@@ -639,6 +677,15 @@ again:
 							   previous char, req->parsed should be ok
 							   because we always alloc BUF_SIZE+1 */
 			*req->parsed=0;
+
+			if (req->state==H_PING_CRLF) {
+				init_dst_from_rcv(&dst, &con->rcv);
+
+				if (tcp_send(&dst, 0, CRLF, CRLF_LEN) < 0) {
+					LOG(L_ERR, "CRLF ping: tcp_send() failed\n");
+				}
+				ret = 0;
+			}else
 #ifdef USE_STUN
 			if (unlikely(req->state==H_STUN_END)){
 				/* stun request */