From af723c6572e988753c24cbb911d6b521600f4a3f Mon Sep 17 00:00:00 2001
From: Damien Wedhorn <voip@facts.com.au>
Date: Thu, 19 Dec 2013 00:32:00 +0000
Subject: [PATCH] Fixup skinny registration following network issues.

On session registration, if device is already reporting that it is
connected to a device, an innocuous packet (update time) is sent to
the already connected device. If the tcp connection is down, the
device will be unregistered and the new connection allowed.

Without this patch, network issues can see a situation where a device
can not reregister until after 3*timeout.
........

Merged revisions 404292 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404293 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_skinny.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 49f2c84f60..9d04f2336a 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1651,6 +1651,8 @@ static void activatesub(struct skinny_subchannel *sub, int state);
 static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION]);
 static int skinny_nokeepalive_cb(const void *data);
 
+static void transmit_definetimedate(struct skinny_device *d);
+
 static struct ast_channel_tech skinny_tech = {
 	.type = "Skinny",
 	.description = tdesc,
@@ -2252,6 +2254,7 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
 	struct sockaddr_in sin;
 	socklen_t slen;
 	int instance;
+	int res = -1;
 
 	if (s->auth_timeout_sched && ast_sched_del(sched, s->auth_timeout_sched)) {
 		return 0;
@@ -2262,10 +2265,16 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
 	AST_LIST_TRAVERSE(&devices, d, list){
 		struct ast_sockaddr addr;
 		ast_sockaddr_from_sin(&addr, &s->sin);
-		if (!d->session && !strcasecmp(req->data.reg.name, d->id)
+		if (!strcasecmp(req->data.reg.name, d->id)
 				&& ast_apply_ha(d->ha, &addr)) {
 			RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
+			if (d->session) {
+				ast_log(LOG_WARNING, "Device already registered.\n");
+				transmit_definetimedate(d);
+				res = 0;
+				break;
+			}
 			s->device = d;
 			d->type = letohl(req->data.reg.type);
 			d->protocolversion = letohl(req->data.reg.protocolVersion);
@@ -2311,14 +2320,12 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
 			ast_endpoint_set_state(d->endpoint, AST_ENDPOINT_ONLINE);
 			blob = ast_json_pack("{s: s}", "peer_status", "Registered");
 			ast_endpoint_blob_publish(d->endpoint, ast_endpoint_state_type(), blob);
+			res = 1;
 			break;
 		}
 	}
 	AST_LIST_UNLOCK(&devices);
-	if (!d) {
-		return 0;
-	}
-	return 1;
+	return res;
 }
 
 static void end_session(struct skinnysession *s)
@@ -7276,15 +7283,21 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
 	case REGISTER_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received REGISTER_MESSAGE from %s, name %s, type %d, protovers %d\n",
 			d->name, req->data.reg.name, letohl(req->data.reg.type), letohl(req->data.reg.protocolVersion));
-		if (skinny_register(req, s)) {
-			ast_atomic_fetchadd_int(&unauth_sessions, -1);
-			ast_verb(3, "Device '%s' successfully registered (protoVers %d)\n", s->device->name, s->device->protocolversion);
-			transmit_registerack(s->device);
-			transmit_capabilitiesreq(s->device);
-		} else {
+		res = skinny_register(req, s);
+		if (!res) {
+			sleep(2);
+			res = skinny_register(req, s);
+		}
+		if (res != 1) {
 			transmit_registerrej(s);
 			return -1;
 		}
+		ast_atomic_fetchadd_int(&unauth_sessions, -1);
+		ast_verb(3, "Device '%s' successfully registered (protoVers %d)\n", s->device->name, s->device->protocolversion);
+		transmit_registerack(s->device);
+		transmit_capabilitiesreq(s->device);
+		res = 0;
+		break;
 	case IP_PORT_MESSAGE:
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received IP_PORT_MESSAGE from %s\n", d->name);
 		res = handle_ip_port_message(req, s);
@@ -7564,7 +7577,7 @@ static void *skinny_session(void *data)
 				if (res >= dlen) {
 					break;
 				}
-				ast_log(LOG_WARNING, "Partial data received, waiting\n");
+				ast_log(LOG_WARNING, "Partial data received, waiting (%d bytes read of %d)\n", res, dlen);
 				if (sched_yield() < 0) {
 					ast_log(LOG_WARNING, "Data yield() returned error: %s\n", strerror(errno));
 					break;
-- 
GitLab