Mon Oct 8 12:39:27 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"

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.
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

Variables

locale_t c_locale


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 2096 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

#define URI_CMP_NOMATCH   1

Definition at line 2097 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().


Function Documentation

AST_TEST_DEFINE ( parse_via_test   ) 

Definition at line 2301 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(), t1, t7, TEST_EXECUTE, and TEST_INIT.

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

AST_TEST_DEFINE ( sip_uri_cmp_test   ) 

Definition at line 2099 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.

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

AST_TEST_DEFINE ( sip_parse_options_test   ) 

Definition at line 1609 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.

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

AST_TEST_DEFINE ( parse_contact_header_test   ) 

Definition at line 1376 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.

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

AST_TEST_DEFINE ( parse_name_andor_addr_test   ) 

Definition at line 1151 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.

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

AST_TEST_DEFINE ( get_in_brackets_test   ) 

Definition at line 1029 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.

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

AST_TEST_DEFINE ( get_name_and_number_test   ) 

Definition at line 846 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.

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

AST_TEST_DEFINE ( get_calleridname_test   ) 

Definition at line 723 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.

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

AST_TEST_DEFINE ( sip_parse_uri_test   ) 

Definition at line 448 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.

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

AST_TEST_DEFINE ( sip_parse_uri_full_test   ) 

Definition at line 224 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.

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

void free_via ( struct sip_via *  v  ) 

Definition at line 2216 of file reqresp_parser.c.

References ast_free.

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

02217 {
02218    if (!v) {
02219       return;
02220    }
02221 
02222    ast_free(v->via);
02223    ast_free(v);
02224 }

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 598 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(), and parse_name_andor_addr().

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

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

Definition at line 1281 of file reqresp_parser.c.

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

Referenced by parse_contact_header().

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

char* get_in_brackets ( char *  tmp  ) 

Definition at line 1019 of file reqresp_parser.c.

References get_in_brackets_full().

Referenced by AST_TEST_DEFINE(), build_route(), check_user_full(), extract_uri(), get_also_info(), get_destination(), get_domain(), get_name_and_number(), get_pai(), get_rdnis(), get_refer_info(), handle_cc_notify(), parse_moved_contact(), parse_ok_contact(), parse_register_contact(), register_verify(), reqprep(), sip_get_cc_information(), transmit_refer(), and transmit_state_notify().

01020 {
01021    char *out;
01022 
01023    if ((get_in_brackets_full(tmp, &out, NULL))) {
01024       return tmp;
01025    }
01026    return out;
01027 }

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

Definition at line 951 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().

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

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

Definition at line 806 of file reqresp_parser.c.

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

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

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

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

Definition at line 1318 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().

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

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 1107 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().

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

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 1530 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().

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

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

Definition at line 434 of file reqresp_parser.c.

References parse_uri_full().

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

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

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 39 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().

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

struct sip_via* parse_via ( const char *  header  ) 

Definition at line 2226 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().

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

void sip_reqresp_parser_exit ( void   ) 

Definition at line 2517 of file reqresp_parser.c.

02518 {
02519 #ifdef HAVE_XLOCALE_H
02520    if (c_locale) {
02521       freelocale(c_locale);
02522       c_locale = NULL;
02523    }
02524 #endif
02525 }

int sip_reqresp_parser_init ( void   ) 

Definition at line 2506 of file reqresp_parser.c.

Referenced by load_module().

02507 {
02508 #ifdef HAVE_XLOCALE_H
02509    c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
02510    if (!c_locale) {
02511       return -1;
02512    }
02513 #endif
02514    return 0;
02515 }

void sip_request_parser_register_tests ( void   ) 

Definition at line 2479 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

02480 {
02481    AST_TEST_REGISTER(get_calleridname_test);
02482    AST_TEST_REGISTER(sip_parse_uri_test);
02483    AST_TEST_REGISTER(get_in_brackets_test);
02484    AST_TEST_REGISTER(get_name_and_number_test);
02485    AST_TEST_REGISTER(sip_parse_uri_full_test);
02486    AST_TEST_REGISTER(parse_name_andor_addr_test);
02487    AST_TEST_REGISTER(parse_contact_header_test);
02488    AST_TEST_REGISTER(sip_parse_options_test);
02489    AST_TEST_REGISTER(sip_uri_cmp_test);
02490    AST_TEST_REGISTER(parse_via_test);
02491 }

void sip_request_parser_unregister_tests ( void   ) 

Definition at line 2492 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

02493 {
02494    AST_TEST_UNREGISTER(sip_parse_uri_test);
02495    AST_TEST_UNREGISTER(get_calleridname_test);
02496    AST_TEST_UNREGISTER(get_in_brackets_test);
02497    AST_TEST_UNREGISTER(get_name_and_number_test);
02498    AST_TEST_UNREGISTER(sip_parse_uri_full_test);
02499    AST_TEST_UNREGISTER(parse_name_andor_addr_test);
02500    AST_TEST_UNREGISTER(parse_contact_header_test);
02501    AST_TEST_UNREGISTER(sip_parse_options_test);
02502    AST_TEST_UNREGISTER(sip_uri_cmp_test);
02503    AST_TEST_UNREGISTER(parse_via_test);
02504 }

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

Definition at line 1992 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero(), ast_uri_decode(), 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().

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

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 1954 of file reqresp_parser.c.

References ast_sockaddr_cmp(), and ast_sockaddr_parse().

Referenced by sip_uri_cmp().

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

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 1889 of file reqresp_parser.c.

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

Referenced by sip_uri_cmp().

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

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 1763 of file reqresp_parser.c.

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

Referenced by sip_uri_cmp().

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


Variable Documentation

locale_t c_locale

Definition at line 35 of file reqresp_parser.c.


Generated on Mon Oct 8 12:39:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7