Browse Source

Merge pull request #816 from kamailio/co/tcp_closed_routes

TCP closed event route improvement
Camille Oudot 9 years ago
parent
commit
b5d1f36492
6 changed files with 107 additions and 47 deletions
  1. 64 19
      modules/tcpops/doc/eventroutes.xml
  2. 9 12
      modules/tcpops/tcpops.c
  3. 1 0
      modules/tcpops/tcpops.h
  4. 11 5
      modules/tcpops/tcpops_mod.c
  5. 13 0
      tcp_conn.h
  6. 9 11
      tcp_read.c

+ 64 - 19
modules/tcpops/doc/eventroutes.xml

@@ -8,28 +8,73 @@
 
 ]>
 <section id="tcpops.ex.event_routes">
-    <title>Event routes</title>
-    <section>
-        <title>
-            <function moreinfo="none">tcp:closed</function>
-        </title>
-        <para>
-			This route is called when a socket is closed by the remote party,
-			or reset, or timeout. The corresponding <emphasis>$conid</emphasis>
-			variable will be available in the event route. 
-        </para>
-        <para>
-			Whether this route is always called, never, or on a per socket basis
-			is controlled by the <emphasis>closed_event</emphasis> parameter.
-        </para>
-        <para>
-    		<programlisting  format="linespecific">
+	<title>Event routes</title>
+		<para>The 3 following routes are called when a socket is closed.</para>
+		<para>
+			The corresponding
+			<emphasis>$conid</emphasis>
+			,
+			<emphasis>$Ri</emphasis>
+			,
+			<emphasis>$Rp</emphasis>
+			,
+			<emphasis>$si</emphasis>
+			,
+			<emphasis>$sp</emphasis>
+			and
+			<emphasis>$proto</emphasis>
+			variable will be available in the event routes.
+		</para>
+		<para>
+			Whether these routes are always called, never, or on a per socket
+			basis is controlled by the
+			<emphasis>closed_event</emphasis>
+			parameter.
+		</para>
+	<section>
+		<title>
+			<function moreinfo="none">tcp:closed</function>
+		</title>
+		<para>
+			Called for each "normal" TCP socket closure by the other side (FIN,ACK).
+		</para>
+	</section>
+	<section>
+		<title>
+			<function moreinfo="none">tcp:timeout</function>
+		</title>
+		<para>
+			Called for connection timeouts (unanswered keepalives).
+		</para>
+	</section>
+	<section>
+		<title>
+			<function moreinfo="none">tcp:reset</function>
+		</title>
+		<para>
+			Called if the connection is reset by peer (RST).
+		</para>
+	</section>
+	<section>
+		<title>
+			<function moreinfo="none">Example</function>
+		</title>
+		<para>
+			<programlisting format="linespecific">
 ...
 event_route[tcp:closed] {
-    xlog("L_INFO", "TCP connection closed ($conid)\n");
+	xlog("L_INFO", "$proto connection closed ($conid)\n");
+}
+
+event_route[tcp:timeout] {
+	xlog("L_INFO", "$proto connection timed out ($conid)\n");
+}
+
+event_route[tcp:reset] {
+	xlog("L_INFO", "$proto connection reset by peer ($conid)\n");
 }
 ...
-  	    	</programlisting>
-    	</para>
+			</programlisting>
+		</para>
 	</section>
 </section>

+ 9 - 12
modules/tcpops/tcpops.c

@@ -38,6 +38,9 @@
 /* globally enabled by default */
 int tcp_closed_event = 1;
 
+int tcp_closed_routes[_TCP_CLOSED_REASON_MAX] =
+	{[0 ... sizeof(tcp_closed_routes)/sizeof(*tcp_closed_routes)-1] = -1};
+
 /**
  * gets the fd of the current message source connection
  *
@@ -192,20 +195,14 @@ int tcpops_set_connection_lifetime(struct tcp_connection* con, int time) {
 	return 1;
 }
 
-static void tcpops_tcp_closed_run_route(struct tcp_connection *con)
+static void tcpops_tcp_closed_run_route(tcp_closed_event_info_t *tev)
 {
 	int rt, backup_rt;
 	struct run_act_ctx ctx;
 	sip_msg_t *fmsg;
 
-	LM_DBG("tcp_closed_run_route event_route[tcp:closed]\n");
-
-	rt = route_get(&event_rt, "tcp:closed");
-	if (rt < 0 || event_rt.rlist[rt] == NULL)
-	{
-		LM_DBG("route does not exist");
-		return;
-	}
+	rt = tcp_closed_routes[tev->reason];
+	if (rt == -1) return;
 
 	if (faked_msg_init() < 0)
 	{
@@ -213,7 +210,7 @@ static void tcpops_tcp_closed_run_route(struct tcp_connection *con)
 		return;
 	}
 	fmsg = faked_msg_next();
-	fmsg->rcv = con->rcv;
+	fmsg->rcv = tev->con->rcv;
 
 	backup_rt = get_route_type();
 	set_route_type(EVENT_ROUTE);
@@ -224,7 +221,7 @@ static void tcpops_tcp_closed_run_route(struct tcp_connection *con)
 
 int tcpops_handle_tcp_closed(void *data)
 {
-	tcp_event_info_t *tev = (tcp_event_info_t *) data;
+	tcp_closed_event_info_t *tev = (tcp_closed_event_info_t *) data;
 
 	if (tev == NULL || tev->con == NULL) {
 		LM_WARN("received bad TCP closed event\n");
@@ -234,7 +231,7 @@ int tcpops_handle_tcp_closed(void *data)
 	/* run event route if tcp_closed_event == 1 or if the
 	 * F_CONN_CLOSE_EV flag is explicitly set */
 	if (tcp_closed_event == 1 || (tev->con->flags & F_CONN_CLOSE_EV))
-		tcpops_tcp_closed_run_route(tev->con);
+		tcpops_tcp_closed_run_route(tev);
 
 	return 0;
 }

+ 1 - 0
modules/tcpops/tcpops.h

@@ -28,6 +28,7 @@
 #include "../../events.h"
 
 extern int tcp_closed_event;
+extern int tcp_closed_routes[_TCP_CLOSED_REASON_MAX];
 
 int tcpops_get_current_fd(int conid, int *fd);
 int tcpops_acquire_fd_from_tcpmain(int conid, int *fd);

+ 11 - 5
modules/tcpops/tcpops_mod.c

@@ -118,11 +118,17 @@ static int mod_init(void)
 		return -1;
 	}
 
-	if (tcp_closed_event /* register event only if tcp_closed_event != 0 */
-		&& (sr_event_register_cb(SREV_TCP_CLOSED, tcpops_handle_tcp_closed) != 0))
-	{
-		LM_ERR("problem registering tcpops_handle_tcp_closed call-back\n");
-		return -1;
+	if (tcp_closed_event) {
+		/* register event only if tcp_closed_event != 0 */
+		if (sr_event_register_cb(SREV_TCP_CLOSED, tcpops_handle_tcp_closed) != 0) {
+			LM_ERR("problem registering tcpops_handle_tcp_closed call-back\n");
+			return -1;
+		}
+
+		/* get event routes */
+		tcp_closed_routes[TCP_CLOSED_EOF] = route_get(&event_rt, "tcp:closed");
+		tcp_closed_routes[TCP_CLOSED_TIMEOUT] = route_get(&event_rt, "tcp:timeout");
+		tcp_closed_routes[TCP_CLOSED_RESET] = route_get(&event_rt, "tcp:reset");
 	}
 
 	return 0;

+ 13 - 0
tcp_conn.h

@@ -335,6 +335,19 @@ typedef struct tcp_event_info {
 	struct tcp_connection *con;
 } tcp_event_info_t;
 
+enum tcp_closed_reason {
+	TCP_CLOSED_EOF = 0,
+	TCP_CLOSED_TIMEOUT,
+	TCP_CLOSED_RESET,
+
+	_TCP_CLOSED_REASON_MAX /* /!\ keep this one always at the end */
+};
+
+typedef struct tcp_closed_event_info {
+	enum tcp_closed_reason reason;
+	struct tcp_connection *con;
+} tcp_closed_event_info_t;
+
 typedef struct ws_event_info {
 	int type;
 	char *buf;

+ 9 - 11
tcp_read.c

@@ -186,17 +186,16 @@ int tcp_http11_continue(struct tcp_connection *c)
 }
 #endif /* HTTP11 */
 
-static int tcp_make_closed_event(struct receive_info* rcv_info, struct tcp_connection* con)
+static int tcp_emit_closed_event(struct tcp_connection *con, enum tcp_closed_reason reason)
 {
 	int ret;
-	tcp_event_info_t tev;
+	tcp_closed_event_info_t tev;
 
 	ret = 0;
 	LM_DBG("TCP closed event creation triggered\n");
 	if(likely(sr_event_enabled(SREV_TCP_CLOSED))) {
-		memset(&tev, 0, sizeof(tcp_event_info_t));
-		tev.type = SREV_TCP_CLOSED;
-		tev.rcv = rcv_info;
+		memset(&tev, 0, sizeof(tcp_closed_event_info_t));
+		tev.reason = reason;
 		tev.con = con;
 		ret = sr_event_exec(SREV_TCP_CLOSED, (void*)(&tev));
 	} else {
@@ -291,19 +290,18 @@ again:
 						strerror(errno), errno,
 						ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
 				LOG(cfg_get(core, core_cfg, corelog),"-> [%s]:%u)\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port);
-				if((errno == ECONNRESET || errno == ETIMEDOUT) && likely(c->rcv.proto_reserved1 != 0)){
-					tcp_make_closed_event(&c->rcv, c);
+				if (errno == ETIMEDOUT) {
+					tcp_emit_closed_event(c, TCP_CLOSED_TIMEOUT);
+				} else if (errno == ECONNRESET) {
+					tcp_emit_closed_event(c, TCP_CLOSED_RESET);
 				}
-
 				return -1;
 			}
 		}else if (unlikely((bytes_read==0) || 
 					(*flags & RD_CONN_FORCE_EOF))){
 			c->state=S_CONN_EOF;
 			*flags|=RD_CONN_EOF;
-			if (likely(c->rcv.proto_reserved1 != 0)){
-				tcp_make_closed_event(&c->rcv, c);
-			}
+			tcp_emit_closed_event(c, TCP_CLOSED_EOF);
 			LM_DBG("EOF on %p, FD %d ([%s]:%u ->", c, fd, ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
 			LM_DBG("-> [%s]:%u)\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port);
 		}else{