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