Wed Oct 29 05:04:50 2014

Asterisk developer's documentation


reqresp_parser.c File Reference

sip request parsing functions and unit tests More...

#include "asterisk.h"
#include "include/sip.h"
#include "include/sip_utils.h"
#include "include/reqresp_parser.h"
Include dependency graph for reqresp_parser.c:

Go to the source code of this file.

Defines

#define URI_CMP_MATCH   0
#define URI_CMP_NOMATCH   1

Functions

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

Detailed Description

sip request parsing functions and unit tests

Definition in file reqresp_parser.c.


Define Documentation

#define URI_CMP_MATCH   0

Definition at line 2153 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

#define URI_CMP_NOMATCH   1

Definition at line 2154 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().


Function Documentation

AST_TEST_DEFINE ( parse_via_test   ) 

Definition at line 2358 of file reqresp_parser.c.

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

02359 {
02360    int res = AST_TEST_PASS;
02361    int i = 1;
02362    struct sip_via *via;
02363    struct testdata {
02364       char *in;
02365       char *expected_protocol;
02366       char *expected_branch;
02367       char *expected_sent_by;
02368       char *expected_maddr;
02369       unsigned int expected_port;
02370       unsigned char expected_ttl;
02371       int expected_null;
02372       AST_LIST_ENTRY(testdata) list;
02373    };
02374    struct testdata *testdataptr;
02375    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
02376    struct testdata t1 = {
02377       .in = "SIP/2.0/UDP host:port;branch=thebranch",
02378       .expected_protocol = "SIP/2.0/UDP",
02379       .expected_sent_by = "host:port",
02380       .expected_branch = "thebranch",
02381    };
02382    struct testdata t2 = {
02383       .in = "SIP/2.0/UDP host:port",
02384       .expected_protocol = "SIP/2.0/UDP",
02385       .expected_sent_by = "host:port",
02386       .expected_branch = "",
02387    };
02388    struct testdata t3 = {
02389       .in = "SIP/2.0/UDP",
02390       .expected_null = 1,
02391    };
02392    struct testdata t4 = {
02393       .in = "BLAH/BLAH/BLAH host:port;branch=",
02394       .expected_protocol = "BLAH/BLAH/BLAH",
02395       .expected_sent_by = "host:port",
02396       .expected_branch = "",
02397    };
02398    struct testdata t5 = {
02399       .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
02400       .expected_protocol = "SIP/2.0/UDP",
02401       .expected_sent_by = "host:5060",
02402       .expected_port = 5060,
02403       .expected_branch = "thebranch",
02404       .expected_maddr = "224.0.0.1",
02405       .expected_ttl = 1,
02406    };
02407    struct testdata t6 = {
02408       .in = "SIP/2.0/UDP      host:5060;\n   branch=thebranch;\r\n  maddr=224.0.0.1;   ttl=1",
02409       .expected_protocol = "SIP/2.0/UDP",
02410       .expected_sent_by = "host:5060",
02411       .expected_port = 5060,
02412       .expected_branch = "thebranch",
02413       .expected_maddr = "224.0.0.1",
02414       .expected_ttl = 1,
02415    };
02416    struct testdata t7 = {
02417       .in = "SIP/2.0/UDP [::1]:5060",
02418       .expected_protocol = "SIP/2.0/UDP",
02419       .expected_sent_by = "[::1]:5060",
02420       .expected_port = 5060,
02421       .expected_branch = "",
02422    };
02423    switch (cmd) {
02424    case TEST_INIT:
02425       info->name = "parse_via_test";
02426       info->category = "/channels/chan_sip/";
02427       info->summary = "Tests parsing the Via header";
02428       info->description =
02429             "Runs through various test situations in which various "
02430             " parameters parameter must be extracted from a VIA header";
02431       return AST_TEST_NOT_RUN;
02432    case TEST_EXECUTE:
02433       break;
02434    }
02435 
02436    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
02437    AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
02438    AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
02439    AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
02440    AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
02441    AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
02442    AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
02443 
02444 
02445    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
02446       via = parse_via(testdataptr->in);
02447       if (!via) {
02448               if (!testdataptr->expected_null) {
02449             ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02450                "failed to parse header\n",
02451             i, testdataptr->in);
02452             res = AST_TEST_FAIL;
02453          }
02454          i++;
02455          continue;
02456       }
02457 
02458       if (testdataptr->expected_null) {
02459          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02460             "successfully parased invalid via header\n",
02461          i, testdataptr->in);
02462          res = AST_TEST_FAIL;
02463          free_via(via);
02464          i++;
02465          continue;
02466       }
02467 
02468       if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
02469          || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
02470 
02471          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02472             "parsed protocol = \"%s\"\n"
02473             "expected = \"%s\"\n"
02474             "failed to parse protocol\n",
02475          i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
02476          res = AST_TEST_FAIL;
02477       }
02478 
02479       if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
02480          || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
02481 
02482          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02483             "parsed sent_by = \"%s\"\n"
02484             "expected = \"%s\"\n"
02485             "failed to parse sent-by\n",
02486          i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
02487          res = AST_TEST_FAIL;
02488       }
02489 
02490       if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
02491          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02492             "parsed port = \"%u\"\n"
02493             "expected = \"%u\"\n"
02494             "failed to parse port\n",
02495          i, testdataptr->in, via->port, testdataptr->expected_port);
02496          res = AST_TEST_FAIL;
02497       }
02498 
02499       if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
02500          || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
02501 
02502          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02503             "parsed branch = \"%s\"\n"
02504             "expected = \"%s\"\n"
02505             "failed to parse branch\n",
02506          i, testdataptr->in, via->branch, testdataptr->expected_branch);
02507          res = AST_TEST_FAIL;
02508       }
02509 
02510       if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
02511          || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
02512 
02513          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02514             "parsed maddr = \"%s\"\n"
02515             "expected = \"%s\"\n"
02516             "failed to parse maddr\n",
02517          i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
02518          res = AST_TEST_FAIL;
02519       }
02520 
02521       if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
02522          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02523             "parsed ttl = \"%d\"\n"
02524             "expected = \"%d\"\n"
02525             "failed to parse ttl\n",
02526          i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
02527          res = AST_TEST_FAIL;
02528       }
02529 
02530       free_via(via);
02531       i++;
02532    }
02533    return res;
02534 }

AST_TEST_DEFINE ( sip_uri_cmp_test   ) 

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

02157 {
02158    static const struct {
02159       const char *uri1;
02160       const char *uri2;
02161       int expected_result;
02162    } uri_cmp_tests [] = {
02163       /* These are identical, so they match */
02164       { "sip:bob@example.com", "sip:bob@example.com", URI_CMP_MATCH },
02165       /* Different usernames. No match */
02166       { "sip:alice@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
02167       /* Different hosts. No match */
02168       { "sip:bob@example.com", "sip:bob@examplez.com", URI_CMP_NOMATCH },
02169       /* Now start using IP addresses. Identical, so they match */
02170       { "sip:bob@1.2.3.4", "sip:bob@1.2.3.4", URI_CMP_MATCH },
02171       /* Two identical IPv4 addresses represented differently. Match */
02172       { "sip:bob@1.2.3.4", "sip:bob@001.002.003.004", URI_CMP_MATCH },
02173       /* Logically equivalent IPv4 Address and hostname. No Match */
02174       { "sip:bob@127.0.0.1", "sip:bob@localhost", URI_CMP_NOMATCH },
02175       /* Logically equivalent IPv6 address and hostname. No Match */
02176       { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
02177       /* Try an IPv6 one as well */
02178       { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
02179       /* Two identical IPv6 addresses represented differently. Match */
02180       { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
02181       /* Different ports. No match */
02182       { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4:5061", URI_CMP_NOMATCH },
02183       /* Same port logically, but only one address specifies it. No match */
02184       { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4", URI_CMP_NOMATCH },
02185       /* And for safety, try with IPv6 */
02186       { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
02187       /* User comparison is case sensitive. No match */
02188       { "sip:bob@example.com", "sip:BOB@example.com", URI_CMP_NOMATCH },
02189       /* Host comparison is case insensitive. Match */
02190       { "sip:bob@example.com", "sip:bob@EXAMPLE.COM", URI_CMP_MATCH },
02191       /* Add headers to the URI. Identical, so they match */
02192       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value2", URI_CMP_MATCH },
02193       /* Headers in URI 1 are not in URI 2. No Match */
02194       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com", URI_CMP_NOMATCH },
02195       /* Header present in both URIs does not have matching values. No match */
02196       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value3", URI_CMP_NOMATCH },
02197       /* Add parameters to the URI. Identical so they match */
02198       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
02199       /* Same parameters in both URIs but appear in different order. Match */
02200       { "sip:bob@example.com;param2=value2;param1=value1", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
02201       /* params in URI 1 are not in URI 2. Match */
02202       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com", URI_CMP_MATCH },
02203       /* param present in both URIs does not have matching values. No match */
02204       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value3", URI_CMP_NOMATCH },
02205       /* URI 1 has a maddr param but URI 2 does not. No match */
02206       { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1", URI_CMP_NOMATCH },
02207       /* URI 1 and URI 2 both have identical maddr params. Match */
02208       { "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 },
02209       /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
02210       { "sips:bob@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
02211       /* No URI schemes. No match */
02212       { "bob@example.com", "bob@example.com", URI_CMP_NOMATCH },
02213       /* Crashiness tests. Just an address scheme. No match */
02214       { "sip", "sips", URI_CMP_NOMATCH },
02215       /* Still just an address scheme. Even though they're the same, No match */
02216       { "sip", "sip", URI_CMP_NOMATCH },
02217       /* Empty strings. No match */
02218       { "", "", URI_CMP_NOMATCH },
02219       /* An empty string and a NULL. No match */
02220       { "", NULL, URI_CMP_NOMATCH },
02221    };
02222    int i;
02223    int test_res = AST_TEST_PASS;
02224    switch (cmd) {
02225    case TEST_INIT:
02226       info->name = "sip_uri_cmp_test";
02227       info->category = "/channels/chan_sip/";
02228       info->summary = "Tests comparison of SIP URIs";
02229       info->description = "Several would-be tricky URI comparisons are performed";
02230       return AST_TEST_NOT_RUN;
02231    case TEST_EXECUTE:
02232       break;
02233    }
02234 
02235    for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
02236       int cmp_res1;
02237       int cmp_res2;
02238       if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
02239          /* URI comparison may return -1 or +1 depending on the failure. Standardize
02240           * the return value to be URI_CMP_NOMATCH on any failure
02241           */
02242          cmp_res1 = URI_CMP_NOMATCH;
02243       }
02244       if (cmp_res1 != uri_cmp_tests[i].expected_result) {
02245          ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
02246                "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
02247                uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
02248                cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
02249          test_res = AST_TEST_FAIL;
02250       }
02251 
02252       /* All URI comparisons are commutative, so for the sake of being thorough, we'll
02253        * rerun the comparison with the parameters reversed
02254        */
02255       if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
02256          /* URI comparison may return -1 or +1 depending on the failure. Standardize
02257           * the return value to be URI_CMP_NOMATCH on any failure
02258           */
02259          cmp_res2 = URI_CMP_NOMATCH;
02260       }
02261       if (cmp_res2 != uri_cmp_tests[i].expected_result) {
02262          ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
02263                "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
02264                uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
02265                cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
02266          test_res = AST_TEST_FAIL;
02267       }
02268    }
02269 
02270    return test_res;
02271 }

AST_TEST_DEFINE ( sip_parse_options_test   ) 

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

01667 {
01668    int res = AST_TEST_PASS;
01669    char unsupported[64];
01670    unsigned int option_profile = 0;
01671    struct testdata {
01672       char *name;
01673       char *input_options;
01674       char *expected_unsupported;
01675       unsigned int expected_profile;
01676       AST_LIST_ENTRY(testdata) list;
01677    };
01678 
01679    struct testdata *testdataptr;
01680    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01681 
01682    struct testdata test1 = {
01683       .name = "test_all_unsupported",
01684       .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
01685       .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
01686       .expected_profile = SIP_OPT_UNKNOWN,
01687    };
01688    struct testdata test2 = {
01689       .name = "test_all_unsupported_one_supported",
01690       .input_options = "  unsupported1, replaces,   unsupported3  , , , ,unsupported4",
01691       .expected_unsupported = "unsupported1,unsupported3,unsupported4",
01692       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
01693    };
01694    struct testdata test3 = {
01695       .name = "test_two_supported_two_unsupported",
01696       .input_options = ",,  timer  ,replaces     ,unsupported3,unsupported4",
01697       .expected_unsupported = "unsupported3,unsupported4",
01698       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
01699    };
01700 
01701    struct testdata test4 = {
01702       .name = "test_all_supported",
01703       .input_options = "timer,replaces",
01704       .expected_unsupported = "",
01705       .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
01706    };
01707 
01708    struct testdata test5 = {
01709       .name = "test_all_supported_redundant",
01710       .input_options = "timer,replaces,timer,replace,timer,replaces",
01711       .expected_unsupported = "",
01712       .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
01713    };
01714    struct testdata test6 = {
01715       .name = "test_buffer_overflow",
01716       .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
01717       "____________________________________,__________________________________________"
01718       "________________________________________________",
01719       .expected_unsupported = "unsupported1,unsupported4",
01720       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
01721    };
01722    struct testdata test7 = {
01723       .name = "test_null_input",
01724       .input_options = NULL,
01725       .expected_unsupported = "",
01726       .expected_profile = 0,
01727    };
01728    struct testdata test8 = {
01729       .name = "test_whitespace_input",
01730       .input_options = "         ",
01731       .expected_unsupported = "",
01732       .expected_profile = 0,
01733    };
01734    struct testdata test9 = {
01735       .name = "test_whitespace_plus_option_input",
01736       .input_options = " , , ,timer , ,  , ,        ,    ",
01737       .expected_unsupported = "",
01738       .expected_profile = SIP_OPT_TIMER,
01739    };
01740 
01741    switch (cmd) {
01742    case TEST_INIT:
01743       info->name = "sip_parse_options_test";
01744       info->category = "/channels/chan_sip/";
01745       info->summary = "Tests parsing of sip options";
01746       info->description =
01747                      "Tests parsing of SIP options from supported and required "
01748                      "header fields.  Verifies when unsupported options are encountered "
01749                      "that they are appended to the unsupported out buffer and that the "
01750                      "correct bit field representnig the option profile is returned.";
01751       return AST_TEST_NOT_RUN;
01752    case TEST_EXECUTE:
01753       break;
01754    }
01755 
01756    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
01757    AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
01758    AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
01759    AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
01760    AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
01761    AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
01762    AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
01763    AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
01764    AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
01765 
01766    /* Test with unsupported char buffer */
01767    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01768       option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
01769       if (option_profile != testdataptr->expected_profile ||
01770          strcmp(unsupported, testdataptr->expected_unsupported)) {
01771          ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
01772             "%s expected bit profile: %x actual bit profile: %x\n",
01773             testdataptr->name,
01774             testdataptr->expected_unsupported,
01775             unsupported,
01776             testdataptr->expected_profile,
01777             option_profile);
01778          res = AST_TEST_FAIL;
01779       } else {
01780          ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
01781             testdataptr->name,
01782             unsupported,
01783             option_profile);
01784       }
01785 
01786       option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
01787       if (option_profile != testdataptr->expected_profile) {
01788          ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
01789             testdataptr->name,
01790             testdataptr->expected_profile,
01791             option_profile);
01792          res = AST_TEST_FAIL;
01793       } else {
01794          ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
01795             testdataptr->name,
01796             option_profile);
01797       }
01798    }
01799 
01800    return res;
01801 }

AST_TEST_DEFINE ( parse_contact_header_test   ) 

Definition at line 1429 of file reqresp_parser.c.

References ast_copy_string(), ast_free, AST_LIST_ENTRY, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, 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.

01430 {
01431    int res = AST_TEST_PASS;
01432    char contactheader[1024];
01433    int star;
01434    struct contactliststruct contactlist;
01435    struct contactliststruct *contactlistptr=&contactlist;
01436 
01437    struct testdata {
01438       char *desc;
01439       char *contactheader;
01440       int star;
01441       struct contactliststruct *contactlist;
01442 
01443       AST_LIST_ENTRY(testdata) list;
01444    };
01445 
01446    struct testdata *testdataptr;
01447    struct contact *tdcontactptr;
01448    struct contact *contactptr;
01449 
01450    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01451    struct contactliststruct contactlist1, contactlist2;
01452 
01453    struct testdata td1 = {
01454       .desc = "single contact",
01455       .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
01456       .contactlist = &contactlist1,
01457       .star = 0
01458    };
01459    struct contact contact11 = {
01460       .name = "name :@;?&,",
01461       .user = "user",
01462       .pass = "secret",
01463       .hostport = "host:5082",
01464       .params.transport = "tcp",
01465       .params.ttl = "",
01466       .params.lr = 0,
01467       .headers = "",
01468       .expires = "3600",
01469       .q = ""
01470    };
01471 
01472    struct testdata td2 = {
01473       .desc = "multiple contacts",
01474       .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
01475       .contactlist = &contactlist2,
01476       .star = 0,
01477    };
01478    struct contact contact21 = {
01479       .name = "",
01480       .user = ",user1,",
01481       .pass = ",secret1,",
01482       .hostport = "host1",
01483       .params.transport = "",
01484       .params.ttl = "7",
01485       .params.lr = 0,
01486       .headers = "",
01487       .expires = "3600",
01488       .q = "1"
01489    };
01490    struct contact contact22 = {
01491       .name = "",
01492       .user = "",
01493       .pass = "",
01494       .hostport = "host2",
01495       .params.transport = "",
01496       .params.ttl = "",
01497       .params.lr = 0,
01498       .headers = "",
01499       .expires = "",
01500       .q = ""
01501    };
01502 
01503    struct testdata td3 = {
01504       .desc = "star - all contacts",
01505       .contactheader = "*",
01506       .star = 1,
01507       .contactlist = NULL
01508    };
01509 
01510    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
01511    AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
01512    AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
01513 
01514    AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
01515 
01516    AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
01517    AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
01518 
01519 
01520    switch (cmd) {
01521    case TEST_INIT:
01522       info->name = "parse_contact_header_test";
01523       info->category = "/channels/chan_sip/";
01524       info->summary = "tests parsing of sip contact header";
01525       info->description =
01526          "Tests parsing of a contact header including those with multiple contacts "
01527          "Verifies output matches expected behavior.";
01528       return AST_TEST_NOT_RUN;
01529    case TEST_EXECUTE:
01530       break;
01531    }
01532 
01533    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01534       ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
01535       star = parse_contact_header(contactheader,contactlistptr);
01536       if (testdataptr->star) {
01537          /* expecting star rather than list of contacts */
01538          if (!star) {
01539             ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01540             res = AST_TEST_FAIL;
01541             break;
01542          }
01543       } else {
01544          contactptr = AST_LIST_FIRST(contactlistptr);
01545          AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
01546             if (!contactptr ||
01547                strcmp(tdcontactptr->name, contactptr->name) ||
01548                strcmp(tdcontactptr->user, contactptr->user) ||
01549                strcmp(tdcontactptr->pass, contactptr->pass) ||
01550                strcmp(tdcontactptr->hostport, contactptr->hostport) ||
01551                strcmp(tdcontactptr->headers, contactptr->headers) ||
01552                strcmp(tdcontactptr->expires, contactptr->expires) ||
01553                strcmp(tdcontactptr->q, contactptr->q) ||
01554                strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
01555                strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
01556                (tdcontactptr->params.lr != contactptr->params.lr)
01557                ) {
01558                ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01559                res = AST_TEST_FAIL;
01560                break;
01561             }
01562 
01563             contactptr = AST_LIST_NEXT(contactptr,list);
01564          }
01565 
01566          while ((contactptr = AST_LIST_REMOVE_HEAD(contactlistptr,list))) {
01567             ast_free(contactptr);
01568          }
01569       }
01570    }
01571 
01572    return res;
01573 }

AST_TEST_DEFINE ( parse_name_andor_addr_test   ) 

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

01205 {
01206    int res = AST_TEST_PASS;
01207    char uri[1024];
01208    char *name, *user, *pass, *hostport, *headers, *residue;
01209    struct uriparams params;
01210 
01211    struct testdata {
01212       char *desc;
01213       char *uri;
01214       char *name;
01215       char *user;
01216       char *pass;
01217       char *hostport;
01218       char *headers;
01219       char *residue;
01220       struct uriparams params;
01221       AST_LIST_ENTRY(testdata) list;
01222    };
01223 
01224    struct testdata *testdataptr;
01225 
01226    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01227 
01228    struct testdata td1 = {
01229       .desc = "quotes and brackets",
01230       .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
01231       .name =  "name :@ ",
01232       .user = "user",
01233       .pass = "secret",
01234       .hostport = "host:5060",
01235       .headers = "",
01236       .residue = "tag=tag",
01237       .params.transport = "tcp",
01238       .params.lr = 0,
01239       .params.user = ""
01240    };
01241 
01242    struct testdata td2 = {
01243       .desc = "no quotes",
01244       .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
01245       .name = "givenname familyname",
01246       .user = "user",
01247       .pass = "secret",
01248       .hostport = "host:5060",
01249       .headers = "",
01250       .residue = "expires=3600",
01251       .params.transport = "tcp",
01252       .params.lr = 0,
01253       .params.user = ""
01254    };
01255 
01256    struct testdata td3 = {
01257       .desc = "no brackets",
01258       .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
01259       .name = "",
01260       .user = "user",
01261       .pass = "secret",
01262       .hostport = "host:5060",
01263       .headers = "",
01264       .residue = "q=1",
01265       .params.transport = "tcp",
01266       .params.lr = 0,
01267       .params.user = ""
01268    };
01269 
01270    struct testdata td4 = {
01271       .desc = "just host",
01272       .uri = "sips:host",
01273       .name = "",
01274       .user = "",
01275       .pass = "",
01276       .hostport = "host",
01277       .headers = "",
01278       .residue = "",
01279       .params.transport = "",
01280       .params.lr = 0,
01281       .params.user = ""
01282    };
01283 
01284 
01285    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
01286    AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
01287    AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
01288    AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
01289 
01290 
01291    switch (cmd) {
01292    case TEST_INIT:
01293       info->name = "parse_name_andor_addr_test";
01294       info->category = "/channels/chan_sip/";
01295       info->summary = "tests parsing of name_andor_addr abnf structure";
01296       info->description =
01297          "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
01298          "Verifies output matches expected behavior.";
01299       return AST_TEST_NOT_RUN;
01300    case TEST_EXECUTE:
01301       break;
01302    }
01303 
01304    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01305       name = user = pass = hostport = headers = residue = NULL;
01306       params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
01307       params.lr = 0;
01308       ast_copy_string(uri,testdataptr->uri,sizeof(uri));
01309       if (parse_name_andor_addr(uri, "sip:,sips:",
01310                  &name,
01311                  &user,
01312                  &pass,
01313                  &hostport,
01314                  &params,
01315                  &headers,
01316                  &residue) ||
01317          (name && strcmp(testdataptr->name, name)) ||
01318          (user && strcmp(testdataptr->user, user)) ||
01319          (pass && strcmp(testdataptr->pass, pass)) ||
01320          (hostport && strcmp(testdataptr->hostport, hostport)) ||
01321          (headers && strcmp(testdataptr->headers, headers)) ||
01322          (residue && strcmp(testdataptr->residue, residue)) ||
01323          (strcmp(testdataptr->params.transport,params.transport)) ||
01324          (strcmp(testdataptr->params.user,params.user))
01325          ) {
01326          ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01327          res = AST_TEST_FAIL;
01328       }
01329    }
01330 
01331    return res;
01332 }

AST_TEST_DEFINE ( get_in_brackets_test   ) 

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

01083 {
01084    int res = AST_TEST_PASS;
01085    char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
01086    char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01087    char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01088    char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01089    char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01090    char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
01091    char no_name_no_brackets[] = "sip:name@host";
01092    char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
01093    char *uri = NULL;
01094 
01095    switch (cmd) {
01096    case TEST_INIT:
01097       info->name = "sip_get_in_brackets_test";
01098       info->category = "/channels/chan_sip/";
01099       info->summary = "Tests getting a sip uri in <> brackets within a sip header.";
01100       info->description =
01101             "Runs through various test situations in which a sip uri "
01102             "in angle brackets needs to be retrieved";
01103       return AST_TEST_NOT_RUN;
01104    case TEST_EXECUTE:
01105       break;
01106    }
01107 
01108    /* Test 1, simple get in brackets */
01109    if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
01110       ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
01111       res = AST_TEST_FAIL;
01112    }
01113 
01114    /* Test 2, starts with quoted string */
01115    if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
01116       ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
01117       res = AST_TEST_FAIL;
01118    }
01119 
01120    /* Test 3, missing end quote */
01121    if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
01122       ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
01123       res = AST_TEST_FAIL;
01124    }
01125 
01126    /* Test 4, starts with a name not in quotes */
01127    if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
01128       ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
01129       res = AST_TEST_FAIL;
01130    }
01131 
01132    /* Test 5, no end bracket, should just return everything after the first '<'  */
01133    if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
01134       ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
01135       res = AST_TEST_FAIL;
01136    }
01137 
01138    /* Test 6, NULL input  */
01139    if (get_in_brackets(NULL)) {
01140       ast_test_status_update(test, "Test 6, NULL input failed.\n");
01141       res = AST_TEST_FAIL;
01142    }
01143 
01144    /* Test 7, no name, and no brackets. */
01145    if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
01146       ast_test_status_update(test, "Test 7 failed. %s\n", uri);
01147       res = AST_TEST_FAIL;
01148    }
01149 
01150    /* Test 8, no start bracket, but with ending bracket. */
01151    if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
01152       ast_test_status_update(test, "Test 8 failed. %s\n", uri);
01153       res = AST_TEST_FAIL;
01154    }
01155 
01156    return res;
01157 }

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

References ast_free.

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

02274 {
02275    if (!v) {
02276       return;
02277    }
02278 
02279    ast_free(v->via);
02280    ast_free(v);
02281 }

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

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

Referenced by parse_contact_header().

01335 {
01336    char *c;
01337    char *parse = in;
01338    if (out) {
01339       *out = in;
01340    }
01341 
01342    /* Skip any quoted text */
01343    while (*parse) {
01344       if ((c = strchr(parse, '"'))) {
01345          in = (char *)find_closing_quote((const char *)c + 1, NULL);
01346          if (!*in) {
01347             ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
01348             return -1;
01349          } else {
01350             break;
01351          }
01352       } else {
01353          break;
01354       }
01355       parse++;
01356    }
01357    parse = in;
01358 
01359    /* Skip any userinfo components of a uri as they may contain commas */
01360    if ((c = strchr(parse,'@'))) {
01361       parse = c+1;
01362    }
01363    if ((out) && (c = strchr(parse,','))) {
01364       *c++ = '\0';
01365       *out = c;
01366       return 0;
01367    }
01368    return 1;
01369 }

char* get_in_brackets ( char *  tmp  ) 
int get_in_brackets_const ( const char *  src,
const char **  start,
int *  length 
)

Definition at line 951 of file reqresp_parser.c.

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

Referenced by build_route().

00952 {
00953    const char *parse = src;
00954    const char *first_bracket;
00955    const char *second_bracket;
00956 
00957    if (start == NULL) {
00958       return -1;
00959    }
00960    if (length == NULL) {
00961       return -1;
00962    }
00963    *start = NULL;
00964    *length = -1;
00965    if (ast_strlen_zero(src)) {
00966       return 1;
00967    }
00968 
00969    /*
00970     * Skip any quoted text until we find the part in brackets.
00971     * On any error give up and return -1
00972     */
00973    while ( (first_bracket = strchr(parse, '<')) ) {
00974       const char *first_quote = strchr(parse, '"');
00975       first_bracket++;
00976       if (!first_quote || first_quote >= first_bracket) {
00977          break; /* no need to look at quoted part */
00978       }
00979       /* the bracket is within quotes, so ignore it */
00980       parse = find_closing_quote(first_quote + 1, NULL);
00981       if (!*parse) {
00982          ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src);
00983          return  -1;
00984       }
00985       parse++;
00986    }
00987 
00988    /* Require a first bracket.  Unlike get_in_brackets_full, this procedure is passed a const,
00989     * so it can expect a pointer to an original value */
00990    if (!first_bracket) {
00991       ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src);
00992       return 1;
00993    }
00994 
00995    if ((second_bracket = strchr(first_bracket, '>'))) {
00996       *start = first_bracket;
00997       *length = second_bracket - first_bracket;
00998       return 0;
00999    }
01000    ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src);
01001    return -1;
01002 }

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

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

01005 {
01006    const char *parse = tmp;
01007    char *first_bracket;
01008    char *second_bracket;
01009 
01010    if (out) {
01011       *out = "";
01012    }
01013    if (residue) {
01014       *residue = "";
01015    }
01016 
01017    if (ast_strlen_zero(tmp)) {
01018       return 1;
01019    }
01020 
01021    /*
01022     * Skip any quoted text until we find the part in brackets.
01023    * On any error give up and return -1
01024    */
01025    while ( (first_bracket = strchr(parse, '<')) ) {
01026       char *first_quote = strchr(parse, '"');
01027       first_bracket++;
01028       if (!first_quote || first_quote >= first_bracket) {
01029          break; /* no need to look at quoted part */
01030       }
01031       /* the bracket is within quotes, so ignore it */
01032       parse = find_closing_quote(first_quote + 1, NULL);
01033       if (!*parse) {
01034          ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
01035          return  -1;
01036       }
01037       parse++;
01038    }
01039 
01040    /* If no first bracket then still look for a second bracket as some other parsing functions
01041    may overwrite first bracket with NULL when terminating a token based display-name. As this
01042    only affects token based display-names there is no danger of brackets being in quotes */
01043    if (first_bracket) {
01044       parse = first_bracket;
01045    } else {
01046       parse = tmp;
01047    }
01048 
01049    if ((second_bracket = strchr(parse, '>'))) {
01050       *second_bracket++ = '\0';
01051       if (out) {
01052          *out = (char *) parse;
01053       }
01054       if (residue) {
01055          *residue = second_bracket;
01056       }
01057       return 0;
01058    }
01059 
01060    if ((first_bracket)) {
01061       ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
01062       return -1;
01063    }
01064 
01065    if (out) {
01066       *out = tmp;
01067    }
01068 
01069    return 1;
01070 }

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[256];
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 1371 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().

01372 {
01373    int res;
01374    int last;
01375    char *comma;
01376    char *residue;
01377    char *param;
01378    char *value;
01379    struct contact *split_contact = NULL;
01380 
01381    if (*contactheader == '*') {
01382       return 1;
01383    }
01384 
01385    split_contact = ast_calloc(1, sizeof(*split_contact));
01386 
01387    AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
01388    while ((last = get_comma(contactheader, &comma)) != -1) {
01389       res = parse_name_andor_addr(contactheader, "sip:,sips:",
01390          &split_contact->name, &split_contact->user,
01391          &split_contact->pass, &split_contact->hostport,
01392          &split_contact->params, &split_contact->headers,
01393          &residue);
01394       if (res == -1) {
01395          return res;
01396       }
01397 
01398       /* parse contact params */
01399       split_contact->expires = split_contact->q = "";
01400 
01401       while ((value = strchr(residue,'='))) {
01402          *value++ = '\0';
01403 
01404          param = residue;
01405          if ((residue = strchr(value,';'))) {
01406             *residue++ = '\0';
01407          } else {
01408             residue = "";
01409          }
01410 
01411          if (!strcmp(param,"expires")) {
01412             split_contact->expires = value;
01413          } else if (!strcmp(param,"q")) {
01414             split_contact->q = value;
01415          }
01416       }
01417 
01418       if (last) {
01419          return 0;
01420       }
01421       contactheader = comma;
01422 
01423       split_contact = ast_calloc(1, sizeof(*split_contact));
01424       AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
01425    }
01426    return last;
01427 }

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

01164 {
01165    char buf[1024];
01166    char **residue2 = residue;
01167    char *orig_uri = uri;
01168    int ret;
01169 
01170    buf[0] = '\0';
01171    if (name) {
01172       uri = (char *) get_calleridname(uri, buf, sizeof(buf));
01173    }
01174    ret = get_in_brackets_full(uri, &uri, residue);
01175    if (ret == 0) {
01176       /*
01177        * The uri is in brackets so do not treat unknown trailing uri
01178        * parameters as potential message header parameters.
01179        */
01180       if (residue && **residue) {
01181          /* step over the first semicolon as per parse_uri_full residue */
01182          *residue = *residue + 1;
01183       }
01184       residue2 = NULL;
01185    }
01186 
01187    if (name) {
01188       if (buf[0]) {
01189          /*
01190           * There is always room at orig_uri for the display-name because
01191           * at least one character has always been removed.  A '"' or '<'
01192           * has been removed.
01193           */
01194          strcpy(orig_uri, buf);
01195          *name = orig_uri;
01196       } else {
01197          *name = "";
01198       }
01199    }
01200 
01201    return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
01202 }

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

01588 {
01589    char *next, *sep;
01590    char *temp;
01591    int i, found, supported;
01592    unsigned int profile = 0;
01593 
01594    char *out = unsupported;
01595    size_t outlen = unsupported_len;
01596    char *cur_out = out;
01597 
01598    if (out && (outlen > 0)) {
01599       memset(out, 0, outlen);
01600    }
01601 
01602    if (ast_strlen_zero(options) )
01603       return 0;
01604 
01605    temp = ast_strdupa(options);
01606 
01607    ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
01608 
01609    for (next = temp; next; next = sep) {
01610       found = FALSE;
01611       supported = FALSE;
01612       if ((sep = strchr(next, ',')) != NULL) {
01613          *sep++ = '\0';
01614       }
01615 
01616       /* trim leading and trailing whitespace */
01617       next = ast_strip(next);
01618 
01619       if (ast_strlen_zero(next)) {
01620          continue; /* if there is a blank argument in there just skip it */
01621       }
01622 
01623       ast_debug(3, "Found SIP option: -%s-\n", next);
01624       for (i = 0; i < ARRAY_LEN(sip_options); i++) {
01625          if (!strcasecmp(next, sip_options[i].text)) {
01626             profile |= sip_options[i].id;
01627             if (sip_options[i].supported == SUPPORTED) {
01628                supported = TRUE;
01629             }
01630             found = TRUE;
01631             ast_debug(3, "Matched SIP option: %s\n", next);
01632             break;
01633          }
01634       }
01635 
01636       /* If option is not supported, add to unsupported out buffer */
01637       if (!supported && out && outlen) {
01638          size_t copylen = strlen(next);
01639          size_t cur_outlen = strlen(out);
01640          /* Check to see if there is enough room to store this option.
01641           * Copy length is string length plus 2 for the ',' and '\0' */
01642          if ((cur_outlen + copylen + 2) < outlen) {
01643             /* if this isn't the first item, add the ',' */
01644             if (cur_outlen) {
01645                *cur_out = ',';
01646                cur_out++;
01647                cur_outlen++;
01648             }
01649             ast_copy_string(cur_out, next, (outlen - cur_outlen));
01650             cur_out += copylen;
01651          }
01652       }
01653 
01654       if (!found) {
01655          profile |= SIP_OPT_UNKNOWN;
01656          if (!strncasecmp(next, "x-", 2))
01657             ast_debug(3, "Found private SIP option, not supported: %s\n", next);
01658          else
01659             ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
01660       }
01661    }
01662 
01663    return profile;
01664 }

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(), 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  )  [read]

Definition at line 2283 of file reqresp_parser.c.

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

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

02284 {
02285    struct sip_via *v = ast_calloc(1, sizeof(*v));
02286    char *via, *parm;
02287 
02288    if (!v) {
02289       return NULL;
02290    }
02291 
02292    v->via = ast_strdup(header);
02293    v->ttl = 1;
02294 
02295    via = v->via;
02296 
02297    if (ast_strlen_zero(via)) {
02298       ast_log(LOG_ERROR, "received request without a Via header\n");
02299       free_via(v);
02300       return NULL;
02301    }
02302 
02303    /* seperate the first via-parm */
02304    via = strsep(&via, ",");
02305 
02306    /* chop off sent-protocol */
02307    v->protocol = strsep(&via, " \t\r\n");
02308    if (ast_strlen_zero(v->protocol)) {
02309       ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
02310       free_via(v);
02311       return NULL;
02312    }
02313    v->protocol = ast_skip_blanks(v->protocol);
02314 
02315    if (via) {
02316       via = ast_skip_blanks(via);
02317    }
02318 
02319    /* chop off sent-by */
02320    v->sent_by = strsep(&via, "; \t\r\n");
02321    if (ast_strlen_zero(v->sent_by)) {
02322       ast_log(LOG_ERROR, "missing sent-by in Via header\n");
02323       free_via(v);
02324       return NULL;
02325    }
02326    v->sent_by = ast_skip_blanks(v->sent_by);
02327 
02328    /* store the port, we have to handle ipv6 addresses containing ':'
02329     * characters gracefully */
02330    if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) {
02331       char *endptr;
02332 
02333       v->port = strtol(++parm, &endptr, 10);
02334    }
02335 
02336    /* evaluate any via-parms */
02337    while ((parm = strsep(&via, "; \t\r\n"))) {
02338       char *c;
02339       if ((c = strstr(parm, "maddr="))) {
02340          v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
02341       } else if ((c = strstr(parm, "branch="))) {
02342          v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
02343       } else if ((c = strstr(parm, "ttl="))) {
02344          char *endptr;
02345          c = ast_skip_blanks(c + sizeof("ttl=") - 1);
02346          v->ttl = strtol(c, &endptr, 10);
02347 
02348          /* make sure we got a valid ttl value */
02349          if (c == endptr) {
02350             v->ttl = 1;
02351          }
02352       }
02353    }
02354 
02355    return v;
02356 }

void sip_reqresp_parser_exit ( void   ) 

Definition at line 2574 of file reqresp_parser.c.

Referenced by unload_module().

02575 {
02576 #ifdef HAVE_XLOCALE_H
02577    if (c_locale) {
02578       freelocale(c_locale);
02579       c_locale = NULL;
02580    }
02581 #endif
02582 }

int sip_reqresp_parser_init ( void   ) 

Definition at line 2563 of file reqresp_parser.c.

Referenced by load_module().

02564 {
02565 #ifdef HAVE_XLOCALE_H
02566    c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
02567    if (!c_locale) {
02568       return -1;
02569    }
02570 #endif
02571    return 0;
02572 }

void sip_request_parser_register_tests ( void   ) 

Definition at line 2536 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

02537 {
02538    AST_TEST_REGISTER(get_calleridname_test);
02539    AST_TEST_REGISTER(sip_parse_uri_test);
02540    AST_TEST_REGISTER(get_in_brackets_test);
02541    AST_TEST_REGISTER(get_name_and_number_test);
02542    AST_TEST_REGISTER(sip_parse_uri_full_test);
02543    AST_TEST_REGISTER(parse_name_andor_addr_test);
02544    AST_TEST_REGISTER(parse_contact_header_test);
02545    AST_TEST_REGISTER(sip_parse_options_test);
02546    AST_TEST_REGISTER(sip_uri_cmp_test);
02547    AST_TEST_REGISTER(parse_via_test);
02548 }

void sip_request_parser_unregister_tests ( void   ) 

Definition at line 2549 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

02550 {
02551    AST_TEST_UNREGISTER(sip_parse_uri_test);
02552    AST_TEST_UNREGISTER(get_calleridname_test);
02553    AST_TEST_UNREGISTER(get_in_brackets_test);
02554    AST_TEST_UNREGISTER(get_name_and_number_test);
02555    AST_TEST_UNREGISTER(sip_parse_uri_full_test);
02556    AST_TEST_UNREGISTER(parse_name_andor_addr_test);
02557    AST_TEST_UNREGISTER(parse_contact_header_test);
02558    AST_TEST_UNREGISTER(sip_parse_options_test);
02559    AST_TEST_UNREGISTER(sip_uri_cmp_test);
02560    AST_TEST_UNREGISTER(parse_via_test);
02561 }

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

Definition at line 2049 of file reqresp_parser.c.

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

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

02050 {
02051    char *uri1;
02052    char *uri2;
02053    char *uri_scheme1;
02054    char *uri_scheme2;
02055    char *host1;
02056    char *host2;
02057    char *params1;
02058    char *params2;
02059    char *headers1;
02060    char *headers2;
02061 
02062    /* XXX It would be really nice if we could just use parse_uri_full() here
02063     * to separate the components of the URI, but unfortunately it is written
02064     * in a way that can cause URI parameters to be discarded.
02065     */
02066 
02067    if (!input1 || !input2) {
02068       return 1;
02069    }
02070 
02071    uri1 = ast_strdupa(input1);
02072    uri2 = ast_strdupa(input2);
02073 
02074    ast_uri_decode(uri1);
02075    ast_uri_decode(uri2);
02076 
02077    uri_scheme1 = strsep(&uri1, ":");
02078    uri_scheme2 = strsep(&uri2, ":");
02079 
02080    if (strcmp(uri_scheme1, uri_scheme2)) {
02081       return 1;
02082    }
02083 
02084    /* This function is tailored for SIP and SIPS URIs. There's no
02085     * need to check uri_scheme2 since we have determined uri_scheme1
02086     * and uri_scheme2 are equivalent already.
02087     */
02088    if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
02089       return 1;
02090    }
02091 
02092    if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
02093       return 1;
02094    }
02095 
02096    if ((host1 = strchr(uri1, '@'))) {
02097       *host1++ = '\0';
02098    }
02099    if ((host2 = strchr(uri2, '@'))) {
02100       *host2++ = '\0';
02101    }
02102 
02103    /* Check for mismatched username and passwords. This is the
02104     * only case-sensitive comparison of a SIP URI
02105     */
02106    if ((host1 && !host2) ||
02107          (host2 && !host1) ||
02108          (host1 && host2 && strcmp(uri1, uri2))) {
02109       return 1;
02110    }
02111 
02112    if (!host1) {
02113       host1 = uri1;
02114    }
02115    if (!host2) {
02116       host2 = uri2;
02117    }
02118 
02119    /* Strip off the parameters and headers so we can compare
02120     * host and port
02121     */
02122 
02123    if ((params1 = strchr(host1, ';'))) {
02124       *params1++ = '\0';
02125    }
02126    if ((params2 = strchr(host2, ';'))) {
02127       *params2++ = '\0';
02128    }
02129 
02130    /* Headers come after parameters, but there may be headers without
02131     * parameters, thus the S_OR
02132     */
02133    if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
02134       *headers1++ = '\0';
02135    }
02136    if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
02137       *headers2++ = '\0';
02138    }
02139 
02140    if (sip_uri_domain_cmp(host1, host2)) {
02141       return 1;
02142    }
02143 
02144    /* Headers have easier rules to follow, so do those first */
02145    if (sip_uri_headers_cmp(headers1, headers2)) {
02146       return 1;
02147    }
02148 
02149    /* And now the parameters. Ugh */
02150    return sip_uri_params_cmp(params1, params2);
02151 }

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

References ast_sockaddr_cmp(), and ast_sockaddr_parse().

Referenced by sip_uri_cmp().

02012 {
02013    struct ast_sockaddr addr1;
02014    struct ast_sockaddr addr2;
02015    int addr1_parsed;
02016    int addr2_parsed;
02017 
02018    addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
02019    addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
02020 
02021    if (addr1_parsed != addr2_parsed) {
02022       /* One domain was an IP address and the other had
02023        * a host name. FAIL!
02024        */
02025       return 1;
02026    }
02027 
02028    /* Both are host names. A string comparison will work
02029     * perfectly here. Specifying the "C" locale ensures that
02030     * The LC_CTYPE conventions use those defined in ANSI C,
02031     * i.e. ASCII.
02032     */
02033    if (!addr1_parsed) {
02034 #ifdef HAVE_XLOCALE_H
02035       if(!c_locale) {
02036          return strcasecmp(host1, host2);
02037       } else {
02038          return strcasecmp_l(host1, host2, c_locale);
02039       }
02040 #else
02041       return strcasecmp(host1, host2);
02042 #endif
02043    }
02044 
02045    /* Both contain IP addresses */
02046    return ast_sockaddr_cmp(&addr1, &addr2);
02047 }

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

References ast_strdupa, and ast_strlen_zero().

Referenced by sip_uri_cmp().

01947 {
01948    char *headers1 = NULL;
01949    char *headers2 = NULL;
01950    int zerolength1 = 0;
01951    int zerolength2 = 0;
01952    int different = 0;
01953    char *header1;
01954 
01955    if (ast_strlen_zero(input1)) {
01956       zerolength1 = 1;
01957    } else {
01958       headers1 = ast_strdupa(input1);
01959    }
01960 
01961    if (ast_strlen_zero(input2)) {
01962       zerolength2 = 1;
01963    } else {
01964       headers2 = ast_strdupa(input2);
01965    }
01966 
01967    /* If one URI contains no headers and the other
01968     * does, then they cannot possibly match
01969     */
01970    if (zerolength1 != zerolength2) {
01971       return 1;
01972    }
01973 
01974    if (zerolength1 && zerolength2)
01975       return 0;
01976 
01977    /* At this point, we can definitively state that both inputs are
01978     * not zero-length. First, one more optimization. If the length
01979     * of the headers is not equal, then we definitely have no match
01980     */
01981    if (strlen(headers1) != strlen(headers2)) {
01982       return 1;
01983    }
01984 
01985    for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
01986       if (!strcasestr(headers2, header1)) {
01987          different = 1;
01988          break;
01989       }
01990    }
01991 
01992    return different;
01993 }

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

References ast_strdupa, and ast_strlen_zero().

Referenced by sip_uri_cmp().

01821 {
01822    char *params1 = NULL;
01823    char *params2 = NULL;
01824    char *pos1;
01825    char *pos2;
01826    int zerolength1 = 0;
01827    int zerolength2 = 0;
01828    int maddrmatch = 0;
01829    int ttlmatch = 0;
01830    int usermatch = 0;
01831    int methodmatch = 0;
01832 
01833    if (ast_strlen_zero(input1)) {
01834       zerolength1 = 1;
01835    } else {
01836       params1 = ast_strdupa(input1);
01837    }
01838    if (ast_strlen_zero(input2)) {
01839       zerolength2 = 1;
01840    } else {
01841       params2 = ast_strdupa(input2);
01842    }
01843 
01844    /* Quick optimization. If both params are zero-length, then
01845     * they match
01846     */
01847    if (zerolength1 && zerolength2) {
01848       return 0;
01849    }
01850 
01851    for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
01852       char *value1 = pos1;
01853       char *name1 = strsep(&value1, "=");
01854       char *params2dup = NULL;
01855       int matched = 0;
01856       if (!value1) {
01857          value1 = "";
01858       }
01859       /* Checkpoint reached. We have the name and value parsed for param1
01860        * We have to duplicate params2 each time through this loop
01861        * or else the inner loop below will not work properly.
01862        */
01863       if (!zerolength2) {
01864          params2dup = ast_strdupa(params2);
01865       }
01866       for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
01867          char *name2 = pos2;
01868          char *value2 = strchr(pos2, '=');
01869          if (!value2) {
01870             value2 = "";
01871          } else {
01872             *value2++ = '\0';
01873          }
01874          if (!strcasecmp(name1, name2)) {
01875             if (strcasecmp(value1, value2)) {
01876                goto fail;
01877             } else {
01878                matched = 1;
01879                break;
01880             }
01881          }
01882       }
01883       /* Check to see if the parameter is one of the 'must-match' parameters */
01884       if (!strcasecmp(name1, "maddr")) {
01885          if (matched) {
01886             maddrmatch = 1;
01887          } else {
01888             goto fail;
01889          }
01890       } else if (!strcasecmp(name1, "ttl")) {
01891          if (matched) {
01892             ttlmatch = 1;
01893          } else {
01894             goto fail;
01895          }
01896       } else if (!strcasecmp(name1, "user")) {
01897          if (matched) {
01898             usermatch = 1;
01899          } else {
01900             goto fail;
01901          }
01902       } else if (!strcasecmp(name1, "method")) {
01903          if (matched) {
01904             methodmatch = 1;
01905          } else {
01906             goto fail;
01907          }
01908       }
01909    }
01910 
01911    /* We've made it out of that horrible O(m*n) construct and there are no
01912     * failures yet. We're not done yet, though, because params2 could have
01913     * an maddr, ttl, user, or method header and params1 did not.
01914     */
01915    for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
01916       char *value2 = pos2;
01917       char *name2 = strsep(&value2, "=");
01918       if (!value2) {
01919          value2 = "";
01920       }
01921       if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
01922             (!strcasecmp(name2, "ttl") && !ttlmatch) ||
01923             (!strcasecmp(name2, "user") && !usermatch) ||
01924             (!strcasecmp(name2, "method") && !methodmatch)) {
01925          goto fail;
01926       }
01927    }
01928    return 0;
01929 
01930 fail:
01931    return 1;
01932 }


Generated on 29 Oct 2014 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1