[sr-dev] git:pd/outbound: modules/registrar: RFC 5626 section 6 support

Peter Dunkley peter.dunkley at crocodile-rcs.com
Thu Feb 28 15:41:28 CET 2013


Module: sip-router
Branch: pd/outbound
Commit: 65dc9c8cf35fc3e631380d65e8c99e8f84d465cc
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=65dc9c8cf35fc3e631380d65e8c99e8f84d465cc

Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
Committer: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
Date:   Thu Feb 28 14:40:41 2013 +0000

modules/registrar: RFC 5626 section 6 support

- Behaviour when outbound in use but first edge proxy does not
  support it.

---

 modules/registrar/reply.c  |   11 ++++--
 modules/registrar/rerrno.h |    3 +-
 modules/registrar/save.c   |   79 ++++++++++++++++++++++++++++++++++++--------
 3 files changed, 75 insertions(+), 18 deletions(-)

diff --git a/modules/registrar/reply.c b/modules/registrar/reply.c
index 4b05aa7..129e7d6 100644
--- a/modules/registrar/reply.c
+++ b/modules/registrar/reply.c
@@ -375,6 +375,7 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 #define MSG_400 "Bad Request"
 #define MSG_420 "Bad Extension"
 #define MSG_421 "Extension Required"
+#define MSG_439 "First Hop Lacks Outbound Support"
 #define MSG_500 "Server Internal Error"
 #define MSG_503 "Service Unavailable"
 
@@ -410,6 +411,7 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 #define EI_R_PATH_UNSUP  "No support for found Path indicated"      /* R_PATH_UNSUP */
 #define EI_R_OB_UNSUP    "No support for Outbound indicated"        /* R_OB_UNSUP */
 #define EI_R_OB_REQD     "No support for Outbound on server"        /* R_OB_REQD */
+#define EI_R_OB_UNSUP_EDGE "No support for Outbound on edge proxy"  /* R_OB_UNSUP_EDGE */
 
 
 str error_info[] = {
@@ -444,7 +446,8 @@ str error_info[] = {
 	{EI_R_PARSE_PATH, sizeof(EI_R_PARSE_PATH) - 1},
 	{EI_R_PATH_UNSUP, sizeof(EI_R_PATH_UNSUP) - 1},
 	{EI_R_OB_UNSUP,   sizeof(EI_R_OB_UNSUP) - 1},
-	{EI_R_OB_REQD,   sizeof(EI_R_OB_REQD) - 1},
+	{EI_R_OB_REQD,    sizeof(EI_R_OB_REQD) - 1},
+	{EI_R_OB_UNSUP_EDGE, sizeof(EI_R_OB_UNSUP_EDGE) - 1},
 };
 
 int codes[] = {
@@ -479,7 +482,8 @@ int codes[] = {
 	400, /* R_PARSE_PATH */
 	420, /* R_PATH_UNSUP */
 	421, /* R_OB_UNSUP */
-	420  /* R_OB_REQD */
+	420, /* R_OB_REQD */
+	439, /* R_OB_UNSUP_EDGE */
 };
 
 
@@ -700,7 +704,8 @@ int reg_send_reply(struct sip_msg* _m)
 	case 200: msg.s = MSG_200; msg.len = sizeof(MSG_200)-1;break;
 	case 400: msg.s = MSG_400; msg.len = sizeof(MSG_400)-1;break;
 	case 420: msg.s = MSG_420; msg.len = sizeof(MSG_420)-1;break;
-	case 421: msg.s = MSG_420; msg.len = sizeof(MSG_421)-1;break;
+	case 421: msg.s = MSG_421; msg.len = sizeof(MSG_421)-1;break;
+	case 439: msg.s = MSG_439; msg.len = sizeof(MSG_439)-1;break;
 	case 500: msg.s = MSG_500; msg.len = sizeof(MSG_500)-1;break;
 	case 503: msg.s = MSG_503; msg.len = sizeof(MSG_503)-1;break;
 	}
diff --git a/modules/registrar/rerrno.h b/modules/registrar/rerrno.h
index 9bc9338..535be04 100644
--- a/modules/registrar/rerrno.h
+++ b/modules/registrar/rerrno.h
@@ -65,7 +65,8 @@ typedef enum rerr {
 	R_PARSE_PATH, /*!< Error while parsing Path */
 	R_PATH_UNSUP, /*!< Path not supported by UAC */
 	R_OB_UNSUP,   /*!< Outbound not supported by UAC */
-	R_OB_REQD     /*!< Outbound required by UAC but not supported on server */
+	R_OB_REQD,    /*!< Outbound required by UAC but not supported on server */
+	R_OB_UNSUP_EDGE, /*!< Outbound needed for this registration but not supported on edge proxy */
 
 } rerr_t;
 
diff --git a/modules/registrar/save.c b/modules/registrar/save.c
index b7a4035..d568334 100644
--- a/modules/registrar/save.c
+++ b/modules/registrar/save.c
@@ -50,6 +50,7 @@
 #include "../../parser/parse_allow.h"
 #include "../../parser/parse_methods.h"
 #include "../../parser/msg_parser.h"
+#include "../../parser/parse_rr.h"
 #include "../../parser/parse_to.h"
 #include "../../parser/parse_uri.h"
 #include "../../dprint.h"
@@ -217,8 +218,7 @@ static inline int no_contacts(sip_msg_t *_m, udomain_t* _d, str* _a, str* _h)
 /*! \brief
  * Fills the common part (for all contacts) of the info structure
  */
-static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
-											unsigned int _e, unsigned int _f)
+static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, int _use_regid)
 {
 	static ucontact_info_t ci;
 	static str no_ua = str_init("n/a");
@@ -365,7 +365,7 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 		}
 		if(_c->instance!=NULL && _c->instance->body.len>0)
 			ci.instance = _c->instance->body;
-		if(_c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) {
+		if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) {
 			if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0)
 			{
 				LM_ERR("invalid reg-id value\n");
@@ -424,7 +424,7 @@ int reg_get_crt_max_contacts(void)
  * and insert all contacts from the message that have expires
  * > 0
  */
-static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
+static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a, int _use_regid)
 {
 	ucontact_info_t* ci;
 	urecord_t* r = NULL;
@@ -480,7 +480,7 @@ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
 		}
 
 		/* pack the contact_info */
-		if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags))==0 ) {
+		if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags, _use_regid))==0 ) {
 			LM_ERR("failed to extract contact info\n");
 			goto error;
 		}
@@ -607,8 +607,7 @@ static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
  * 3) If contact in usrloc exists and expires
  *    == 0, delete contact
  */
-static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
-										int _mode)
+static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, int _mode, int _use_regid)
 {
 	ucontact_info_t *ci;
 	ucontact_t *c, *ptr, *ptr0;
@@ -627,7 +626,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 
 	rc = 0;
 	/* pack the contact_info */
-	if ( (ci=pack_ci( _m, 0, 0, flags))==0 ) {
+	if ( (ci=pack_ci( _m, 0, 0, flags, _use_regid))==0 ) {
 		LM_ERR("failed to initial pack contact info\n");
 		goto error;
 	}
@@ -658,7 +657,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 		calc_contact_expires(_m, _c->expires, &expires);
 
 		/* pack the contact info */
-		if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
+		if ( (ci=pack_ci( 0, _c, expires, 0, _use_regid))==0 ) {
 			LM_ERR("failed to pack contact specific info\n");
 			goto error;
 		}
@@ -774,7 +773,7 @@ error:
  * contained some contact header fields
  */
 static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
-		str* _a, int _mode)
+		str* _a, int _mode, int _use_regid)
 {
 	int res;
 	int ret;
@@ -796,7 +795,7 @@ static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
 	}
 
 	if (res == 0) { /* Contacts found */
-		if ((ret=update_contacts(_m, r, _mode)) < 0) {
+		if ((ret=update_contacts(_m, r, _mode, _use_regid)) < 0) {
 			build_contact(_m, r->contacts, &u->host);
 			ul.release_urecord(r);
 			ul.unlock_udomain(_d, _a);
@@ -805,7 +804,7 @@ static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
 		build_contact(_m, r->contacts, &u->host);
 		ul.release_urecord(r);
 	} else {
-		if (insert_contacts(_m, _d, _a) < 0) {
+		if (insert_contacts(_m, _d, _a, _use_regid) < 0) {
 			ul.unlock_udomain(_d, _a);
 			return -4;
 		}
@@ -827,6 +826,12 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	str aor;
 	int ret;
 	sip_uri_t *u;
+	rr_t *route;
+	struct sip_uri puri;
+	param_hooks_t hooks;
+	param_t *params;
+	contact_t *contact;
+	int use_ob = 1, use_regid = 1;
 
 	u = parse_to_uri(_m);
 	if(u==NULL)
@@ -855,12 +860,58 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	if (parse_require(_m) == 0) {
 		if (!(get_require(_m) & F_OPTION_TAG_OUTBOUND)
 				&& reg_outbound_mode == REG_OUTBOUND_NONE) {
-			LM_WARN("Outbound required by client and not supported by server\n");
+			LM_WARN("Outbound required by UAC and not supported by server\n");
 			rerrno = R_OB_REQD;
 			goto error;
 		}
 	}
 
+	if (reg_outbound_mode != REG_OUTBOUND_NONE
+		&& !(parse_headers(_m, HDR_VIA2_F, 0) == -1 || _m->via2 == 0
+			|| _m->via2->error != PARSE_OK)) {
+		/* Outbound supported on server, and more than one Via: - not the first hop */
+
+		if (!(parse_headers(_m, HDR_PATH_F, 0) == -1 || _m->path == 0)) {
+			if (parse_rr_body(_m->path->body.s, _m->path->body.len, &route) < 0) {
+				LM_ERR("Failed to parse Path: header body\n");
+				goto error;
+			}
+			if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) {
+				LM_ERR("Failed to parse Path: URI\n");
+				goto error;
+			}
+			if (parse_params(&puri.params, CLASS_URI, &hooks, &params) != 0) {
+				LM_ERR("Failed to parse Path: URI parameters\n");
+				goto error;
+			}
+			if (!hooks.uri.ob) {
+				/* No ;ob parameter to top Path: URI - no outbound */
+				use_ob = 0;
+			}
+
+		} else {
+			/* No Path: header - no outbound */
+			use_ob = 0;
+
+		}
+
+		contact = ((contact_body_t *) _m->contact->parsed)->contacts;
+		if (!contact) {
+			LM_ERR("empty Contact:\n");
+			goto error;
+		}
+
+		if (use_ob == 0 && (get_supported(_m) & F_OPTION_TAG_OUTBOUND)
+			&& contact->reg_id) {
+			LM_WARN("Outbound used by UAC but not supported by edge proxy\n");
+			rerrno = R_OB_UNSUP_EDGE;
+			goto error;
+		} else {
+			/* ignore ;reg-id parameter */
+			use_regid = 0;
+		}
+	}
+
 	
 	get_act_time();
 	c = get_first_contact(_m);
@@ -882,7 +933,7 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 		}
 	} else {
 		mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
-		if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0)
+		if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode, use_regid)) < 0)
 			goto error;
 		ret = (ret==0)?1:ret;
 	}




More information about the sr-dev mailing list