Module: sip-router
Branch: pd/outbound
Commit: 65dc9c8cf35fc3e631380d65e8c99e8f84d465cc
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=65dc9c8…
Author: Peter Dunkley <peter.dunkley(a)crocodile-rcs.com>
Committer: Peter Dunkley <peter.dunkley(a)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, ¶ms) != 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;
}