[asterisk-commits] dvossel: branch dvossel/sip_request_transaction_matching r275386 - in /team/d...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jul 9 16:16:20 CDT 2010
Author: dvossel
Date: Fri Jul 9 16:16:16 2010
New Revision: 275386
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=275386
Log:
store info from top via of initial Request, detect loops by comparing branch parameter
Modified:
team/dvossel/sip_request_transaction_matching/channels/chan_sip.c
team/dvossel/sip_request_transaction_matching/channels/sip/include/reqresp_parser.h
team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h
team/dvossel/sip_request_transaction_matching/channels/sip/reqresp_parser.c
Modified: team/dvossel/sip_request_transaction_matching/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/sip_request_transaction_matching/channels/chan_sip.c?view=diff&rev=275386&r1=275385&r2=275386
==============================================================================
--- team/dvossel/sip_request_transaction_matching/channels/chan_sip.c (original)
+++ team/dvossel/sip_request_transaction_matching/channels/chan_sip.c Fri Jul 9 16:16:16 2010
@@ -6913,6 +6913,15 @@
}
if (req) {
+ char *sent_by, *branch;
+ /* get branch parameter from initial Request that started this dialog */
+ get_viabranch(ast_strdupa(get_header(req, "Via")), &branch, &sent_by);
+ /* 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);
+ }
set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
} else {
set_socket_transport(&p->socket, SIP_TRANSPORT_UDP);
@@ -7026,7 +7035,6 @@
static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method)
{
struct sip_pvt *p = NULL;
- char *tag = ""; /* note, tag is never NULL */
char totag[128];
char fromtag[128];
const char *callid = get_header(req, "Call-ID");
@@ -7059,8 +7067,6 @@
req->has_to_tag = 1; /* Used in handle_request/response */
gettag(req, "From", fromtag, sizeof(fromtag));
- tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
-
ast_debug(5, "= Looking for Call ID: %s (Checking %s) --From tag %s --To-tag %s \n", callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
/* All messages must always have From: tag */
@@ -7091,37 +7097,76 @@
};
struct ao2_iterator *iterator = ao2_t_find(dialogs, &tmp_dialog, OBJ_POINTER | OBJ_MULTIPLE,
"pedantic ao2_find in dialogs");
- if (iterator) {
- int found = TRUE;
-
- while ((sip_pvt_ptr = ao2_iterator_next(iterator))) {
- if (req->method != SIP_REGISTER) {
- found = ast_strlen_zero(tag) || ast_strlen_zero(sip_pvt_ptr->theirtag) ||
- !ast_test_flag(&sip_pvt_ptr->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED) ||
- !strcmp(sip_pvt_ptr->theirtag, tag);
+ /* Iterate a list of dialogs already matched by Call-id */
+ while (iterator && (sip_pvt_ptr = ao2_iterator_next(iterator))) {
+ if (req->method == SIP_RESPONSE) {
+ /* MATCH RESPONSE with DIALOG */
+ /* check totag if we have one stored for this dialog */
+ if (!ast_strlen_zero(sip_pvt_ptr->theirtag)) {
+ if (ast_strlen_zero(totag)) {
+ /* missing totag when they already gave us one earlier */
+ goto not_a_match;
+ }
+ if (strcmp(totag, sip_pvt_ptr->theirtag)) {
+ /* The totag of the response does not match the one we have stored */
+ goto not_a_match;
+ }
}
- ast_debug(5, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match",
- sip_pvt_ptr->callid, sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
- /* If we get a new request within an existing to-tag - check the to tag as well */
- if (found && req->method != SIP_RESPONSE) { /* SIP Request */
- if (sip_pvt_ptr->tag[0] == '\0' && totag[0]) {
- /* We have no to tag, but they have. Wrong dialog */
- found = FALSE;
- } else if (totag[0]) { /* Both have tags, compare them */
- if (strcmp(totag, sip_pvt_ptr->tag)) {
- found = FALSE; /* This is not our packet */
+ /* check fromtag of response matches the tag we gave them. */
+ if (strcmp(fromtag, sip_pvt_ptr->tag)) {
+ /* fromtag from response does not match our tag */
+ goto not_a_match;
+ }
+ } else {
+ /* MATCH REQUEST with DIALOG */
+ /* Verify the fromtag of Request matches the tag they provided earlier. */
+ if (strcmp(fromtag, sip_pvt_ptr->theirtag)) {
+ /* their tag does not match the one was have stored for them */
+ goto not_a_match;
+ }
+ /* if totag is present in Request, verify it matches what we gave them as our tag earlier */
+ if (!ast_strlen_zero(totag) && (strcmp(totag, sip_pvt_ptr->tag))) {
+ /* totag from Request does not match our tag */
+ goto not_a_match;
+ }
+ /* If totag is NOT present in Request, compare branch parameters with initial Request */
+ if (ast_strlen_zero(totag) && !ast_strlen_zero(sip_pvt_ptr->initviabranch)) {
+ char *sent_by, *branch;
+ /* get branch parameter from top VIA header of Request */
+ get_viabranch(ast_strdupa(get_header(req, "Via")), &branch, &sent_by);
+ if (ast_strlen_zero(branch) ||
+ strcmp(branch, sip_pvt_ptr->initviabranch) ||
+ ast_strlen_zero(sent_by) ||
+ strcmp(sent_by, sip_pvt_ptr->initviasentby)) {
+
+ /* If we made it in here, the branch and sent_by of top VIA did not match our initial Request */
+ if (sip_pvt_ptr->method != req->method) {
+ /* If the methods are not the same, then this is just a normal mismatch. */
+ goto not_a_match;
+ } else {
+ /* Loop Detected: everything is the EXACT same about this Request and the initial
+ * request except the branch parameters are different in the TOP VIA. */
+ goto loop_detected;
}
}
- if (!found)
- ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n",
- sip_pvt_ptr->callid, totag, sip_methods[req->method].text);
}
- if (found) {
- sip_pvt_lock(sip_pvt_ptr);
- ao2_iterator_destroy(iterator);
- return sip_pvt_ptr;
- }
- }
+ }
+ /* If we made it here, then this is a match. Leave the reference from the iterator */
+ sip_pvt_lock(sip_pvt_ptr);
+ ao2_iterator_destroy(iterator);
+ return sip_pvt_ptr;
+
+loop_detected:
+ /* This is likely a forked Request that somehow resulted in us receiving multiple parts of the fork.
+ * RFC 3261 section 8.2.2.2, Indicate that we want to merge requests by sending a 482 response. */
+ transmit_response_using_temp(callid, addr, 1, intended_method, req, "482 (Loop Detected)");
+ dialog_unref(sip_pvt_ptr, "This pvt did not match incomming SIP msg, unref pvt from find_call search.");
+ return NULL;
+not_a_match:
+ dialog_unref(sip_pvt_ptr, "This pvt did not match incomming SIP msg, unref pvt from find_call search.");
+ } /* end of while */
+
+ if (iterator) {
ao2_iterator_destroy(iterator);
}
}
Modified: team/dvossel/sip_request_transaction_matching/channels/sip/include/reqresp_parser.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/sip_request_transaction_matching/channels/sip/include/reqresp_parser.h?view=diff&rev=275386&r1=275385&r2=275386
==============================================================================
--- team/dvossel/sip_request_transaction_matching/channels/sip/include/reqresp_parser.h (original)
+++ team/dvossel/sip_request_transaction_matching/channels/sip/include/reqresp_parser.h Fri Jul 9 16:16:16 2010
@@ -142,4 +142,10 @@
*/
unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len);
+/*!
+ * \brief Parse the VIA header into it's parts.
+ *
+ * \note This will modify the string
+ */
+void get_viabranch(char *via, char **sent_by, char **branch);
#endif
Modified: team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h?view=diff&rev=275386&r1=275385&r2=275386
==============================================================================
--- team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h (original)
+++ team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h Fri Jul 9 16:16:16 2010
@@ -910,6 +910,8 @@
int method; /*!< SIP method that opened this dialog */
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(callid); /*!< Global CallID */
+ AST_STRING_FIELD(initviabranch); /*!< The branch ID from the topmost Via header in the initial request */
+ AST_STRING_FIELD(initviasentby); /*!< The sent-by from the topmost Via header in the initial request */
AST_STRING_FIELD(randdata); /*!< Random data */
AST_STRING_FIELD(accountcode); /*!< Account code */
AST_STRING_FIELD(realm); /*!< Authorization realm */
Modified: team/dvossel/sip_request_transaction_matching/channels/sip/reqresp_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/sip_request_transaction_matching/channels/sip/reqresp_parser.c?view=diff&rev=275386&r1=275385&r2=275386
==============================================================================
--- team/dvossel/sip_request_transaction_matching/channels/sip/reqresp_parser.c (original)
+++ team/dvossel/sip_request_transaction_matching/channels/sip/reqresp_parser.c Fri Jul 9 16:16:16 2010
@@ -1773,6 +1773,150 @@
return res;
}
+void get_viabranch(char *via, char **sent_by, char **branch)
+{
+ char *tmp;
+
+ if (sent_by) {
+ *sent_by = NULL;
+ }
+ if (branch) {
+ *branch = NULL;
+ }
+ if (ast_strlen_zero(via)) {
+ return;
+ }
+ via = ast_skip_blanks(via);
+ /*
+ * VIA syntax. RFC 3261 section 6.40.5
+ * Via = ( "Via" | "v") ":" 1#( sent-protocol sent-by *( ";" via-params ) [ comment ] )
+ * via-params = via-hidden | via-ttl | via-maddr | via-received | via-branch
+ * via-hidden = "hidden"
+ * via-ttl = "ttl" "=" ttl
+ * via-maddr = "maddr" "=" maddr
+ * via-received = "received" "=" host
+ * via-branch = "branch" "=" token
+ * sent-protocol = protocol-name "/" protocol-version "/" transport
+ * protocol-name = "SIP" | token
+ * protocol-version = token
+ * transport = "UDP" | "TCP" | token
+ * sent-by = ( host [ ":" port ] ) | ( concealed-host )
+ * concealed-host = token
+ * ttl = 1*3DIGIT ; 0 to 255
+ */
+
+ /* chop off ("Via:" | "v:") if present */
+ if (!strncasecmp(via, "Via:", 4)) {
+ via += 4;
+ } else if (!strncasecmp(via, "v:", 2)) {
+ via += 2;
+ }
+ if (ast_strlen_zero(via)) {
+ return;
+ }
+
+ /* chop off sent-protocol */
+ via = ast_skip_blanks(via);
+ strsep(&via, " \t\r\n");
+ if (ast_strlen_zero(via)) {
+ return;
+ }
+
+ /* chop off sent-by */
+ via = ast_skip_blanks(via);
+ *sent_by = strsep(&via, "; \t\r\n");
+ if (ast_strlen_zero(via)) {
+ return;
+ }
+
+ /* now see if there is a branch parameter in there */
+ if (!ast_strlen_zero(via) && (tmp = strstr(via, "branch="))) {
+ /* find the branch ID */
+ via = ast_skip_blanks(tmp + 7);
+
+ /* chop off the branch parameter */
+ *branch = strsep(&via, "; \t\r\n");
+ }
+}
+
+AST_TEST_DEFINE(get_viabranch_test)
+{
+ int res = AST_TEST_PASS;
+ int i = 1;
+ char *sent_by, *branch;
+ struct testdata {
+ char *in;
+ char *expected_branch;
+ char *expected_sent_by;
+ AST_LIST_ENTRY(testdata) list;
+ };
+ struct testdata *testdataptr;
+ static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
+ struct testdata t1 = {
+ .in = "Via: SIP/2.0/UDP host:port;branch=thebranch",
+ .expected_branch = "thebranch",
+ .expected_sent_by = "host:port"
+ };
+ struct testdata t2 = {
+ .in = "SIP/2.0/UDP host:port;branch=thebranch",
+ .expected_branch = "thebranch",
+ .expected_sent_by = "host:port"
+ };
+ struct testdata t3 = {
+ .in = "SIP/2.0/UDP host:port",
+ .expected_branch = "",
+ .expected_sent_by = "host:port"
+ };
+ struct testdata t4 = {
+ .in = "BLAH/BLAH/BLAH host:port ; branch= thebranch ;;;;;;;",
+ .expected_branch = "thebranch",
+ .expected_sent_by = "host:port"
+ };
+ struct testdata t5 = {
+ .in = "v: BLAH/BLAH/BLAH",
+ .expected_branch = "",
+ .expected_sent_by = ""
+ };
+ struct testdata t6 = {
+ .in = "BLAH/BLAH/BLAH host:port;branch=",
+ .expected_branch = "",
+ .expected_sent_by = "host:port"
+ };
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "get_viabranch_test";
+ info->category = "channels/chan_sip/";
+ info->summary = "Tests getting sent-by and branch parameter from via";
+ info->description =
+ "Runs through various test situations in which a sent-by and"
+ " branch parameter must be extracted from a VIA header";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
+ AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
+ AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
+
+
+ AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
+ get_viabranch(ast_strdupa(testdataptr->in), &sent_by, &branch);
+ if ((ast_strlen_zero(sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by)) ||
+ (ast_strlen_zero(branch) && !ast_strlen_zero(testdataptr->expected_branch)) ||
+ (!ast_strlen_zero(sent_by) && strcmp(sent_by, testdataptr->expected_sent_by)) ||
+ (!ast_strlen_zero(branch) && strcmp(branch, testdataptr->expected_branch))) {
+ ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\" parsed sent-by = \"%s\" parsed branch = \"%s\"\n",
+ i, testdataptr->in, sent_by, branch);
+ res = AST_TEST_FAIL;
+ }
+ i++;
+ }
+ return res;
+}
void sip_request_parser_register_tests(void)
{
@@ -1784,6 +1928,7 @@
AST_TEST_REGISTER(parse_name_andor_addr_test);
AST_TEST_REGISTER(parse_contact_header_test);
AST_TEST_REGISTER(sip_parse_options_test);
+ AST_TEST_REGISTER(get_viabranch_test);
}
void sip_request_parser_unregister_tests(void)
{
@@ -1795,4 +1940,5 @@
AST_TEST_UNREGISTER(parse_name_andor_addr_test);
AST_TEST_UNREGISTER(parse_contact_header_test);
AST_TEST_UNREGISTER(sip_parse_options_test);
-}
+ AST_TEST_UNREGISTER(get_viabranch_test);
+}
More information about the asterisk-commits
mailing list