Hello,

I've made a patch to kamailio-4.0.3 which removes stale registration when kamailio looses an incoming tcp connection.
Of course this patch needs more work.

Since the are no direct references between user location contacts and tcp connections callback function uses linear search through the whole location table using received field as a key.

Can anybody more experienced in kamailio internals check if I chose the right place to get information about lost tcp connections ? Another thing I wanted to ask is maybe somebody can suggest a better way to tie a tcp connection to the user location information without complicating "usrloc" module by any heavy data structures.

If anybody else except me need this It would be great to fix known problems and add it to kamailio.
diff -uNr kamailio-4.0.3/events.c sshfs-4.0.3/events.c
--- kamailio-4.0.3/events.c	2013-08-15 16:42:39.000000000 +0300
+++ sshfs-4.0.3/events.c	2013-08-26 17:02:15.000000000 +0300
@@ -106,6 +106,11 @@
 					_sr_events_list.tcp_ws_frame_out = f;
 				else return -1;
 			break;
+		case SREV_TCP_CONN_LOST:
+				if(_sr_events_list.tcp_conn_lost==0)
+					_sr_events_list.tcp_conn_lost = f;
+				else return -1;
+			break;
 		default:
 			return -1;
 	}
@@ -209,6 +214,12 @@
 					ret = _sr_events_list.tcp_ws_frame_out(data);
 					return ret;
 				} else return 1;
+		case SREV_TCP_CONN_LOST:
+				if(unlikely(_sr_events_list.tcp_conn_lost!=0))
+				{
+					ret = _sr_events_list.tcp_conn_lost(data);
+					return ret;
+				} else return 1;
 		default:
 			return -1;
 	}
@@ -242,6 +253,8 @@
 				return (_sr_events_list.tcp_ws_frame_in!=0)?1:0;
 		case SREV_TCP_WS_FRAME_OUT:
 				return (_sr_events_list.tcp_ws_frame_out!=0)?1:0;
+		case SREV_TCP_CONN_LOST:
+				return (_sr_events_list.tcp_conn_lost!=0)?1:0;
 	}
 	return 0;
 }
diff -uNr kamailio-4.0.3/events.h sshfs-4.0.3/events.h
--- kamailio-4.0.3/events.h	2013-08-15 16:42:39.000000000 +0300
+++ sshfs-4.0.3/events.h	2013-08-26 17:01:51.000000000 +0300
@@ -30,10 +30,11 @@
 #define SREV_PKG_SET_USED		5
 #define SREV_PKG_SET_REAL_USED	6
 #define SREV_NET_DGRAM_IN		7
-#define SREV_TCP_HTTP_100C		8
-#define SREV_TCP_MSRP_FRAME		9
-#define SREV_TCP_WS_FRAME_IN		10
-#define SREV_TCP_WS_FRAME_OUT		11
+#define SREV_TCP_HTTP_100C      8
+#define SREV_TCP_MSRP_FRAME     9
+#define SREV_TCP_WS_FRAME_IN    10
+#define SREV_TCP_WS_FRAME_OUT   11
+#define SREV_TCP_CONN_LOST      12
 
 
 typedef int (*sr_event_cb_f)(void *data);
@@ -50,6 +51,7 @@
 	sr_event_cb_f tcp_msrp_frame;
 	sr_event_cb_f tcp_ws_frame_in;
 	sr_event_cb_f tcp_ws_frame_out;
+	sr_event_cb_f tcp_conn_lost;
 } sr_event_cb_t;
 
 void sr_event_cb_init(void);
diff -uNr kamailio-4.0.3/modules/usrloc/tcp_conn_cb.c sshfs-4.0.3/modules/usrloc/tcp_conn_cb.c
--- kamailio-4.0.3/modules/usrloc/tcp_conn_cb.c	1970-01-01 03:00:00.000000000 +0300
+++ sshfs-4.0.3/modules/usrloc/tcp_conn_cb.c	2013-08-26 18:36:16.000000000 +0300
@@ -0,0 +1,179 @@
+#include "../../dprint.h"
+#include "../../tcp_conn.h"
+#include "../../ip_addr.h"
+#include "tcp_conn_cb.h"
+#include "usrloc.h"
+#include "dlist.h"
+#include "udomain.h"
+#include "urecord.h"
+#include "ucontact.h"
+
+/* result points to a static buffer.
+ * Ones should copy it before the next call to not loose data */
+static int
+create_rcv_uri(str* uri, struct tcp_connection *c)
+{
+	static char buf[MAX_URI_SIZE];
+	char *p;
+	str ip, port;
+	int len;
+	str proto;
+
+	if (!uri || !c) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	ip.s = ip_addr2a(&c->rcv.src_ip);
+	ip.len = strlen(ip.s);
+
+	port.s = int2str(c->rcv.src_port, &port.len);
+
+	switch(c->rcv.proto) {
+	case PROTO_NONE:
+	case PROTO_UDP:
+		proto.s = 0; /* Do not add transport parameter, UDP is default */
+		proto.len = 0;
+		break;
+
+	case PROTO_TCP:
+		proto.s = "TCP";
+		proto.len = 3;
+		break;
+
+	case PROTO_TLS:
+		proto.s = "TLS";
+		proto.len = 3;
+		break;
+
+	case PROTO_SCTP:
+		proto.s = "SCTP";
+		proto.len = 4;
+		break;
+
+	case PROTO_WS:
+	case PROTO_WSS:
+		proto.s = "WS";
+		proto.len = 2;
+		break;
+
+	default:
+		LM_ERR("unknown transport protocol\n");
+		return -1;
+	}
+
+	/* "sip:" + ip + "[only for ipv6]" + ":" + "port" */
+	len = 4 + ip.len + 2*(c->rcv.src_ip.af==AF_INET6) + 1 + port.len;
+	if (proto.s) {
+		len += TRANSPORT_PARAM_LEN;
+		len += proto.len;
+	}
+
+	if (len > MAX_URI_SIZE) {
+		LM_ERR("buffer too small\n");
+		return -1;
+	}
+
+	p = buf;
+	memcpy(p, "sip:", 4);
+	p += 4;
+
+	if (c->rcv.src_ip.af==AF_INET6)
+		*p++ = '[';
+	memcpy(p, ip.s, ip.len);
+	p += ip.len;
+	if (c->rcv.src_ip.af==AF_INET6)
+		*p++ = ']';
+
+	*p++ = ':';
+
+	memcpy(p, port.s, port.len);
+	p += port.len;
+
+	if (proto.s) {
+		memcpy(p, TRANSPORT_PARAM, TRANSPORT_PARAM_LEN);
+		p += TRANSPORT_PARAM_LEN;
+
+		memcpy(p, proto.s, proto.len);
+		p += proto.len;
+	}
+
+	uri->s = buf;
+	uri->len = len;
+
+	return 0;
+}
+
+static int remove_by_rcv(str *rcv)
+{
+	udomain_t *d = NULL;
+	urecord_t *r = NULL;
+	ucontact_t *c = NULL;
+	str d_name = {"location", strlen("location")};
+	int rc = -1;
+
+	if (find_domain(&d_name, &d) != 0) {
+		LM_ERR("Domain [%.*s] is not found\n", d_name.len, d_name.s);
+		return rc;
+	}
+
+	/* loop through hslots */
+	int i;
+	for (i=0; i < d->size; i++) {
+
+		lock_ulslot(d, i);
+
+		/* loop through records */
+		for (r=d->table[i].first; r; r=r->next) {
+			/* loop through contacts */
+			for (c=r->contacts; c; c=c->next) {
+				if (c->received.s == NULL)
+					continue; /* skip contact with no received field */
+
+				LM_DBG("Comparing [%.*s] to pattern [%.*s]\n", c->received.len, c->received.s,
+				                                               rcv->len, rcv->s);
+				int len = (rcv->len < c->received.len) ? rcv->len : c->received.len;
+				if (!strncasecmp(c->received.s, rcv->s, len)) {
+					rc = delete_ucontact(r, c);
+					if (!rc) break;
+				}
+			}
+
+			if (!rc) break;
+		}
+
+		unlock_ulslot(d, i);
+
+		/* successfuly removed */
+		if (!rc) break;
+	}
+
+	if (rc)
+		LM_DBG("no contacts with received [%.*s] were found\n", rcv->len, rcv->s);
+
+	return rc;
+}
+
+static int handle_conn_lost(struct tcp_connection *c)
+{
+	str uri;
+
+	if (create_rcv_uri(&uri, c) < 0) {
+		LM_ERR("Error creating received uri\n");
+		return -1;
+	}
+
+	return remove_by_rcv(&uri);
+}
+
+int tcp_conn_lost_cb(void *data)
+{
+	struct tcp_connection *c = (struct tcp_connection *)data;
+
+	LM_DBG("TCP connection lost callback called for [%p]\n", data);
+
+	if (c->flags&F_CONN_PASSIVE) /* Try to remove only contacts added by incoming tcp connections */
+		return handle_conn_lost(c);
+	else
+		return -1;
+}
diff -uNr kamailio-4.0.3/modules/usrloc/tcp_conn_cb.h sshfs-4.0.3/modules/usrloc/tcp_conn_cb.h
--- kamailio-4.0.3/modules/usrloc/tcp_conn_cb.h	1970-01-01 03:00:00.000000000 +0300
+++ sshfs-4.0.3/modules/usrloc/tcp_conn_cb.h	2013-08-26 18:36:19.000000000 +0300
@@ -0,0 +1,6 @@
+#ifndef TCP_CONN_CB_H_
+#define TCP_CONN_CB_H_
+
+int tcp_conn_lost_cb(void *data);
+
+#endif /* TCP_CONN_CB_H_ */
diff -uNr kamailio-4.0.3/modules/usrloc/ul_mod.c sshfs-4.0.3/modules/usrloc/ul_mod.c
--- kamailio-4.0.3/modules/usrloc/ul_mod.c	2013-08-15 16:42:39.000000000 +0300
+++ sshfs-4.0.3/modules/usrloc/ul_mod.c	2013-08-26 17:10:03.000000000 +0300
@@ -55,6 +55,7 @@
 #include "ul_mod.h"
 #include "../../sr_module.h"
 #include "../../dprint.h"
+#include "../../events.h"    /* sr_event_register_cb */
 #include "../../rpc_lookup.h"
 #include "../../timer.h"     /* register_timer */
 #include "../../timer_proc.h" /* register_sync_timer */
@@ -69,6 +70,7 @@
 #include "ul_rpc.h"
 #include "ul_callback.h"
 #include "usrloc.h"
+#include "tcp_conn_cb.h"
 
 MODULE_VERSION
 
@@ -387,6 +389,12 @@
 			return -1;
 		}
 	}
+
+	if (sr_event_register_cb(SREV_TCP_CONN_LOST, tcp_conn_lost_cb) != 0) {
+		LM_ERR("registering tcp connection lost callback [%p] failed\n", tcp_conn_lost_cb);
+		return -1;
+	}
+
 	init_flag = 1;
 
 	return 0;
diff -uNr kamailio-4.0.3/tcp_read.c sshfs-4.0.3/tcp_read.c
--- kamailio-4.0.3/tcp_read.c	2013-08-15 16:42:39.000000000 +0300
+++ sshfs-4.0.3/tcp_read.c	2013-08-26 17:26:50.000000000 +0300
@@ -1454,6 +1454,11 @@
 			c->fd=-1;
 		}
 		/* errno==EINTR, EWOULDBLOCK a.s.o todo */
+
+		if (state < 0 && likely(sr_event_enabled(SREV_TCP_CONN_LOST))) {
+			sr_event_exec(SREV_TCP_CONN_LOST, (void*)c);
+		}
+
 		response[0]=(long)c;
 		response[1]=state;
 		
_______________________________________________
SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list
sr-users@lists.sip-router.org
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users

Reply via email to