Hi
I have added support CRLF ping/pong keepalives aka SIP outbound
style (http://tools.ietf.org/html/draft-ietf-sip-outbound-13).
(thanks to Andrei for guidance).
The patch is against SER v2.1 and adds a new configuration item
in tcp_options.crlf_ping which is enabled by default.
the code works by looking for empty double CRLF's in between
SIP messages, and when detected it will respond with a single
CRLF on the same TCP connection.
I have done some brief testing, but this patch needs much
more heavy testing before it is accepted into CVS (if?)
For people interested in SER v2.0 I can also provide a patch.
Please review and test, comments are welcome
/alfred
Index: core_cmd.c
===================================================================
RCS file: /cvsroot/ser/sip_router/core_cmd.c,v
retrieving revision 1.25
diff -u -3 -r1.25 core_cmd.c
--- core_cmd.c 21 Dec 2007 17:58:07 -0000 1.25
+++ core_cmd.c 22 Apr 2008 08:11:10 -0000
@@ -562,7 +562,7 @@
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 @@
"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");
Index: tcp_conn.h
===================================================================
RCS file: /cvsroot/ser/sip_router/tcp_conn.h,v
retrieving revision 1.39
diff -u -3 -r1.39 tcp_conn.h
--- tcp_conn.h 20 Feb 2008 14:37:30 -0000 1.39
+++ tcp_conn.h 22 Apr 2008 08:11:10 -0000
@@ -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,
Index: tcp_options.c
===================================================================
RCS file: /cvsroot/ser/sip_router/tcp_options.c,v
retrieving revision 1.5
diff -u -3 -r1.5 tcp_options.c
--- tcp_options.c 21 Dec 2007 17:58:07 -0000 1.5
+++ tcp_options.c 22 Apr 2008 08:11:10 -0000
@@ -58,6 +58,7 @@
#ifdef HAVE_TCP_QUICKACK
tcp_options.delayed_ack=1;
#endif
+ tcp_options.crlf_ping=1;
}
Index: tcp_options.h
===================================================================
RCS file: /cvsroot/ser/sip_router/tcp_options.h,v
retrieving revision 1.4
diff -u -3 -r1.4 tcp_options.h
--- tcp_options.h 21 Dec 2007 17:58:07 -0000 1.4
+++ tcp_options.h 22 Apr 2008 08:11:10 -0000
@@ -126,6 +126,7 @@
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 */
};
Index: tcp_read.c
===================================================================
RCS file: /cvsroot/ser/sip_router/tcp_read.c,v
retrieving revision 1.49
diff -u -3 -r1.49 tcp_read.c
--- tcp_read.c 5 Feb 2008 21:47:29 -0000 1.49
+++ tcp_read.c 22 Apr 2008 08:11:10 -0000
@@ -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 @@
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 @@
};
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 resp;
long size;
struct tcp_req* req;
+ struct dest_info dst;
int s;
char c;
int ret;
@@ -639,6 +677,15 @@
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 */
_______________________________________________
Serdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/serdev