diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-07-01 16:40:17 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-07-01 16:40:17 +0000 |
commit | d12a014d5aa559d335c6210a1931a870a2586c2d (patch) | |
tree | 40333dfdabffa545bf218f4d3acc4f694ea727b1 /channels | |
parent | b5f418e3438d24b43bc19772423fd46d77f37524 (diff) |
correct handling of get_destination return values
A failure when calling the get_destination can mean multiple things. If
the extension is not found, a 404 error is appropriate, but if the URI
scheme is incorrect, a 404 is not approperiate. This patch adds the
get_destination_result enum to differentiate between these and other failure
types. The only logical difference in this patch is that we now send a "416
Unsupported URI scheme" response instead of a "404" when the scheme is not
recognized. This indicates to the initiator of the INVITE to retry the request
with a correct URI.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@273427 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 75 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 9 |
2 files changed, 55 insertions, 29 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index c11310810..549c9d7c9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1446,7 +1446,7 @@ static int set_address_from_contact(struct sip_pvt *pvt); static void check_via(struct sip_pvt *p, struct sip_request *req); static int get_rpid(struct sip_pvt *p, struct sip_request *oreq); static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason); -static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id); +static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id); static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline); static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout); static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen); @@ -13622,15 +13622,13 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c We use the request uri as a destination. This code assumes authentication has been done, so that the device (peer/user) context is already set. - \return 0 on success (found a matching extension), - 1 for pickup extension or overlap dialling support (if we support it), - -1 on error. + \return 0 on success (found a matching extension), non-zero on failure \note If the incoming uri is a SIPS: uri, we are required to carry this across the dialplan, so that the outbound call also is a sips: call or encrypted IAX2 call. If that's not available, the call should FAIL. */ -static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id) +static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id) { char tmp[256] = "", *uri, *domain, *dummy = NULL; char tmpf[256] = "", *from = NULL; @@ -13649,7 +13647,7 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ if (parse_uri(uri, "sip:,sips:", &uri, &dummy, &domain, &dummy, NULL)) { ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri); - return -1; + return SIP_GET_DEST_INVALID_URI; } SIP_PEDANTIC_DECODE(domain); @@ -13666,7 +13664,7 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ from = get_in_brackets(tmpf); if (parse_uri(from, "sip:,sips:", &from, NULL, &domain, NULL, NULL)) { ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from); - return -1; + return SIP_GET_DEST_INVALID_URI; } SIP_PEDANTIC_DECODE(from); @@ -13682,7 +13680,7 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ if (!check_sip_domain(p->domain, domain_context, sizeof(domain_context))) { if (!sip_cfg.allow_external_domains && (req->method == SIP_INVITE || req->method == SIP_REFER)) { ast_debug(1, "Got SIP %s to non-local domain '%s'; refusing request.\n", sip_methods[req->method].text, p->domain); - return -2; + return SIP_GET_DEST_REFUSED; } } /* If we don't have a peer (i.e. we're a guest call), @@ -13701,7 +13699,9 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ /* If this is a subscription we actually just need to see if a hint exists for the extension */ if (req->method == SIP_SUBSCRIBE) { char hint[AST_MAX_EXTENSION]; - return (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten) ? 0 : -1); + return (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten) ? + SIP_GET_DEST_EXTEN_FOUND : + SIP_GET_DEST_EXTEN_NOT_FOUND); } else { struct ast_cc_agent *agent; decoded_uri = ast_strdupa(uri); @@ -13711,11 +13711,12 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ Since extensions.conf can have unescaped characters, try matching a decoded uri in addition to the non-decoded uri Return 0 if we have a matching extension */ - if (ast_exists_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from)) || ast_exists_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from)) || + if (ast_exists_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from)) || + ast_exists_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from)) || !strcmp(decoded_uri, ast_pickup_ext())) { if (!oreq) ast_string_field_set(p, exten, decoded_uri); - return 0; + return SIP_GET_DEST_EXTEN_FOUND; } else if ((agent = find_sip_cc_agent_by_notify_uri(tmp))) { struct sip_cc_agent_pvt *agent_pvt = agent->private_data; /* This is a CC recall. We can set p's extension to the exten from @@ -13731,7 +13732,7 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ *cc_recall_core_id = agent->core_id; } ao2_ref(agent, -1); - return 0; + return SIP_GET_DEST_EXTEN_FOUND; } } @@ -13739,10 +13740,10 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_ if((ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP) && ast_canmatch_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))) || !strncmp(decoded_uri, ast_pickup_ext(), strlen(decoded_uri))) { - return 1; + return SIP_GET_DEST_PICKUP_EXTEN_FOUND; } - - return -1; + + return SIP_GET_DEST_EXTEN_NOT_FOUND; } /*! \brief Lock dialog lock and find matching pvt lock @@ -19844,7 +19845,7 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req) return 0; } - res = get_destination(p, req, NULL); + res = (get_destination(p, req, NULL) == SIP_GET_DEST_EXTEN_FOUND ? 0 : -1); build_contact(p); if (ast_strlen_zero(p->context)) @@ -20789,18 +20790,30 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); } - if (!replace_id && gotdest) { /* No matching extension found */ - if (gotdest == 1 && ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) - transmit_response_reliable(p, "484 Address Incomplete", req); - else { - char *decoded_exten = ast_strdupa(p->exten); + if (!replace_id && (gotdest != SIP_GET_DEST_EXTEN_FOUND)) { /* No matching extension found */ + switch(gotdest) { + case SIP_GET_DEST_INVALID_URI: + transmit_response_reliable(p, "416 Unsupported URI scheme", req); + break; + case SIP_GET_DEST_PICKUP_EXTEN_FOUND: + if (ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) { + transmit_response_reliable(p, "484 Address Incomplete", req); + break; + } + /* INTENTIONAL FALL THROUGH */ + case SIP_GET_DEST_EXTEN_NOT_FOUND: + case SIP_GET_DEST_REFUSED: + default: + { + char *decoded_exten = ast_strdupa(p->exten); + transmit_response_reliable(p, "404 Not Found", req); + ast_uri_decode(decoded_exten); + ast_log(LOG_NOTICE, "Call from '%s' to extension" + " '%s' rejected because extension not found in context '%s'.\n", + S_OR(p->username, p->peername), decoded_exten, p->context); + } + } /* end switch */ - transmit_response_reliable(p, "404 Not Found", req); - ast_uri_decode(decoded_exten); - ast_log(LOG_NOTICE, "Call from '%s' to extension" - " '%s' rejected because extension not found in context '%s'.\n", - S_OR(p->username, p->peername), decoded_exten, p->context); - } p->invitestate = INV_COMPLETED; update_call_counter(p, DEC_CALL_LIMIT); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); @@ -22609,8 +22622,12 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, parse_ok_contact(p, req); build_contact(p); - if (gotdest) { - transmit_response(p, "404 Not Found", req); + if (gotdest != SIP_GET_DEST_EXTEN_FOUND) { + if (gotdest == SIP_GET_DEST_INVALID_URI) { + transmit_response(p, "416 Unsupported URI scheme", req); + } else { + transmit_response(p, "404 Not Found", req); + } pvt_set_needdestroy(p, "subscription target not found"); if (authpeer) unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 2)"); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 01cbb2c73..13527517f 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -449,6 +449,15 @@ enum sip_auth_type { WWW_AUTH = 401, }; +/*! \brief Result from get_destination function */ +enum sip_get_dest_result { + SIP_GET_DEST_PICKUP_EXTEN_FOUND = 1, + SIP_GET_DEST_EXTEN_FOUND = 0, + SIP_GET_DEST_EXTEN_NOT_FOUND = -1, + SIP_GET_DEST_REFUSED = -2, + SIP_GET_DEST_INVALID_URI = -3, +}; + /*! \brief Authentication result from check_auth* functions */ enum check_auth_result { AUTH_DONT_KNOW = -100, /*!< no result, need to check further */ |