aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
authormnicholson <mnicholson@f38db490-d61c-443f-a65b-d21fe96a405b>2011-01-26 20:43:27 +0000
committermnicholson <mnicholson@f38db490-d61c-443f-a65b-d21fe96a405b>2011-01-26 20:43:27 +0000
commit08a0b8006c2bb4cd48aea07f77023a12700c421a (patch)
tree04c082e49ef550a14c50d8693377f27257e6dad3 /channels/chan_sip.c
parentf3a3df360d336ed657fc856c65306789b403d088 (diff)
Merged revisions 304244 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r304244 | mnicholson | 2011-01-26 14:42:16 -0600 (Wed, 26 Jan 2011) | 13 lines Merged revisions 304241 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r304241 | mnicholson | 2011-01-26 14:38:22 -0600 (Wed, 26 Jan 2011) | 6 lines This patch modifies chan_sip to route responses to the address the request came from. It also modifies chan_sip to respect the maddr parameter in the Via header. ABE-2664 Review: https://reviewboard.asterisk.org/r/1059/ ........ ................ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.8@304245 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c81
1 files changed, 73 insertions, 8 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 5fa5bdc66..d41ef2109 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -7095,17 +7095,20 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
/* If this dialog is created as the result of an incoming Request. Lets store
* some information about that request */
if (req) {
- char *sent_by, *branch;
+ struct sip_via *via;
const char *cseq = get_header(req, "Cseq");
unsigned int seqno;
/* get branch parameter from initial Request that started this dialog */
- get_viabranch(ast_strdupa(get_header(req, "Via")), &sent_by, &branch);
- /* only store the branch if it begins with the magic prefix "z9hG4bK", otherwise
- * it is not useful to us to have it */
- if (!ast_strlen_zero(branch) && !strncasecmp(branch, "z9hG4bK", 7)) {
- ast_string_field_set(p, initviabranch, branch);
- ast_string_field_set(p, initviasentby, sent_by);
+ via = parse_via(get_header(req, "Via"));
+ if (via) {
+ /* only store the branch if it begins with the magic prefix "z9hG4bK", otherwise
+ * it is not useful to us to have it */
+ if (!ast_strlen_zero(via->branch) && !strncasecmp(via->branch, "z9hG4bK", 7)) {
+ ast_string_field_set(p, initviabranch, via->branch);
+ ast_string_field_set(p, initviasentby, via->sent_by);
+ }
+ free_via(via);
}
/* Store initial incoming cseq. An error in sscanf here is ignored. There is no approperiate
@@ -7217,6 +7220,50 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
return p;
}
+/*!
+ * \brief Check if an ip is an multicast IP.
+ * \parm addr the address to check
+ *
+ * This function checks if an address is in the 224.0.0.0/4 network block.
+ * \return non-zero if this is a multicast address
+ */
+static int addr_is_multicast(const struct ast_sockaddr *addr)
+{
+ return ((ast_sockaddr_ipv4(addr) & 0xf0000000) == 0xe0000000);
+}
+
+static int process_via(struct sip_pvt *p, const struct sip_request *req)
+{
+ struct sip_via *via = parse_via(get_header(req, "Via"));
+
+ if (!via) {
+ ast_log(LOG_ERROR, "error processing via header\n");
+ return -1;
+ }
+
+ if (via->maddr) {
+ if (ast_sockaddr_resolve_first(&p->sa, via->maddr, PARSE_PORT_FORBID)) {
+ ast_log(LOG_WARNING, "Can't find address for maddr '%s'\n", via->maddr);
+ ast_log(LOG_ERROR, "error processing via header\n");
+ free_via(via);
+ return -1;
+ }
+
+ if (via->port) {
+ ast_sockaddr_set_port(&p->sa, via->port);
+ } else {
+ ast_sockaddr_set_port(&p->sa, STANDARD_SIP_PORT);
+ }
+
+ if (addr_is_multicast(&p->sa)) {
+ setsockopt(sipsock, IPPROTO_IP, IP_MULTICAST_TTL, &via->ttl, sizeof(via->ttl));
+ }
+ }
+
+ free_via(via);
+ return 0;
+}
+
/* \brief arguments used for Request/Response to matching */
struct match_req_args {
int method;
@@ -7447,6 +7494,7 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
dialog_find_multiple,
&tmp_dialog,
"pedantic ao2_find in dialogs");
+ struct sip_via *via = NULL;
args.method = req->method;
args.callid = NULL; /* we already matched this. */
@@ -7457,7 +7505,11 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
/* If this is a Request, set the Via and Authorization header arguments */
if (req->method != SIP_RESPONSE) {
args.ruri = REQ_OFFSET_TO_STR(req, rlPart2);
- get_viabranch(ast_strdupa(get_header(req, "Via")), (char **) &args.viasentby, (char **) &args.viabranch);
+ via = parse_via(get_header(req, "Via"));
+ if (via) {
+ args.viasentby = via->sent_by;
+ args.viabranch = via->branch;
+ }
if (!ast_strlen_zero(get_header(req, "Authorization")) ||
!ast_strlen_zero(get_header(req, "Proxy-Authorization"))) {
args.authentication_present = 1;
@@ -7472,6 +7524,7 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
case SIP_REQ_MATCH:
sip_pvt_lock(sip_pvt_ptr);
ao2_iterator_destroy(iterator);
+ free_via(via);
return sip_pvt_ptr; /* return pvt with ref */
case SIP_REQ_LOOP_DETECTED:
/* This is likely a forked Request that somehow resulted in us receiving multiple parts of the fork.
@@ -7479,6 +7532,7 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
transmit_response_using_temp(callid, addr, 1, intended_method, req, "482 (Loop Detected)");
dialog_unref(sip_pvt_ptr, "pvt did not match incoming SIP msg, unref from search.");
ao2_iterator_destroy(iterator);
+ free_via(via);
return NULL;
case SIP_REQ_NOT_MATCH:
default:
@@ -7488,6 +7542,8 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
if (iterator) {
ao2_iterator_destroy(iterator);
}
+
+ free_via(via);
} /* end of pedantic mode Request/Reponse to Dialog matching */
/* See if the method is capable of creating a dialog */
@@ -9537,6 +9593,15 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
ast_string_field_set(p, url, NULL);
}
+ /* default to routing the response to the address where the request
+ * came from. Since we don't have a transport layer, we do this here.
+ */
+ p->sa = p->recv;
+
+ if (process_via(p, req)) {
+ ast_log(LOG_WARNING, "error processing via header, will send response to originating address\n");
+ }
+
return 0;
}