Sun May 20 06:36:53 2012

Asterisk developer's documentation


reqresp_parser.c File Reference

sip request parsing functions and unit tests More...

#include "asterisk.h"
#include "include/sip.h"
#include "include/sip_utils.h"
#include "include/reqresp_parser.h"

Include dependency graph for reqresp_parser.c:

Go to the source code of this file.

Defines

#define URI_CMP_MATCH   0
#define URI_CMP_NOMATCH   1

Functions

 AST_TEST_DEFINE (parse_via_test)
 AST_TEST_DEFINE (sip_uri_cmp_test)
 AST_TEST_DEFINE (sip_parse_options_test)
 AST_TEST_DEFINE (parse_contact_header_test)
 AST_TEST_DEFINE (parse_name_andor_addr_test)
 AST_TEST_DEFINE (get_in_brackets_test)
 AST_TEST_DEFINE (get_name_and_number_test)
 AST_TEST_DEFINE (get_calleridname_test)
 AST_TEST_DEFINE (sip_parse_uri_test)
 AST_TEST_DEFINE (sip_parse_uri_full_test)
void free_via (struct sip_via *v)
const char * get_calleridname (const char *input, char *output, size_t outputsize)
 Get caller id name from SIP headers, copy into output buffer.
int get_comma (char *in, char **out)
char * get_in_brackets (char *tmp)
int get_in_brackets_full (char *tmp, char **out, char **residue)
int get_name_and_number (const char *hdr, char **name, char **number)
int parse_contact_header (char *contactheader, struct contactliststruct *contactlist)
int parse_name_andor_addr (char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
unsigned int parse_sip_options (const char *options, char *unsupported, size_t unsupported_len)
 Parse supported header in incoming packet.
int parse_uri (char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
int parse_uri_full (char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
 * parses a URI in its components.
struct sip_via * parse_via (const char *header)
void sip_reqresp_parser_exit (void)
int sip_reqresp_parser_init (void)
void sip_request_parser_register_tests (void)
void sip_request_parser_unregister_tests (void)
int sip_uri_cmp (const char *input1, const char *input2)
static int sip_uri_domain_cmp (const char *host1, const char *host2)
 Compare domain sections of SIP URIs.
static int sip_uri_headers_cmp (const char *input1, const char *input2)
 helper routine for sip_uri_cmp to compare URI headers
static int sip_uri_params_cmp (const char *input1, const char *input2)
 helper routine for sip_uri_cmp to compare URI parameters


Detailed Description

sip request parsing functions and unit tests

Definition in file reqresp_parser.c.


Define Documentation

#define URI_CMP_MATCH   0

Definition at line 2092 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

#define URI_CMP_NOMATCH   1

Definition at line 2093 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().


Function Documentation

AST_TEST_DEFINE ( parse_via_test   ) 

Definition at line 2297 of file reqresp_parser.c.

References AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, free_via(), parse_via(), TEST_EXECUTE, and TEST_INIT.

02298 {
02299    int res = AST_TEST_PASS;
02300    int i = 1;
02301    struct sip_via *via;
02302    struct testdata {
02303       char *in;
02304       char *expected_protocol;
02305       char *expected_branch;
02306       char *expected_sent_by;
02307       char *expected_maddr;
02308       unsigned int expected_port;
02309       unsigned char expected_ttl;
02310       int expected_null;
02311       AST_LIST_ENTRY(testdata) list;
02312    };
02313    struct testdata *testdataptr;
02314    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
02315    struct testdata t1 = {
02316       .in = "SIP/2.0/UDP host:port;branch=thebranch",
02317       .expected_protocol = "SIP/2.0/UDP",
02318       .expected_sent_by = "host:port",
02319       .expected_branch = "thebranch",
02320    };
02321    struct testdata t2 = {
02322       .in = "SIP/2.0/UDP host:port",
02323       .expected_protocol = "SIP/2.0/UDP",
02324       .expected_sent_by = "host:port",
02325       .expected_branch = "",
02326    };
02327    struct testdata t3 = {
02328       .in = "SIP/2.0/UDP",
02329       .expected_null = 1,
02330    };
02331    struct testdata t4 = {
02332       .in = "BLAH/BLAH/BLAH host:port;branch=",
02333       .expected_protocol = "BLAH/BLAH/BLAH",
02334       .expected_sent_by = "host:port",
02335       .expected_branch = "",
02336    };
02337    struct testdata t5 = {
02338       .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
02339       .expected_protocol = "SIP/2.0/UDP",
02340       .expected_sent_by = "host:5060",
02341       .expected_port = 5060,
02342       .expected_branch = "thebranch",
02343       .expected_maddr = "224.0.0.1",
02344       .expected_ttl = 1,
02345    };
02346    struct testdata t6 = {
02347       .in = "SIP/2.0/UDP      host:5060;\n   branch=thebranch;\r\n  maddr=224.0.0.1;   ttl=1",
02348       .expected_protocol = "SIP/2.0/UDP",
02349       .expected_sent_by = "host:5060",
02350       .expected_port = 5060,
02351       .expected_branch = "thebranch",
02352       .expected_maddr = "224.0.0.1",
02353       .expected_ttl = 1,
02354    };
02355    struct testdata t7 = {
02356       .in = "SIP/2.0/UDP [::1]:5060",
02357       .expected_protocol = "SIP/2.0/UDP",
02358       .expected_sent_by = "[::1]:5060",
02359       .expected_port = 5060,
02360       .expected_branch = "",
02361    };
02362    switch (cmd) {
02363    case TEST_INIT:
02364       info->name = "parse_via_test";
02365       info->category = "/channels/chan_sip/";
02366       info->summary = "Tests parsing the Via header";
02367       info->description =
02368             "Runs through various test situations in which various "
02369             " parameters parameter must be extracted from a VIA header";
02370       return AST_TEST_NOT_RUN;
02371    case TEST_EXECUTE:
02372       break;
02373    }
02374 
02375    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
02376    AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
02377    AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
02378    AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
02379    AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
02380    AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
02381    AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
02382 
02383 
02384    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
02385       via = parse_via(testdataptr->in);
02386       if (!via) {
02387               if (!testdataptr->expected_null) {
02388             ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02389                "failed to parse header\n",
02390             i, testdataptr->in);
02391             res = AST_TEST_FAIL;
02392          }
02393          i++;
02394          continue;
02395       }
02396 
02397       if (testdataptr->expected_null) {
02398          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02399             "successfully parased invalid via header\n",
02400          i, testdataptr->in);
02401          res = AST_TEST_FAIL;
02402          free_via(via);
02403          i++;
02404          continue;
02405       }
02406 
02407       if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
02408          || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
02409 
02410          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02411             "parsed protocol = \"%s\"\n"
02412             "expected = \"%s\"\n"
02413             "failed to parse protocol\n",
02414          i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
02415          res = AST_TEST_FAIL;
02416       }
02417 
02418       if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
02419          || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
02420 
02421          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02422             "parsed sent_by = \"%s\"\n"
02423             "expected = \"%s\"\n"
02424             "failed to parse sent-by\n",
02425          i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
02426          res = AST_TEST_FAIL;
02427       }
02428 
02429       if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
02430          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02431             "parsed port = \"%d\"\n"
02432             "expected = \"%d\"\n"
02433             "failed to parse port\n",
02434          i, testdataptr->in, via->port, testdataptr->expected_port);
02435          res = AST_TEST_FAIL;
02436       }
02437 
02438       if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
02439          || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
02440 
02441          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02442             "parsed branch = \"%s\"\n"
02443             "expected = \"%s\"\n"
02444             "failed to parse branch\n",
02445          i, testdataptr->in, via->branch, testdataptr->expected_branch);
02446          res = AST_TEST_FAIL;
02447       }
02448 
02449       if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
02450          || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
02451 
02452          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02453             "parsed maddr = \"%s\"\n"
02454             "expected = \"%s\"\n"
02455             "failed to parse maddr\n",
02456          i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
02457          res = AST_TEST_FAIL;
02458       }
02459 
02460       if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
02461          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02462             "parsed ttl = \"%d\"\n"
02463             "expected = \"%d\"\n"
02464             "failed to parse ttl\n",
02465          i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
02466          res = AST_TEST_FAIL;
02467       }
02468 
02469       free_via(via);
02470       i++;
02471    }
02472    return res;
02473 }

AST_TEST_DEFINE ( sip_uri_cmp_test   ) 

Definition at line 2095 of file reqresp_parser.c.

References ARRAY_LEN, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_uri_cmp(), TEST_EXECUTE, TEST_INIT, URI_CMP_MATCH, and URI_CMP_NOMATCH.

02096 {
02097    static const struct {
02098       const char *uri1;
02099       const char *uri2;
02100       int expected_result;
02101    } uri_cmp_tests [] = {
02102       /* These are identical, so they match */
02103       { "sip:bob@example.com", "sip:bob@example.com", URI_CMP_MATCH },
02104       /* Different usernames. No match */
02105       { "sip:alice@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
02106       /* Different hosts. No match */
02107       { "sip:bob@example.com", "sip:bob@examplez.com", URI_CMP_NOMATCH },
02108       /* Now start using IP addresses. Identical, so they match */
02109       { "sip:bob@1.2.3.4", "sip:bob@1.2.3.4", URI_CMP_MATCH },
02110       /* Two identical IPv4 addresses represented differently. Match */
02111       { "sip:bob@1.2.3.4", "sip:bob@001.002.003.004", URI_CMP_MATCH },
02112       /* Logically equivalent IPv4 Address and hostname. No Match */
02113       { "sip:bob@127.0.0.1", "sip:bob@localhost", URI_CMP_NOMATCH },
02114       /* Logically equivalent IPv6 address and hostname. No Match */
02115       { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
02116       /* Try an IPv6 one as well */
02117       { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
02118       /* Two identical IPv6 addresses represented differently. Match */
02119       { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
02120       /* Different ports. No match */
02121       { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4:5061", URI_CMP_NOMATCH },
02122       /* Same port logically, but only one address specifies it. No match */
02123       { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4", URI_CMP_NOMATCH },
02124       /* And for safety, try with IPv6 */
02125       { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
02126       /* User comparison is case sensitive. No match */
02127       { "sip:bob@example.com", "sip:BOB@example.com", URI_CMP_NOMATCH },
02128       /* Host comparison is case insensitive. Match */
02129       { "sip:bob@example.com", "sip:bob@EXAMPLE.COM", URI_CMP_MATCH },
02130       /* Add headers to the URI. Identical, so they match */
02131       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value2", URI_CMP_MATCH },
02132       /* Headers in URI 1 are not in URI 2. No Match */
02133       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com", URI_CMP_NOMATCH },
02134       /* Header present in both URIs does not have matching values. No match */
02135       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value3", URI_CMP_NOMATCH },
02136       /* Add parameters to the URI. Identical so they match */
02137       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
02138       /* Same parameters in both URIs but appear in different order. Match */
02139       { "sip:bob@example.com;param2=value2;param1=value1", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
02140       /* params in URI 1 are not in URI 2. Match */
02141       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com", URI_CMP_MATCH },
02142       /* param present in both URIs does not have matching values. No match */
02143       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value3", URI_CMP_NOMATCH },
02144       /* URI 1 has a maddr param but URI 2 does not. No match */
02145       { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1", URI_CMP_NOMATCH },
02146       /* URI 1 and URI 2 both have identical maddr params. Match */
02147       { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1;maddr=192.168.0.1", URI_CMP_MATCH },
02148       /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
02149       { "sips:bob@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
02150       /* No URI schemes. No match */
02151       { "bob@example.com", "bob@example.com", URI_CMP_NOMATCH },
02152       /* Crashiness tests. Just an address scheme. No match */
02153       { "sip", "sips", URI_CMP_NOMATCH },
02154       /* Still just an address scheme. Even though they're the same, No match */
02155       { "sip", "sip", URI_CMP_NOMATCH },
02156       /* Empty strings. No match */
02157       { "", "", URI_CMP_NOMATCH },
02158       /* An empty string and a NULL. No match */
02159       { "", NULL, URI_CMP_NOMATCH },
02160    };
02161    int i;
02162    int test_res = AST_TEST_PASS;
02163    switch (cmd) {
02164    case TEST_INIT:
02165       info->name = "sip_uri_cmp_test";
02166       info->category = "/channels/chan_sip/";
02167       info->summary = "Tests comparison of SIP URIs";
02168       info->description = "Several would-be tricky URI comparisons are performed";
02169       return AST_TEST_NOT_RUN;
02170    case TEST_EXECUTE:
02171       break;
02172    }
02173 
02174    for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
02175       int cmp_res1;
02176       int cmp_res2;
02177       if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
02178          /* URI comparison may return -1 or +1 depending on the failure. Standardize
02179           * the return value to be URI_CMP_NOMATCH on any failure
02180           */
02181          cmp_res1 = URI_CMP_NOMATCH;
02182       }
02183       if (cmp_res1 != uri_cmp_tests[i].expected_result) {
02184          ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
02185                "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
02186                uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
02187                cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
02188          test_res = AST_TEST_FAIL;
02189       }
02190 
02191       /* All URI comparisons are commutative, so for the sake of being thorough, we'll
02192        * rerun the comparison with the parameters reversed
02193        */
02194       if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
02195          /* URI comparison may return -1 or +1 depending on the failure. Standardize
02196           * the return value to be URI_CMP_NOMATCH on any failure
02197           */
02198          cmp_res2 = URI_CMP_NOMATCH;
02199       }
02200       if (cmp_res2 != uri_cmp_tests[i].expected_result) {
02201          ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
02202                "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
02203                uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
02204                cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
02205          test_res = AST_TEST_FAIL;
02206       }
02207    }
02208 
02209    return test_res;
02210 }

AST_TEST_DEFINE ( sip_parse_options_test   ) 

Definition at line 1605 of file reqresp_parser.c.

References ARRAY_LEN, AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, name, parse_sip_options(), TEST_EXECUTE, and TEST_INIT.

01606 {
01607    int res = AST_TEST_PASS;
01608    char unsupported[64];
01609    unsigned int option_profile = 0;
01610    struct testdata {
01611       char *name;
01612       char *input_options;
01613       char *expected_unsupported;
01614       unsigned int expected_profile;
01615       AST_LIST_ENTRY(testdata) list;
01616    };
01617 
01618    struct testdata *testdataptr;
01619    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01620 
01621    struct testdata test1 = {
01622       .name = "test_all_unsupported",
01623       .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
01624       .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
01625       .expected_profile = SIP_OPT_UNKNOWN,
01626    };
01627    struct testdata test2 = {
01628       .name = "test_all_unsupported_one_supported",
01629       .input_options = "  unsupported1, replaces,   unsupported3  , , , ,unsupported4",
01630       .expected_unsupported = "unsupported1,unsupported3,unsupported4",
01631       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
01632    };
01633    struct testdata test3 = {
01634       .name = "test_two_supported_two_unsupported",
01635       .input_options = ",,  timer  ,replaces     ,unsupported3,unsupported4",
01636       .expected_unsupported = "unsupported3,unsupported4",
01637       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
01638    };
01639 
01640    struct testdata test4 = {
01641       .name = "test_all_supported",
01642       .input_options = "timer,replaces",
01643       .expected_unsupported = "",
01644       .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
01645    };
01646 
01647    struct testdata test5 = {
01648       .name = "test_all_supported_redundant",
01649       .input_options = "timer,replaces,timer,replace,timer,replaces",
01650       .expected_unsupported = "",
01651       .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
01652    };
01653    struct testdata test6 = {
01654       .name = "test_buffer_overflow",
01655       .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
01656       "____________________________________,__________________________________________"
01657       "________________________________________________",
01658       .expected_unsupported = "unsupported1,unsupported4",
01659       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
01660    };
01661    struct testdata test7 = {
01662       .name = "test_null_input",
01663       .input_options = NULL,
01664       .expected_unsupported = "",
01665       .expected_profile = 0,
01666    };
01667    struct testdata test8 = {
01668       .name = "test_whitespace_input",
01669       .input_options = "         ",
01670       .expected_unsupported = "",
01671       .expected_profile = 0,
01672    };
01673    struct testdata test9 = {
01674       .name = "test_whitespace_plus_option_input",
01675       .input_options = " , , ,timer , ,  , ,        ,    ",
01676       .expected_unsupported = "",
01677       .expected_profile = SIP_OPT_TIMER,
01678    };
01679 
01680    switch (cmd) {
01681    case TEST_INIT:
01682       info->name = "sip_parse_options_test";
01683       info->category = "/channels/chan_sip/";
01684       info->summary = "Tests parsing of sip options";
01685       info->description =
01686                      "Tests parsing of SIP options from supported and required "
01687                      "header fields.  Verifies when unsupported options are encountered "
01688                      "that they are appended to the unsupported out buffer and that the "
01689                      "correct bit field representnig the option profile is returned.";
01690       return AST_TEST_NOT_RUN;
01691    case TEST_EXECUTE:
01692       break;
01693    }
01694 
01695    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
01696    AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
01697    AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
01698    AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
01699    AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
01700    AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
01701    AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
01702    AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
01703    AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
01704 
01705    /* Test with unsupported char buffer */
01706    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01707       option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
01708       if (option_profile != testdataptr->expected_profile ||
01709          strcmp(unsupported, testdataptr->expected_unsupported)) {
01710          ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
01711             "%s expected bit profile: %x actual bit profile: %x\n",
01712             testdataptr->name,
01713             testdataptr->expected_unsupported,
01714             unsupported,
01715             testdataptr->expected_profile,
01716             option_profile);
01717          res = AST_TEST_FAIL;
01718       } else {
01719          ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
01720             testdataptr->name,
01721             unsupported,
01722             option_profile);
01723       }
01724 
01725       option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
01726       if (option_profile != testdataptr->expected_profile) {
01727          ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
01728             testdataptr->name,
01729             testdataptr->expected_profile,
01730             option_profile);
01731          res = AST_TEST_FAIL;
01732       } else {
01733          ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
01734             testdataptr->name,
01735             option_profile);
01736       }
01737    }
01738 
01739    return res;
01740 }

AST_TEST_DEFINE ( parse_contact_header_test   ) 

Definition at line 1372 of file reqresp_parser.c.

References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, parse_contact_header(), TEST_EXECUTE, and TEST_INIT.

01373 {
01374    int res = AST_TEST_PASS;
01375    char contactheader[1024];
01376    int star;
01377    struct contactliststruct contactlist;
01378    struct contactliststruct *contactlistptr=&contactlist;
01379 
01380    struct testdata {
01381       char *desc;
01382       char *contactheader;
01383       int star;
01384       struct contactliststruct *contactlist;
01385 
01386       AST_LIST_ENTRY(testdata) list;
01387    };
01388 
01389    struct testdata *testdataptr;
01390    struct contact *tdcontactptr;
01391    struct contact *contactptr;
01392 
01393    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01394    struct contactliststruct contactlist1, contactlist2;
01395 
01396    struct testdata td1 = {
01397       .desc = "single contact",
01398       .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
01399       .contactlist = &contactlist1,
01400       .star = 0
01401    };
01402    struct contact contact11 = {
01403       .name = "name :@;?&,",
01404       .user = "user",
01405       .pass = "secret",
01406       .hostport = "host:5082",
01407       .params.transport = "tcp",
01408       .params.ttl = "",
01409       .params.lr = 0,
01410       .headers = "",
01411       .expires = "3600",
01412       .q = ""
01413    };
01414 
01415    struct testdata td2 = {
01416       .desc = "multiple contacts",
01417       .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
01418       .contactlist = &contactlist2,
01419       .star = 0,
01420    };
01421    struct contact contact21 = {
01422       .name = "",
01423       .user = ",user1,",
01424       .pass = ",secret1,",
01425       .hostport = "host1",
01426       .params.transport = "",
01427       .params.ttl = "7",
01428       .params.lr = 0,
01429       .headers = "",
01430       .expires = "3600",
01431       .q = "1"
01432    };
01433    struct contact contact22 = {
01434       .name = "",
01435       .user = "",
01436       .pass = "",
01437       .hostport = "host2",
01438       .params.transport = "",
01439       .params.ttl = "",
01440       .params.lr = 0,
01441       .headers = "",
01442       .expires = "",
01443       .q = ""
01444    };
01445 
01446    struct testdata td3 = {
01447       .desc = "star - all contacts",
01448       .contactheader = "*",
01449       .star = 1,
01450       .contactlist = NULL
01451    };
01452 
01453    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
01454    AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
01455    AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
01456 
01457    AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
01458 
01459    AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
01460    AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
01461 
01462 
01463    switch (cmd) {
01464    case TEST_INIT:
01465       info->name = "parse_contact_header_test";
01466       info->category = "/channels/chan_sip/";
01467       info->summary = "tests parsing of sip contact header";
01468       info->description =
01469          "Tests parsing of a contact header including those with multiple contacts "
01470          "Verifies output matches expected behavior.";
01471       return AST_TEST_NOT_RUN;
01472    case TEST_EXECUTE:
01473       break;
01474    }
01475 
01476    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01477       ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
01478       star = parse_contact_header(contactheader,contactlistptr);
01479       if (testdataptr->star) {
01480          /* expecting star rather than list of contacts */
01481          if (!star) {
01482             ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01483             res = AST_TEST_FAIL;
01484             break;
01485          }
01486       } else {
01487          contactptr = AST_LIST_FIRST(contactlistptr);
01488          AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
01489             if (!contactptr ||
01490                strcmp(tdcontactptr->name, contactptr->name) ||
01491                strcmp(tdcontactptr->user, contactptr->user) ||
01492                strcmp(tdcontactptr->pass, contactptr->pass) ||
01493                strcmp(tdcontactptr->hostport, contactptr->hostport) ||
01494                strcmp(tdcontactptr->headers, contactptr->headers) ||
01495                strcmp(tdcontactptr->expires, contactptr->expires) ||
01496                strcmp(tdcontactptr->q, contactptr->q) ||
01497                strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
01498                strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
01499                (tdcontactptr->params.lr != contactptr->params.lr)
01500                ) {
01501                ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01502                res = AST_TEST_FAIL;
01503                break;
01504             }
01505 
01506             contactptr = AST_LIST_NEXT(contactptr,list);
01507          }
01508       }
01509    }
01510 
01511    return res;
01512 }

AST_TEST_DEFINE ( parse_name_andor_addr_test   ) 

Definition at line 1147 of file reqresp_parser.c.

References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, name, parse_name_andor_addr(), pass, TEST_EXECUTE, and TEST_INIT.

01148 {
01149    int res = AST_TEST_PASS;
01150    char uri[1024];
01151    char *name, *user, *pass, *hostport, *headers, *residue;
01152    struct uriparams params;
01153 
01154    struct testdata {
01155       char *desc;
01156       char *uri;
01157       char *name;
01158       char *user;
01159       char *pass;
01160       char *hostport;
01161       char *headers;
01162       char *residue;
01163       struct uriparams params;
01164       AST_LIST_ENTRY(testdata) list;
01165    };
01166 
01167    struct testdata *testdataptr;
01168 
01169    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01170 
01171    struct testdata td1 = {
01172       .desc = "quotes and brackets",
01173       .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
01174       .name =  "name :@ ",
01175       .user = "user",
01176       .pass = "secret",
01177       .hostport = "host:5060",
01178       .headers = "",
01179       .residue = "tag=tag",
01180       .params.transport = "tcp",
01181       .params.lr = 0,
01182       .params.user = ""
01183    };
01184 
01185    struct testdata td2 = {
01186       .desc = "no quotes",
01187       .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
01188       .name = "givenname familyname",
01189       .user = "user",
01190       .pass = "secret",
01191       .hostport = "host:5060",
01192       .headers = "",
01193       .residue = "expires=3600",
01194       .params.transport = "tcp",
01195       .params.lr = 0,
01196       .params.user = ""
01197    };
01198 
01199    struct testdata td3 = {
01200       .desc = "no brackets",
01201       .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
01202       .name = "",
01203       .user = "user",
01204       .pass = "secret",
01205       .hostport = "host:5060",
01206       .headers = "",
01207       .residue = "q=1",
01208       .params.transport = "tcp",
01209       .params.lr = 0,
01210       .params.user = ""
01211    };
01212 
01213    struct testdata td4 = {
01214       .desc = "just host",
01215       .uri = "sips:host",
01216       .name = "",
01217       .user = "",
01218       .pass = "",
01219       .hostport = "host",
01220       .headers = "",
01221       .residue = "",
01222       .params.transport = "",
01223       .params.lr = 0,
01224       .params.user = ""
01225    };
01226 
01227 
01228    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
01229    AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
01230    AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
01231    AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
01232 
01233 
01234    switch (cmd) {
01235    case TEST_INIT:
01236       info->name = "parse_name_andor_addr_test";
01237       info->category = "/channels/chan_sip/";
01238       info->summary = "tests parsing of name_andor_addr abnf structure";
01239       info->description =
01240          "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
01241          "Verifies output matches expected behavior.";
01242       return AST_TEST_NOT_RUN;
01243    case TEST_EXECUTE:
01244       break;
01245    }
01246 
01247    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01248       name = user = pass = hostport = headers = residue = NULL;
01249       params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
01250       params.lr = 0;
01251       ast_copy_string(uri,testdataptr->uri,sizeof(uri));
01252       if (parse_name_andor_addr(uri, "sip:,sips:",
01253                  &name,
01254                  &user,
01255                  &pass,
01256                  &hostport,
01257                  &params,
01258                  &headers,
01259                  &residue) ||
01260          (name && strcmp(testdataptr->name, name)) ||
01261          (user && strcmp(testdataptr->user, user)) ||
01262          (pass && strcmp(testdataptr->pass, pass)) ||
01263          (hostport && strcmp(testdataptr->hostport, hostport)) ||
01264          (headers && strcmp(testdataptr->headers, headers)) ||
01265          (residue && strcmp(testdataptr->residue, residue)) ||
01266          (strcmp(testdataptr->params.transport,params.transport)) ||
01267          (strcmp(testdataptr->params.user,params.user))
01268          ) {
01269          ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01270          res = AST_TEST_FAIL;
01271       }
01272    }
01273 
01274    return res;
01275 }

AST_TEST_DEFINE ( get_in_brackets_test   ) 

Definition at line 1025 of file reqresp_parser.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_in_brackets(), TEST_EXECUTE, and TEST_INIT.

01026 {
01027    int res = AST_TEST_PASS;
01028    char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
01029    char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01030    char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01031    char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01032    char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01033    char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
01034    char no_name_no_brackets[] = "sip:name@host";
01035    char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01036    char *uri = NULL;
01037 
01038    switch (cmd) {
01039    case TEST_INIT:
01040       info->name = "sip_get_in_brackets_test";
01041       info->category = "/channels/chan_sip/";
01042       info->summary = "Tests getting a sip uri in <> brackets within a sip header.";
01043       info->description =
01044             "Runs through various test situations in which a sip uri "
01045             "in angle brackets needs to be retrieved";
01046       return AST_TEST_NOT_RUN;
01047    case TEST_EXECUTE:
01048       break;
01049    }
01050 
01051    /* Test 1, simple get in brackets */
01052    if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
01053       ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
01054       res = AST_TEST_FAIL;
01055    }
01056 
01057    /* Test 2, starts with quoted string */
01058    if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
01059       ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
01060       res = AST_TEST_FAIL;
01061    }
01062 
01063    /* Test 3, missing end quote */
01064    if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
01065       ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
01066       res = AST_TEST_FAIL;
01067    }
01068 
01069    /* Test 4, starts with a name not in quotes */
01070    if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
01071       ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
01072       res = AST_TEST_FAIL;
01073    }
01074 
01075    /* Test 5, no end bracket, should just return everything after the first '<'  */
01076    if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
01077       ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
01078       res = AST_TEST_FAIL;
01079    }
01080 
01081    /* Test 6, NULL input  */
01082    if ((uri = get_in_brackets(NULL))) {
01083       ast_test_status_update(test, "Test 6, NULL input failed.\n");
01084       res = AST_TEST_FAIL;
01085    }
01086 
01087    /* Test 7, no name, and no brackets. */
01088    if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
01089       ast_test_status_update(test, "Test 7 failed. %s\n", uri);
01090       res = AST_TEST_FAIL;
01091    }
01092 
01093    /* Test 8, no start bracket, but with ending bracket. */
01094    if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
01095       ast_test_status_update(test, "Test 8 failed. %s\n", uri);
01096       res = AST_TEST_FAIL;
01097    }
01098 
01099    return res;
01100 }

AST_TEST_DEFINE ( get_name_and_number_test   ) 

Definition at line 842 of file reqresp_parser.c.

References ast_free, ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_name_and_number(), name, TEST_EXECUTE, and TEST_INIT.

00843 {
00844    int res = AST_TEST_PASS;
00845    char *name = NULL;
00846    char *number = NULL;
00847    const char *in1 = "NAME <sip:NUMBER@place>";
00848    const char *in2 = "\"NA><ME\" <sip:NUMBER@place>";
00849    const char *in3 = "NAME";
00850    const char *in4 = "<sip:NUMBER@place>";
00851    const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
00852 
00853    switch (cmd) {
00854    case TEST_INIT:
00855       info->name = "sip_get_name_and_number_test";
00856       info->category = "/channels/chan_sip/";
00857       info->summary = "Tests getting name and number from sip header";
00858       info->description =
00859             "Runs through various test situations in which a name and "
00860             "and number can be retrieved from a sip header.";
00861       return AST_TEST_NOT_RUN;
00862    case TEST_EXECUTE:
00863       break;
00864    }
00865 
00866    /* Test 1. get name and number */
00867    number = name = NULL;
00868    if ((get_name_and_number(in1, &name, &number)) ||
00869       strcmp(name, "NAME") ||
00870       strcmp(number, "NUMBER")) {
00871 
00872       ast_test_status_update(test, "Test 1, simple get name and number failed.\n");
00873       res = AST_TEST_FAIL;
00874    }
00875    ast_free(name);
00876    ast_free(number);
00877 
00878    /* Test 2. get quoted name and number */
00879    number = name = NULL;
00880    if ((get_name_and_number(in2, &name, &number)) ||
00881       strcmp(name, "NA><ME") ||
00882       strcmp(number, "NUMBER")) {
00883 
00884       ast_test_status_update(test, "Test 2, get quoted name and number failed.\n");
00885       res = AST_TEST_FAIL;
00886    }
00887    ast_free(name);
00888    ast_free(number);
00889 
00890    /* Test 3. name only */
00891    number = name = NULL;
00892    if (!(get_name_and_number(in3, &name, &number))) {
00893 
00894       ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n");
00895       res = AST_TEST_FAIL;
00896    }
00897    ast_free(name);
00898    ast_free(number);
00899 
00900    /* Test 4. number only */
00901    number = name = NULL;
00902    if ((get_name_and_number(in4, &name, &number)) ||
00903       !ast_strlen_zero(name) ||
00904       strcmp(number, "NUMBER")) {
00905 
00906       ast_test_status_update(test, "Test 4, get number with no name present failed.\n");
00907       res = AST_TEST_FAIL;
00908    }
00909    ast_free(name);
00910    ast_free(number);
00911 
00912    /* Test 5. malformed string, since number can not be parsed, this should return an error.  */
00913    number = name = NULL;
00914    if (!(get_name_and_number(in5, &name, &number)) ||
00915       !ast_strlen_zero(name) ||
00916       !ast_strlen_zero(number)) {
00917 
00918       ast_test_status_update(test, "Test 5, processing malformed string failed.\n");
00919       res = AST_TEST_FAIL;
00920    }
00921    ast_free(name);
00922    ast_free(number);
00923 
00924    /* Test 6. NULL output parameters */
00925    number = name = NULL;
00926    if (!(get_name_and_number(in5, NULL, NULL))) {
00927 
00928       ast_test_status_update(test, "Test 6, NULL output parameters failed.\n");
00929       res = AST_TEST_FAIL;
00930    }
00931 
00932    /* Test 7. NULL input parameter */
00933    number = name = NULL;
00934    if (!(get_name_and_number(NULL, &name, &number)) ||
00935       !ast_strlen_zero(name) ||
00936       !ast_strlen_zero(number)) {
00937 
00938       ast_test_status_update(test, "Test 7, NULL input parameter failed.\n");
00939       res = AST_TEST_FAIL;
00940    }
00941    ast_free(name);
00942    ast_free(number);
00943 
00944    return res;
00945 }

AST_TEST_DEFINE ( get_calleridname_test   ) 

Definition at line 719 of file reqresp_parser.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_calleridname(), TEST_EXECUTE, and TEST_INIT.

00720 {
00721    int res = AST_TEST_PASS;
00722    const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
00723    const char *in2 = " token text with no quotes <stuff>";
00724    const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
00725    const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
00726    const char *noendquote = " \"quoted-text no end <stuff>";
00727    const char *addrspec = " sip:blah@blah";
00728    const char *no_quotes_no_brackets = "blah@blah";
00729    const char *after_dname;
00730    char dname[40];
00731 
00732    switch (cmd) {
00733    case TEST_INIT:
00734       info->name = "sip_get_calleridname_test";
00735       info->category = "/channels/chan_sip/";
00736       info->summary = "decodes callerid name from sip header";
00737       info->description = "Decodes display-name field of sip header.  Checks for valid output and expected failure cases.";
00738       return AST_TEST_NOT_RUN;
00739    case TEST_EXECUTE:
00740       break;
00741    }
00742 
00743    /* quoted-text with backslash escaped quote */
00744    after_dname = get_calleridname(in1, dname, sizeof(dname));
00745    ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname);
00746    if (strcmp(dname, " quoted-text internal \" quote ")) {
00747       ast_test_status_update(test, "display-name1 test failed\n");
00748       res = AST_TEST_FAIL;
00749    }
00750 
00751    /* token text */
00752    after_dname = get_calleridname(in2, dname, sizeof(dname));
00753    ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname);
00754    if (strcmp(dname, "token text with no quotes")) {
00755       ast_test_status_update(test, "display-name2 test failed\n");
00756       res = AST_TEST_FAIL;
00757    }
00758 
00759    /* quoted-text buffer overflow */
00760    after_dname = get_calleridname(overflow1, dname, sizeof(dname));
00761    ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
00762    if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
00763       ast_test_status_update(test, "overflow display-name1 test failed\n");
00764       res = AST_TEST_FAIL;
00765    }
00766 
00767    /* non-quoted-text buffer overflow */
00768    after_dname = get_calleridname(overflow2, dname, sizeof(dname));
00769    ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
00770    if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
00771       ast_test_status_update(test, "overflow display-name2 test failed\n");
00772       res = AST_TEST_FAIL;
00773    }
00774 
00775    /* quoted-text buffer with no terminating end quote */
00776    after_dname = get_calleridname(noendquote, dname, sizeof(dname));
00777    ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
00778    if (*dname != '\0' && after_dname != noendquote) {
00779       ast_test_status_update(test, "no end quote for quoted-text display-name failed\n");
00780       res = AST_TEST_FAIL;
00781    }
00782 
00783    /* addr-spec rather than display-name. */
00784    after_dname = get_calleridname(addrspec, dname, sizeof(dname));
00785    ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
00786    if (*dname != '\0' && after_dname != addrspec) {
00787       ast_test_status_update(test, "detection of addr-spec failed\n");
00788       res = AST_TEST_FAIL;
00789    }
00790 
00791    /* no quotes, no brackets */
00792    after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname));
00793    ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname);
00794    if (*dname != '\0' && after_dname != no_quotes_no_brackets) {
00795       ast_test_status_update(test, "detection of addr-spec failed\n");
00796       res = AST_TEST_FAIL;
00797    }
00798 
00799    return res;
00800 }

AST_TEST_DEFINE ( sip_parse_uri_test   ) 

Definition at line 444 of file reqresp_parser.c.

References ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, name, parse_uri(), pass, TEST_EXECUTE, and TEST_INIT.

00445 {
00446    int res = AST_TEST_PASS;
00447    char *name, *pass, *hostport, *transport;
00448    char uri1[] = "sip:name@host";
00449    char uri2[] = "sip:name@host;transport=tcp";
00450    char uri3[] = "sip:name:secret@host;transport=tcp";
00451    char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00452    /* test 5 is for NULL input */
00453    char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00454    char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00455    char uri8[] = "sip:host";
00456    char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00457    char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00458    char uri11[] = "host";
00459 
00460    switch (cmd) {
00461    case TEST_INIT:
00462       info->name = "sip_uri_parse_test";
00463       info->category = "/channels/chan_sip/";
00464       info->summary = "tests sip uri parsing";
00465       info->description =
00466                      "Tests parsing of various URIs "
00467                      "Verifies output matches expected behavior.";
00468       return AST_TEST_NOT_RUN;
00469    case TEST_EXECUTE:
00470       break;
00471    }
00472 
00473    /* Test 1, simple URI */
00474    name = pass = hostport = transport = NULL;
00475    if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00476          strcmp(name, "name")        ||
00477          !ast_strlen_zero(pass)      ||
00478          strcmp(hostport, "host")      ||
00479          !ast_strlen_zero(transport)) {
00480       ast_test_status_update(test, "Test 1: simple uri failed. \n");
00481       res = AST_TEST_FAIL;
00482    }
00483 
00484    /* Test 2, add tcp transport */
00485    name = pass = hostport = transport = NULL;
00486    if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00487          strcmp(name, "name")        ||
00488          !ast_strlen_zero(pass)      ||
00489          strcmp(hostport, "host")    ||
00490          strcmp(transport, "tcp")) {
00491       ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n");
00492       res = AST_TEST_FAIL;
00493    }
00494 
00495    /* Test 3, add secret */
00496    name = pass = hostport = transport = NULL;
00497    if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00498          strcmp(name, "name")        ||
00499          strcmp(pass, "secret")      ||
00500          strcmp(hostport, "host")    ||
00501          strcmp(transport, "tcp")) {
00502       ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n");
00503       res = AST_TEST_FAIL;
00504    }
00505 
00506    /* Test 4, add port and unparsed header field*/
00507    name = pass = hostport = transport = NULL;
00508    if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00509          strcmp(name, "name")        ||
00510          strcmp(pass, "secret")      ||
00511          strcmp(hostport, "host:port") ||
00512          strcmp(transport, "tcp")) {
00513       ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n");
00514       res = AST_TEST_FAIL;
00515    }
00516 
00517    /* Test 5, verify parse_uri does not crash when given a NULL uri */
00518    name = pass = hostport = transport = NULL;
00519    if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) {
00520       ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n");
00521       res = AST_TEST_FAIL;
00522    }
00523 
00524    /* Test 6, verify parse_uri does not crash when given a NULL output parameters */
00525    name = pass = hostport = transport = NULL;
00526    if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) {
00527       ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n");
00528       res = AST_TEST_FAIL;
00529    }
00530 
00531    /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */
00532    name = pass = hostport = transport = NULL;
00533    if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) ||
00534          strcmp(name, "name:secret")        ||
00535          strcmp(hostport, "host:port")) {
00536 
00537       ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n");
00538       res = AST_TEST_FAIL;
00539    }
00540 
00541    /* Test 8, verify parse_uri can handle a hostport only uri */
00542    name = pass = hostport = transport = NULL;
00543    if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00544          strcmp(hostport, "host") ||
00545          !ast_strlen_zero(name)) {
00546       ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n");
00547       res = AST_TEST_FAIL;
00548    }
00549 
00550    /* Test 9, add port and unparsed header field with hostport only uri*/
00551    name = pass = hostport = transport = NULL;
00552    if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00553          !ast_strlen_zero(name)        ||
00554          !ast_strlen_zero(pass)      ||
00555          strcmp(hostport, "host:port")    ||
00556          strcmp(transport, "tcp")) {
00557       ast_test_status_update(test, "Test 9: hostport only uri failed \n");
00558       res = AST_TEST_FAIL;
00559    }
00560 
00561    /* Test 10, handle invalid/missing "sip:,sips:" scheme
00562     * we expect parse_uri to return an error, but still parse
00563     * the results correctly here */
00564    name = pass = hostport = transport = NULL;
00565    if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00566          !ast_strlen_zero(name)        ||
00567          !ast_strlen_zero(pass)      ||
00568          strcmp(hostport, "host:port")    ||
00569          strcmp(transport, "tcp")) {
00570       ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n");
00571       res = AST_TEST_FAIL;
00572    }
00573 
00574    /* Test 11, simple hostport only URI with missing scheme
00575     * we expect parse_uri to return an error, but still parse
00576     * the results correctly here */
00577    name = pass = hostport = transport = NULL;
00578    if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00579          !ast_strlen_zero(name)      ||
00580          !ast_strlen_zero(pass)      ||
00581          strcmp(hostport, "host")      ||
00582          !ast_strlen_zero(transport)) {
00583       ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n");
00584       res = AST_TEST_FAIL;
00585    }
00586 
00587    return res;
00588 }

AST_TEST_DEFINE ( sip_parse_uri_full_test   ) 

Definition at line 220 of file reqresp_parser.c.

References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, parse_uri_full(), pass, TEST_EXECUTE, and TEST_INIT.

00221 {
00222    int res = AST_TEST_PASS;
00223    char uri[1024];
00224    char *user, *pass, *hostport, *headers, *residue;
00225    struct uriparams params;
00226 
00227    struct testdata {
00228       char *desc;
00229       char *uri;
00230       char *user;
00231       char *pass;
00232       char *hostport;
00233       char *headers;
00234       char *residue;
00235       struct uriparams params;
00236       AST_LIST_ENTRY(testdata) list;
00237    };
00238 
00239 
00240    struct testdata *testdataptr;
00241 
00242    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
00243 
00244    struct testdata td1 = {
00245       .desc = "no headers",
00246       .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue",
00247       .user = "user",
00248       .pass = "secret",
00249       .hostport = "host:5060",
00250       .headers = "",
00251       .residue = "param2=residue",
00252       .params.transport = "tcp",
00253       .params.lr = 0,
00254       .params.user = ""
00255    };
00256 
00257    struct testdata td2 = {
00258       .desc = "with headers",
00259       .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
00260       .user = "user",
00261       .pass = "secret",
00262       .hostport = "host:5060",
00263       .headers = "header=blah&header2=blah2",
00264       .residue = "param3=residue",
00265       .params.transport = "tcp",
00266       .params.lr = 0,
00267       .params.user = ""
00268    };
00269 
00270    struct testdata td3 = {
00271       .desc = "difficult user",
00272       .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp",
00273       .user = "-_.!~*'()&=+$,;?/",
00274       .pass = "secret",
00275       .hostport = "host:5060",
00276       .headers = "",
00277       .residue = "",
00278       .params.transport = "tcp",
00279       .params.lr = 0,
00280       .params.user = ""
00281    };
00282 
00283    struct testdata td4 = {
00284       .desc = "difficult pass",
00285       .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp",
00286       .user = "user",
00287       .pass = "-_.!~*'()&=+$,",
00288       .hostport = "host:5060",
00289       .headers = "",
00290       .residue = "",
00291       .params.transport = "tcp",
00292       .params.lr = 0,
00293       .params.user = ""
00294    };
00295 
00296    struct testdata td5 = {
00297       .desc = "difficult host",
00298       .uri = "sip:user:secret@1-1.a-1.:5060;transport=tcp",
00299       .user = "user",
00300       .pass = "secret",
00301       .hostport = "1-1.a-1.:5060",
00302       .headers = "",
00303       .residue = "",
00304       .params.transport = "tcp",
00305       .params.lr = 0,
00306       .params.user = ""
00307    };
00308 
00309    struct testdata td6 = {
00310       .desc = "difficult params near transport",
00311       .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
00312       .user = "user",
00313       .pass = "secret",
00314       .hostport = "host:5060",
00315       .headers = "",
00316       .residue = "",
00317       .params.transport = "tcp",
00318       .params.lr = 0,
00319       .params.user = ""
00320    };
00321 
00322    struct testdata td7 = {
00323       .desc = "difficult params near headers",
00324       .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
00325       .user = "user",
00326       .pass = "secret",
00327       .hostport = "host:5060",
00328       .headers = "header=blah&header2=blah2",
00329       .residue = "-_.!~*'()[]/:&+$=residue",
00330       .params.transport = "",
00331       .params.lr = 0,
00332       .params.user = ""
00333    };
00334 
00335    struct testdata td8 = {
00336       .desc = "lr parameter",
00337       .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah",
00338       .user = "user",
00339       .pass = "secret",
00340       .hostport = "host:5060",
00341       .headers = "header=blah",
00342       .residue = "",
00343       .params.transport = "",
00344       .params.lr = 1,
00345       .params.user = ""
00346    };
00347 
00348    struct testdata td9 = {
00349       .desc = "alternative lr parameter",
00350       .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah",
00351       .user = "user",
00352       .pass = "secret",
00353       .hostport = "host:5060",
00354       .headers = "header=blah",
00355       .residue = "",
00356       .params.transport = "",
00357       .params.lr = 1,
00358       .params.user = ""
00359    };
00360 
00361    struct testdata td10 = {
00362       .desc = "no lr parameter",
00363       .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
00364       .user = "user",
00365       .pass = "secret",
00366       .hostport = "host:5060",
00367       .headers = "header=blah",
00368       .residue = "",
00369       .params.transport = "",
00370       .params.lr = 0,
00371       .params.user = ""
00372    };
00373 
00374 
00375    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
00376    AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
00377    AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
00378    AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
00379    AST_LIST_INSERT_TAIL(&testdatalist, &td5, list);
00380    AST_LIST_INSERT_TAIL(&testdatalist, &td6, list);
00381    AST_LIST_INSERT_TAIL(&testdatalist, &td7, list);
00382    AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
00383    AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
00384    AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
00385 
00386 
00387    switch (cmd) {
00388    case TEST_INIT:
00389       info->name = "sip_uri_full_parse_test";
00390       info->category = "/channels/chan_sip/";
00391       info->summary = "tests sip full uri parsing";
00392       info->description =
00393          "Tests full parsing of various URIs "
00394          "Verifies output matches expected behavior.";
00395       return AST_TEST_NOT_RUN;
00396    case TEST_EXECUTE:
00397       break;
00398    }
00399 
00400    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
00401       user = pass = hostport = headers = residue = NULL;
00402       params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
00403       params.lr = 0;
00404 
00405       ast_copy_string(uri,testdataptr->uri,sizeof(uri));
00406       if (parse_uri_full(uri, "sip:,sips:", &user,
00407                &pass, &hostport,
00408                &params,
00409                &headers,
00410                &residue) ||
00411          (user && strcmp(testdataptr->user, user)) ||
00412          (pass && strcmp(testdataptr->pass, pass)) ||
00413          (hostport && strcmp(testdataptr->hostport, hostport)) ||
00414          (headers && strcmp(testdataptr->headers, headers)) ||
00415          (residue && strcmp(testdataptr->residue, residue)) ||
00416          (strcmp(testdataptr->params.transport,params.transport)) ||
00417          (testdataptr->params.lr != params.lr) ||
00418          (strcmp(testdataptr->params.user,params.user))
00419       ) {
00420             ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc);
00421             res = AST_TEST_FAIL;
00422       }
00423    }
00424 
00425 
00426    return res;
00427 }

void free_via ( struct sip_via *  v  ) 

Definition at line 2212 of file reqresp_parser.c.

References ast_free.

Referenced by AST_TEST_DEFINE(), find_call(), parse_via(), process_via(), and sip_alloc().

02213 {
02214    if (!v) {
02215       return;
02216    }
02217 
02218    ast_free(v->via);
02219    ast_free(v);
02220 }

const char* get_calleridname ( const char *  input,
char *  output,
size_t  outputsize 
)

Get caller id name from SIP headers, copy into output buffer.

Return values:
input string pointer placed after display-name field if possible

Definition at line 594 of file reqresp_parser.c.

References ast_log(), ast_skip_blanks(), and LOG_WARNING.

Referenced by AST_TEST_DEFINE(), check_user_full(), get_name_and_number(), parse_name_andor_addr(), and receive_message().

00595 {
00596    /* From RFC3261:
00597     *
00598     * From           =  ( "From" / "f" ) HCOLON from-spec
00599     * from-spec      =  ( name-addr / addr-spec ) *( SEMI from-param )
00600     * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
00601     * display-name   =  *(token LWS)/ quoted-string
00602     * token          =  1*(alphanum / "-" / "." / "!" / "%" / "*"
00603     *                     / "_" / "+" / "`" / "'" / "~" )
00604     * quoted-string  =  SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
00605     * qdtext         =  LWS / %x21 / %x23-5B / %x5D-7E
00606     *                     / UTF8-NONASCII
00607     * quoted-pair    =  "\" (%x00-09 / %x0B-0C / %x0E-7F)
00608     *
00609     * HCOLON         = *WSP ":" SWS
00610     * SWS            = [LWS]
00611     * LWS            = *[*WSP CRLF] 1*WSP
00612     * WSP            = (SP / HTAB)
00613     *
00614     * Deviations from it:
00615     * - following CRLF's in LWS is not done (here at least)
00616     * - ascii NUL is never legal as it terminates the C-string
00617     * - utf8-nonascii is not checked for validity
00618     */
00619    char *orig_output = output;
00620    const char *orig_input = input;
00621 
00622    if (!output || !outputsize) {
00623       /* Bad output parameters.  Should never happen. */
00624       return input;
00625    }
00626 
00627    /* clear any empty characters in the beginning */
00628    input = ast_skip_blanks(input);
00629 
00630    /* make sure the output buffer is initilized */
00631    *orig_output = '\0';
00632 
00633    /* make room for '\0' at the end of the output buffer */
00634    --outputsize;
00635 
00636    /* no data at all or no display name? */
00637    if (!input || *input == '<') {
00638       return input;
00639    }
00640 
00641    /* quoted-string rules */
00642    if (input[0] == '"') {
00643       input++; /* skip the first " */
00644 
00645       for (; *input; ++input) {
00646          if (*input == '"') {  /* end of quoted-string */
00647             break;
00648          } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
00649             ++input;
00650             if (!*input) {
00651                break;
00652             }
00653             if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
00654                continue;  /* not a valid quoted-pair, so skip it */
00655             }
00656          } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
00657             || *input == 0x7f) {
00658             continue; /* skip this invalid character. */
00659          }
00660 
00661          if (0 < outputsize) {
00662             /* We still have room for the output display-name. */
00663             *output++ = *input;
00664             --outputsize;
00665          }
00666       }
00667 
00668       /* if this is successful, input should be at the ending quote */
00669       if (*input != '"') {
00670          ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
00671          *orig_output = '\0';
00672          return orig_input;
00673       }
00674 
00675       /* make sure input is past the last quote */
00676       ++input;
00677 
00678       /* terminate output */
00679       *output = '\0';
00680    } else {  /* either an addr-spec or tokenLWS-combo */
00681       for (; *input; ++input) {
00682          /* token or WSP (without LWS) */
00683          if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
00684             || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
00685             || *input == '!' || *input == '%' || *input == '*' || *input == '_'
00686             || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
00687             || *input == 0x9 || *input == ' ') {
00688             if (0 < outputsize) {
00689                /* We still have room for the output display-name. */
00690                *output++ = *input;
00691                --outputsize;
00692             }
00693          } else if (*input == '<') {   /* end of tokenLWS-combo */
00694             /* we could assert that the previous char is LWS, but we don't care */
00695             break;
00696          } else if (*input == ':') {
00697             /* This invalid character which indicates this is addr-spec rather than display-name. */
00698             *orig_output = '\0';
00699             return orig_input;
00700          } else {         /* else, invalid character we can skip. */
00701             continue;    /* skip this character */
00702          }
00703       }
00704 
00705       if (*input != '<') {   /* if we never found the start of addr-spec then this is invalid */
00706          *orig_output = '\0';
00707          return orig_input;
00708       }
00709 
00710       /* terminate output while trimming any trailing whitespace */
00711       do {
00712          *output-- = '\0';
00713       } while (orig_output <= output && (*output == 0x9 || *output == ' '));
00714    }
00715 
00716    return input;
00717 }

int get_comma ( char *  in,
char **  out 
)

Definition at line 1277 of file reqresp_parser.c.

References ast_log(), find_closing_quote(), LOG_WARNING, and parse().

Referenced by parse_contact_header().

01278 {
01279    char *c;
01280    char *parse = in;
01281    if (out) {
01282       *out = in;
01283    }
01284 
01285    /* Skip any quoted text */
01286    while (*parse) {
01287       if ((c = strchr(parse, '"'))) {
01288          in = (char *)find_closing_quote((const char *)c + 1, NULL);
01289          if (!*in) {
01290             ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
01291             return -1;
01292          } else {
01293             break;
01294          }
01295       } else {
01296          break;
01297       }
01298       parse++;
01299    }
01300    parse = in;
01301 
01302    /* Skip any userinfo components of a uri as they may contain commas */
01303    if ((c = strchr(parse,'@'))) {
01304       parse = c+1;
01305    }
01306    if ((out) && (c = strchr(parse,','))) {
01307       *c++ = '\0';
01308       *out = c;
01309       return 0;
01310    }
01311    return 1;
01312 }

char* get_in_brackets ( char *  tmp  ) 

int get_in_brackets_full ( char *  tmp,
char **  out,
char **  residue 
)

Definition at line 947 of file reqresp_parser.c.

References ast_log(), ast_strlen_zero(), find_closing_quote(), LOG_WARNING, and parse().

Referenced by get_in_brackets(), and parse_name_andor_addr().

00948 {
00949    const char *parse = tmp;
00950    char *first_bracket;
00951    char *second_bracket;
00952 
00953    if (out) {
00954       *out = "";
00955    }
00956    if (residue) {
00957       *residue = "";
00958    }
00959 
00960    if (ast_strlen_zero(tmp)) {
00961       return 1;
00962    }
00963 
00964    /*
00965     * Skip any quoted text until we find the part in brackets.
00966    * On any error give up and return -1
00967    */
00968    while ( (first_bracket = strchr(parse, '<')) ) {
00969       char *first_quote = strchr(parse, '"');
00970       first_bracket++;
00971       if (!first_quote || first_quote >= first_bracket) {
00972          break; /* no need to look at quoted part */
00973       }
00974       /* the bracket is within quotes, so ignore it */
00975       parse = find_closing_quote(first_quote + 1, NULL);
00976       if (!*parse) {
00977          ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
00978          return  -1;
00979       }
00980       parse++;
00981    }
00982 
00983    /* If no first bracket then still look for a second bracket as some other parsing functions
00984    may overwrite first bracket with NULL when terminating a token based display-name. As this
00985    only affects token based display-names there is no danger of brackets being in quotes */
00986    if (first_bracket) {
00987       parse = first_bracket;
00988    } else {
00989       parse = tmp;
00990    }
00991 
00992    if ((second_bracket = strchr(parse, '>'))) {
00993       *second_bracket++ = '\0';
00994       if (out) {
00995          *out = (char *) parse;
00996       }
00997       if (residue) {
00998          *residue = second_bracket;
00999       }
01000       return 0;
01001    }
01002 
01003    if ((first_bracket)) {
01004       ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
01005       return -1;
01006    }
01007 
01008    if (out) {
01009       *out = tmp;
01010    }
01011 
01012    return 1;
01013 }

int get_name_and_number ( const char *  hdr,
char **  name,
char **  number 
)

Definition at line 802 of file reqresp_parser.c.

References ast_copy_string(), ast_log(), ast_strdup, ast_strlen_zero(), ast_uri_decode(), ast_uri_sip_user, dummy(), get_calleridname(), get_in_brackets(), LOG_ERROR, and parse_uri().

Referenced by AST_TEST_DEFINE(), change_redirecting_information(), and get_pai().

00803 {
00804    char header[256];
00805    char tmp_name[50];
00806    char *tmp_number = NULL;
00807    char *hostport = NULL;
00808    char *dummy = NULL;
00809 
00810    if (!name || !number || ast_strlen_zero(hdr)) {
00811       return -1;
00812    }
00813 
00814    *number = NULL;
00815    *name = NULL;
00816    ast_copy_string(header, hdr, sizeof(header));
00817 
00818    /* strip the display-name portion off the beginning of the header. */
00819    get_calleridname(header, tmp_name, sizeof(tmp_name));
00820 
00821    /* get uri within < > brackets */
00822    tmp_number = get_in_brackets(header);
00823 
00824    /* parse out the number here */
00825    if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
00826       ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
00827       return -1;
00828    }
00829 
00830    /* number is not option, and must be present at this point */
00831    *number = ast_strdup(tmp_number);
00832    ast_uri_decode(*number, ast_uri_sip_user);
00833 
00834    /* name is optional and may not be present at this point */
00835    if (!ast_strlen_zero(tmp_name)) {
00836       *name = ast_strdup(tmp_name);
00837    }
00838 
00839    return 0;
00840 }

int parse_contact_header ( char *  contactheader,
struct contactliststruct *  contactlist 
)

Definition at line 1314 of file reqresp_parser.c.

References ast_calloc, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, get_comma(), last, parse_name_andor_addr(), and value.

Referenced by AST_TEST_DEFINE().

01315 {
01316    int res;
01317    int last;
01318    char *comma;
01319    char *residue;
01320    char *param;
01321    char *value;
01322    struct contact *split_contact = NULL;
01323 
01324    if (*contactheader == '*') {
01325       return 1;
01326    }
01327 
01328    split_contact = ast_calloc(1, sizeof(*split_contact));
01329 
01330    AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
01331    while ((last = get_comma(contactheader, &comma)) != -1) {
01332       res = parse_name_andor_addr(contactheader, "sip:,sips:",
01333          &split_contact->name, &split_contact->user,
01334          &split_contact->pass, &split_contact->hostport,
01335          &split_contact->params, &split_contact->headers,
01336          &residue);
01337       if (res == -1) {
01338          return res;
01339       }
01340 
01341       /* parse contact params */
01342       split_contact->expires = split_contact->q = "";
01343 
01344       while ((value = strchr(residue,'='))) {
01345          *value++ = '\0';
01346 
01347          param = residue;
01348          if ((residue = strchr(value,';'))) {
01349             *residue++ = '\0';
01350          } else {
01351             residue = "";
01352          }
01353 
01354          if (!strcmp(param,"expires")) {
01355             split_contact->expires = value;
01356          } else if (!strcmp(param,"q")) {
01357             split_contact->q = value;
01358          }
01359       }
01360 
01361       if (last) {
01362          return 0;
01363       }
01364       contactheader = comma;
01365 
01366       split_contact = ast_calloc(1, sizeof(*split_contact));
01367       AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
01368    }
01369    return last;
01370 }

int parse_name_andor_addr ( char *  uri,
const char *  scheme,
char **  name,
char **  user,
char **  pass,
char **  hostport,
struct uriparams *  params,
char **  headers,
char **  residue 
)

Definition at line 1103 of file reqresp_parser.c.

References get_calleridname(), get_in_brackets_full(), and parse_uri_full().

Referenced by AST_TEST_DEFINE(), and parse_contact_header().

01107 {
01108    char buf[1024];
01109    char **residue2 = residue;
01110    char *orig_uri = uri;
01111    int ret;
01112 
01113    buf[0] = '\0';
01114    if (name) {
01115       uri = (char *) get_calleridname(uri, buf, sizeof(buf));
01116    }
01117    ret = get_in_brackets_full(uri, &uri, residue);
01118    if (ret == 0) {
01119       /*
01120        * The uri is in brackets so do not treat unknown trailing uri
01121        * parameters as potential message header parameters.
01122        */
01123       if (residue && **residue) {
01124          /* step over the first semicolon as per parse_uri_full residue */
01125          *residue = *residue + 1;
01126       }
01127       residue2 = NULL;
01128    }
01129 
01130    if (name) {
01131       if (buf[0]) {
01132          /*
01133           * There is always room at orig_uri for the display-name because
01134           * at least one character has always been removed.  A '"' or '<'
01135           * has been removed.
01136           */
01137          strcpy(orig_uri, buf);
01138          *name = orig_uri;
01139       } else {
01140          *name = "";
01141       }
01142    }
01143 
01144    return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
01145 }

unsigned int parse_sip_options ( const char *  options,
char *  unsupported,
size_t  unsupported_len 
)

Parse supported header in incoming packet.

This function parses through the options parameters and builds a bit field representing all the SIP options in that field. When an item is found that is not supported, it is copied to the unsupported out buffer.

Parameters:
option list
unsupported out buffer (optional)
unsupported out buffer length (optional)

Definition at line 1526 of file reqresp_parser.c.

References ARRAY_LEN, ast_copy_string(), ast_debug, ast_strdupa, ast_strip(), ast_strlen_zero(), FALSE, text, and TRUE.

Referenced by AST_TEST_DEFINE(), handle_request_bye(), and handle_request_invite().

01527 {
01528    char *next, *sep;
01529    char *temp;
01530    int i, found, supported;
01531    unsigned int profile = 0;
01532 
01533    char *out = unsupported;
01534    size_t outlen = unsupported_len;
01535    char *cur_out = out;
01536 
01537    if (out && (outlen > 0)) {
01538       memset(out, 0, outlen);
01539    }
01540 
01541    if (ast_strlen_zero(options) )
01542       return 0;
01543 
01544    temp = ast_strdupa(options);
01545 
01546    ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
01547 
01548    for (next = temp; next; next = sep) {
01549       found = FALSE;
01550       supported = FALSE;
01551       if ((sep = strchr(next, ',')) != NULL) {
01552          *sep++ = '\0';
01553       }
01554 
01555       /* trim leading and trailing whitespace */
01556       next = ast_strip(next);
01557 
01558       if (ast_strlen_zero(next)) {
01559          continue; /* if there is a blank argument in there just skip it */
01560       }
01561 
01562       ast_debug(3, "Found SIP option: -%s-\n", next);
01563       for (i = 0; i < ARRAY_LEN(sip_options); i++) {
01564          if (!strcasecmp(next, sip_options[i].text)) {
01565             profile |= sip_options[i].id;
01566             if (sip_options[i].supported == SUPPORTED) {
01567                supported = TRUE;
01568             }
01569             found = TRUE;
01570             ast_debug(3, "Matched SIP option: %s\n", next);
01571             break;
01572          }
01573       }
01574 
01575       /* If option is not supported, add to unsupported out buffer */
01576       if (!supported && out && outlen) {
01577          size_t copylen = strlen(next);
01578          size_t cur_outlen = strlen(out);
01579          /* Check to see if there is enough room to store this option.
01580           * Copy length is string length plus 2 for the ',' and '\0' */
01581          if ((cur_outlen + copylen + 2) < outlen) {
01582             /* if this isn't the first item, add the ',' */
01583             if (cur_outlen) {
01584                *cur_out = ',';
01585                cur_out++;
01586                cur_outlen++;
01587             }
01588             ast_copy_string(cur_out, next, (outlen - cur_outlen));
01589             cur_out += copylen;
01590          }
01591       }
01592 
01593       if (!found) {
01594          profile |= SIP_OPT_UNKNOWN;
01595          if (!strncasecmp(next, "x-", 2))
01596             ast_debug(3, "Found private SIP option, not supported: %s\n", next);
01597          else
01598             ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
01599       }
01600    }
01601 
01602    return profile;
01603 }

int parse_uri ( char *  uri,
const char *  scheme,
char **  user,
char **  pass,
char **  hostport,
char **  transport 
)

Definition at line 430 of file reqresp_parser.c.

References parse_uri_full().

Referenced by AST_TEST_DEFINE(), check_peer_ok(), get_name_and_number(), parse_uri_legacy_check(), and sip_msg_send().

00431                                             {
00432    int ret;
00433    char *headers;
00434    struct uriparams params;
00435 
00436    headers = NULL;
00437    ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
00438    if (transport) {
00439       *transport=params.transport;
00440    }
00441    return ret;
00442 }

int parse_uri_full ( char *  uri,
const char *  scheme,
char **  user,
char **  pass,
char **  hostport,
struct uriparams *  params,
char **  headers,
char **  residue 
)

* parses a URI in its components.

Definition at line 35 of file reqresp_parser.c.

References ast_debug, ast_strdupa, ast_strlen_zero(), strsep(), and value.

Referenced by AST_TEST_DEFINE(), parse_name_andor_addr(), and parse_uri().

00038 {
00039    char *userinfo = NULL;
00040    char *parameters = NULL;
00041    char *endparams = NULL;
00042    char *c = NULL;
00043    int error = 0;
00044 
00045    /*
00046     * Initialize requested strings - some functions don't care if parse_uri fails
00047     * and will attempt to use string pointers passed into parse_uri even after a
00048     * parse_uri failure
00049     */
00050    if (user) {
00051       *user = "";
00052    }
00053    if (pass) {
00054       *pass = "";
00055    }
00056    if (hostport) {
00057       *hostport = "";
00058    }
00059    if (headers) {
00060       *headers = "";
00061    }
00062    if (residue) {
00063       *residue = "";
00064    }
00065 
00066    /* check for valid input */
00067    if (ast_strlen_zero(uri)) {
00068       return -1;
00069    }
00070 
00071    if (scheme) {
00072       int l;
00073       char *scheme2 = ast_strdupa(scheme);
00074       char *cur = strsep(&scheme2, ",");
00075       for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
00076          l = strlen(cur);
00077          if (!strncasecmp(uri, cur, l)) {
00078             uri += l;
00079             break;
00080          }
00081       }
00082       if (ast_strlen_zero(cur)) {
00083          ast_debug(1, "No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme);
00084          error = -1;
00085       }
00086    }
00087 
00088    if (!hostport) {
00089       /* if we don't want to split around hostport, keep everything as a
00090        * userinfo - cos thats how old parse_uri operated*/
00091       userinfo = uri;
00092    } else {
00093       char *dom = "";
00094       if ((c = strchr(uri, '@'))) {
00095          *c++ = '\0';
00096          dom = c;
00097          userinfo = uri;
00098          uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
00099       } else {
00100          /* domain-only URI, according to the SIP RFC. */
00101          dom = uri;
00102          userinfo = "";
00103       }
00104 
00105       *hostport = dom;
00106    }
00107 
00108    if (pass && (c = strchr(userinfo, ':'))) {     /* user:password */
00109       *c++ = '\0';
00110       *pass = c;
00111    } else if (pass) {
00112       *pass = "";
00113    }
00114 
00115    if (user) {
00116       *user = userinfo;
00117    }
00118 
00119    parameters = uri;
00120    /* strip [?headers] from end of uri  - even if no header pointer exists*/
00121    if ((c = strrchr(uri, '?'))) {
00122       *c++ = '\0';
00123       uri = c;
00124       if (headers) {
00125          *headers = c;
00126       }
00127       if ((c = strrchr(uri, ';'))) {
00128          *c++ = '\0';
00129       } else {
00130          c = strrchr(uri, '\0');
00131       }
00132       uri = c; /* residue */
00133 
00134 
00135    } else if (headers) {
00136       *headers = "";
00137    }
00138 
00139    /* parse parameters */
00140    endparams = strchr(parameters,'\0');
00141    if ((c = strchr(parameters, ';'))) {
00142       *c++ = '\0';
00143       parameters = c;
00144    } else {
00145       parameters = endparams;
00146    }
00147 
00148    if (params) {
00149       char *rem = parameters; /* unparsed or unrecognised remainder */
00150       char *label;
00151       char *value;
00152       int lr = 0;
00153 
00154       params->transport = "";
00155       params->user = "";
00156       params->method = "";
00157       params->ttl = "";
00158       params->maddr = "";
00159       params->lr = 0;
00160 
00161       rem = parameters;
00162 
00163       while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
00164          /* The while condition will not continue evaluation to set lr if it matches "lr=" */
00165          if (lr) {
00166             value = parameters;
00167          } else {
00168             *value++ = '\0';
00169          }
00170          label = parameters;
00171          if ((c = strchr(value, ';'))) {
00172             *c++ = '\0';
00173             parameters = c;
00174          } else {
00175             parameters = endparams;
00176          }
00177 
00178          if (!strcmp(label, "transport")) {
00179             params->transport = value;
00180             rem = parameters;
00181          } else if (!strcmp(label, "user")) {
00182             params->user = value;
00183             rem = parameters;
00184          } else if (!strcmp(label, "method")) {
00185             params->method = value;
00186             rem = parameters;
00187          } else if (!strcmp(label, "ttl")) {
00188             params->ttl = value;
00189             rem = parameters;
00190          } else if (!strcmp(label, "maddr")) {
00191             params->maddr = value;
00192             rem = parameters;
00193          /* Treat "lr", "lr=yes", "lr=on", "lr=1", "lr=almostanything" as lr enabled and "", "lr=no", "lr=off", "lr=0", "lr=" and "lranything" as lr disabled */
00194          } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
00195             params->lr = 1;
00196             rem = parameters;
00197          } else {
00198             value--;
00199             *value = '=';
00200             if (c) {
00201                c--;
00202                *c = ';';
00203             }
00204          }
00205       }
00206       if (rem > uri) { /* no headers */
00207          uri = rem;
00208       }
00209 
00210    }
00211 
00212    if (residue) {
00213       *residue = uri;
00214    }
00215 
00216    return error;
00217 }

struct sip_via* parse_via ( const char *  header  )  [read]

Definition at line 2222 of file reqresp_parser.c.

References ast_calloc, ast_log(), ast_skip_blanks(), ast_strdup, ast_strlen_zero(), free_via(), LOG_ERROR, and strsep().

Referenced by AST_TEST_DEFINE(), find_call(), process_via(), and sip_alloc().

02223 {
02224    struct sip_via *v = ast_calloc(1, sizeof(*v));
02225    char *via, *parm;
02226 
02227    if (!v) {
02228       return NULL;
02229    }
02230 
02231    v->via = ast_strdup(header);
02232    v->ttl = 1;
02233 
02234    via = v->via;
02235 
02236    if (ast_strlen_zero(via)) {
02237       ast_log(LOG_ERROR, "received request without a Via header\n");
02238       free_via(v);
02239       return NULL;
02240    }
02241 
02242    /* seperate the first via-parm */
02243    via = strsep(&via, ",");
02244 
02245    /* chop off sent-protocol */
02246    v->protocol = strsep(&via, " \t\r\n");
02247    if (ast_strlen_zero(v->protocol)) {
02248       ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
02249       free_via(v);
02250       return NULL;
02251    }
02252    v->protocol = ast_skip_blanks(v->protocol);
02253 
02254    if (via) {
02255       via = ast_skip_blanks(via);
02256    }
02257 
02258    /* chop off sent-by */
02259    v->sent_by = strsep(&via, "; \t\r\n");
02260    if (ast_strlen_zero(v->sent_by)) {
02261       ast_log(LOG_ERROR, "missing sent-by in Via header\n");
02262       free_via(v);
02263       return NULL;
02264    }
02265    v->sent_by = ast_skip_blanks(v->sent_by);
02266 
02267    /* store the port, we have to handle ipv6 addresses containing ':'
02268     * characters gracefully */
02269    if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) {
02270       char *endptr;
02271 
02272       v->port = strtol(++parm, &endptr, 10);
02273    }
02274 
02275    /* evaluate any via-parms */
02276    while ((parm = strsep(&via, "; \t\r\n"))) {
02277       char *c;
02278       if ((c = strstr(parm, "maddr="))) {
02279          v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
02280       } else if ((c = strstr(parm, "branch="))) {
02281          v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
02282       } else if ((c = strstr(parm, "ttl="))) {
02283          char *endptr;
02284          c = ast_skip_blanks(c + sizeof("ttl=") - 1);
02285          v->ttl = strtol(c, &endptr, 10);
02286 
02287          /* make sure we got a valid ttl value */
02288          if (c == endptr) {
02289             v->ttl = 1;
02290          }
02291       }
02292    }
02293 
02294    return v;
02295 }

void sip_reqresp_parser_exit ( void   ) 

Definition at line 2513 of file reqresp_parser.c.

Referenced by unload_module().

02514 {
02515 #ifdef HAVE_XLOCALE_H
02516    if (c_locale) {
02517       freelocale(c_locale);
02518       c_locale = NULL;
02519    }
02520 #endif
02521 }

int sip_reqresp_parser_init ( void   ) 

Definition at line 2502 of file reqresp_parser.c.

Referenced by load_module().

02503 {
02504 #ifdef HAVE_XLOCALE_H
02505    c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
02506    if (!c_locale) {
02507       return -1;
02508    }
02509 #endif
02510    return 0;
02511 }

void sip_request_parser_register_tests ( void   ) 

Definition at line 2475 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

02476 {
02477    AST_TEST_REGISTER(get_calleridname_test);
02478    AST_TEST_REGISTER(sip_parse_uri_test);
02479    AST_TEST_REGISTER(get_in_brackets_test);
02480    AST_TEST_REGISTER(get_name_and_number_test);
02481    AST_TEST_REGISTER(sip_parse_uri_full_test);
02482    AST_TEST_REGISTER(parse_name_andor_addr_test);
02483    AST_TEST_REGISTER(parse_contact_header_test);
02484    AST_TEST_REGISTER(sip_parse_options_test);
02485    AST_TEST_REGISTER(sip_uri_cmp_test);
02486    AST_TEST_REGISTER(parse_via_test);
02487 }

void sip_request_parser_unregister_tests ( void   ) 

Definition at line 2488 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

02489 {
02490    AST_TEST_UNREGISTER(sip_parse_uri_test);
02491    AST_TEST_UNREGISTER(get_calleridname_test);
02492    AST_TEST_UNREGISTER(get_in_brackets_test);
02493    AST_TEST_UNREGISTER(get_name_and_number_test);
02494    AST_TEST_UNREGISTER(sip_parse_uri_full_test);
02495    AST_TEST_UNREGISTER(parse_name_andor_addr_test);
02496    AST_TEST_UNREGISTER(parse_contact_header_test);
02497    AST_TEST_UNREGISTER(sip_parse_options_test);
02498    AST_TEST_UNREGISTER(sip_uri_cmp_test);
02499    AST_TEST_UNREGISTER(parse_via_test);
02500 }

int sip_uri_cmp ( const char *  input1,
const char *  input2 
)

Definition at line 1988 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero(), ast_uri_decode(), ast_uri_sip_user, S_OR, sip_uri_domain_cmp(), sip_uri_headers_cmp(), sip_uri_params_cmp(), and strsep().

Referenced by AST_TEST_DEFINE(), find_by_notify_uri_helper(), find_by_subscribe_uri_helper(), handle_request_invite(), and match_req_to_dialog().

01989 {
01990    char *uri1;
01991    char *uri2;
01992    char *uri_scheme1;
01993    char *uri_scheme2;
01994    char *host1;
01995    char *host2;
01996    char *params1;
01997    char *params2;
01998    char *headers1;
01999    char *headers2;
02000 
02001    /* XXX It would be really nice if we could just use parse_uri_full() here
02002     * to separate the components of the URI, but unfortunately it is written
02003     * in a way that can cause URI parameters to be discarded.
02004     */
02005 
02006    if (!input1 || !input2) {
02007       return 1;
02008    }
02009 
02010    uri1 = ast_strdupa(input1);
02011    uri2 = ast_strdupa(input2);
02012 
02013    ast_uri_decode(uri1, ast_uri_sip_user);
02014    ast_uri_decode(uri2, ast_uri_sip_user);
02015 
02016    uri_scheme1 = strsep(&uri1, ":");
02017    uri_scheme2 = strsep(&uri2, ":");
02018 
02019    if (strcmp(uri_scheme1, uri_scheme2)) {
02020       return 1;
02021    }
02022 
02023    /* This function is tailored for SIP and SIPS URIs. There's no
02024     * need to check uri_scheme2 since we have determined uri_scheme1
02025     * and uri_scheme2 are equivalent already.
02026     */
02027    if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
02028       return 1;
02029    }
02030 
02031    if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
02032       return 1;
02033    }
02034 
02035    if ((host1 = strchr(uri1, '@'))) {
02036       *host1++ = '\0';
02037    }
02038    if ((host2 = strchr(uri2, '@'))) {
02039       *host2++ = '\0';
02040    }
02041 
02042    /* Check for mismatched username and passwords. This is the
02043     * only case-sensitive comparison of a SIP URI
02044     */
02045    if ((host1 && !host2) ||
02046          (host2 && !host1) ||
02047          (host1 && host2 && strcmp(uri1, uri2))) {
02048       return 1;
02049    }
02050 
02051    if (!host1) {
02052       host1 = uri1;
02053    }
02054    if (!host2) {
02055       host2 = uri2;
02056    }
02057 
02058    /* Strip off the parameters and headers so we can compare
02059     * host and port
02060     */
02061 
02062    if ((params1 = strchr(host1, ';'))) {
02063       *params1++ = '\0';
02064    }
02065    if ((params2 = strchr(host2, ';'))) {
02066       *params2++ = '\0';
02067    }
02068 
02069    /* Headers come after parameters, but there may be headers without
02070     * parameters, thus the S_OR
02071     */
02072    if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
02073       *headers1++ = '\0';
02074    }
02075    if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
02076       *headers2++ = '\0';
02077    }
02078 
02079    if (sip_uri_domain_cmp(host1, host2)) {
02080       return 1;
02081    }
02082 
02083    /* Headers have easier rules to follow, so do those first */
02084    if (sip_uri_headers_cmp(headers1, headers2)) {
02085       return 1;
02086    }
02087 
02088    /* And now the parameters. Ugh */
02089    return sip_uri_params_cmp(params1, params2);
02090 }

static int sip_uri_domain_cmp ( const char *  host1,
const char *  host2 
) [static]

Compare domain sections of SIP URIs.

For hostnames, a case insensitive string comparison is used. For IP addresses, a binary comparison is used. This is mainly because IPv6 addresses have many ways of writing the same address.

For specifics about IP address comparison, see the following document: http://tools.ietf.org/html/draft-ietf-sip-ipv6-abnf-fix-05

Parameters:
host1 The domain from the first URI
host2 THe domain from the second URI
Return values:
0 The domains match
nonzero The domains do not match

Definition at line 1950 of file reqresp_parser.c.

References ast_sockaddr_cmp(), and ast_sockaddr_parse().

Referenced by sip_uri_cmp().

01951 {
01952    struct ast_sockaddr addr1;
01953    struct ast_sockaddr addr2;
01954    int addr1_parsed;
01955    int addr2_parsed;
01956 
01957    addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
01958    addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
01959 
01960    if (addr1_parsed != addr2_parsed) {
01961       /* One domain was an IP address and the other had
01962        * a host name. FAIL!
01963        */
01964       return 1;
01965    }
01966 
01967    /* Both are host names. A string comparison will work
01968     * perfectly here. Specifying the "C" locale ensures that
01969     * The LC_CTYPE conventions use those defined in ANSI C,
01970     * i.e. ASCII.
01971     */
01972    if (!addr1_parsed) {
01973 #ifdef HAVE_XLOCALE_H
01974       if(!c_locale) {
01975          return strcasecmp(host1, host2);
01976       } else {
01977          return strcasecmp_l(host1, host2, c_locale);
01978       }
01979 #else
01980       return strcasecmp(host1, host2);
01981 #endif
01982    }
01983 
01984    /* Both contain IP addresses */
01985    return ast_sockaddr_cmp(&addr1, &addr2);
01986 }

static int sip_uri_headers_cmp ( const char *  input1,
const char *  input2 
) [static]

helper routine for sip_uri_cmp to compare URI headers

This takes the headers from two SIP URIs and determines if the URIs match. The rules for headers is simple. If a header appears in one URI, then it must also appear in the other URI. The order in which the headers appear does not matter.

Parameters:
input1 Headers from URI 1
input2 Headers from URI 2
Return values:
0 URI headers match
nonzero URI headers do not match

Definition at line 1885 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero(), strcasestr(), and strsep().

Referenced by sip_uri_cmp().

01886 {
01887    char *headers1 = NULL;
01888    char *headers2 = NULL;
01889    int zerolength1 = 0;
01890    int zerolength2 = 0;
01891    int different = 0;
01892    char *header1;
01893 
01894    if (ast_strlen_zero(input1)) {
01895       zerolength1 = 1;
01896    } else {
01897       headers1 = ast_strdupa(input1);
01898    }
01899 
01900    if (ast_strlen_zero(input2)) {
01901       zerolength2 = 1;
01902    } else {
01903       headers2 = ast_strdupa(input2);
01904    }
01905 
01906    /* If one URI contains no headers and the other
01907     * does, then they cannot possibly match
01908     */
01909    if (zerolength1 != zerolength2) {
01910       return 1;
01911    }
01912 
01913    if (zerolength1 && zerolength2)
01914       return 0;
01915 
01916    /* At this point, we can definitively state that both inputs are
01917     * not zero-length. First, one more optimization. If the length
01918     * of the headers is not equal, then we definitely have no match
01919     */
01920    if (strlen(headers1) != strlen(headers2)) {
01921       return 1;
01922    }
01923 
01924    for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
01925       if (!strcasestr(headers2, header1)) {
01926          different = 1;
01927          break;
01928       }
01929    }
01930 
01931    return different;
01932 }

static int sip_uri_params_cmp ( const char *  input1,
const char *  input2 
) [static]

helper routine for sip_uri_cmp to compare URI parameters

This takes the parameters from two SIP URIs and determines if the URIs match. The rules for parameters *suck*. Here's a breakdown 1. If a parameter appears in both URIs, then they must have the same value in order for the URIs to match 2. If one URI has a user, maddr, ttl, or method parameter, then the other URI must also have that parameter and must have the same value in order for the URIs to match 3. All other headers appearing in only one URI are not considered when determining if URIs match

Parameters:
input1 Parameters from URI 1
input2 Parameters from URI 2
Return values:
0 URIs' parameters match
nonzero URIs' parameters do not match

Definition at line 1759 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero(), and strsep().

Referenced by sip_uri_cmp().

01760 {
01761    char *params1 = NULL;
01762    char *params2 = NULL;
01763    char *pos1;
01764    char *pos2;
01765    int zerolength1 = 0;
01766    int zerolength2 = 0;
01767    int maddrmatch = 0;
01768    int ttlmatch = 0;
01769    int usermatch = 0;
01770    int methodmatch = 0;
01771 
01772    if (ast_strlen_zero(input1)) {
01773       zerolength1 = 1;
01774    } else {
01775       params1 = ast_strdupa(input1);
01776    }
01777    if (ast_strlen_zero(input2)) {
01778       zerolength2 = 1;
01779    } else {
01780       params2 = ast_strdupa(input2);
01781    }
01782 
01783    /* Quick optimization. If both params are zero-length, then
01784     * they match
01785     */
01786    if (zerolength1 && zerolength2) {
01787       return 0;
01788    }
01789 
01790    for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
01791       char *value1 = pos1;
01792       char *name1 = strsep(&value1, "=");
01793       char *params2dup = NULL;
01794       int matched = 0;
01795       if (!value1) {
01796          value1 = "";
01797       }
01798       /* Checkpoint reached. We have the name and value parsed for param1
01799        * We have to duplicate params2 each time through this loop
01800        * or else the inner loop below will not work properly.
01801        */
01802       if (!zerolength2) {
01803          params2dup = ast_strdupa(params2);
01804       }
01805       for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
01806          char *name2 = pos2;
01807          char *value2 = strchr(pos2, '=');
01808          if (!value2) {
01809             value2 = "";
01810          } else {
01811             *value2++ = '\0';
01812          }
01813          if (!strcasecmp(name1, name2)) {
01814             if (strcasecmp(value1, value2)) {
01815                goto fail;
01816             } else {
01817                matched = 1;
01818                break;
01819             }
01820          }
01821       }
01822       /* Check to see if the parameter is one of the 'must-match' parameters */
01823       if (!strcasecmp(name1, "maddr")) {
01824          if (matched) {
01825             maddrmatch = 1;
01826          } else {
01827             goto fail;
01828          }
01829       } else if (!strcasecmp(name1, "ttl")) {
01830          if (matched) {
01831             ttlmatch = 1;
01832          } else {
01833             goto fail;
01834          }
01835       } else if (!strcasecmp(name1, "user")) {
01836          if (matched) {
01837             usermatch = 1;
01838          } else {
01839             goto fail;
01840          }
01841       } else if (!strcasecmp(name1, "method")) {
01842          if (matched) {
01843             methodmatch = 1;
01844          } else {
01845             goto fail;
01846          }
01847       }
01848    }
01849 
01850    /* We've made it out of that horrible O(m*n) construct and there are no
01851     * failures yet. We're not done yet, though, because params2 could have
01852     * an maddr, ttl, user, or method header and params1 did not.
01853     */
01854    for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
01855       char *value2 = pos2;
01856       char *name2 = strsep(&value2, "=");
01857       if (!value2) {
01858          value2 = "";
01859       }
01860       if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
01861             (!strcasecmp(name2, "ttl") && !ttlmatch) ||
01862             (!strcasecmp(name2, "user") && !usermatch) ||
01863             (!strcasecmp(name2, "method") && !methodmatch)) {
01864          goto fail;
01865       }
01866    }
01867    return 0;
01868 
01869 fail:
01870    return 1;
01871 }


Generated on Sun May 20 06:36:53 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6