Fri Aug 17 00:17:46 2018

Asterisk developer's documentation


reqresp_parser.c File Reference

sip request parsing functions and unit tests More...

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

Go to the source code of this file.

Defines

#define URI_CMP_MATCH   0
#define URI_CMP_NOMATCH   1

Functions

 AST_TEST_DEFINE (parse_via_test)
 AST_TEST_DEFINE (sip_uri_cmp_test)
 AST_TEST_DEFINE (sip_parse_options_test)
 AST_TEST_DEFINE (parse_contact_header_test)
 AST_TEST_DEFINE (parse_name_andor_addr_test)
 AST_TEST_DEFINE (get_in_brackets_test)
 AST_TEST_DEFINE (get_name_and_number_test)
 AST_TEST_DEFINE (get_calleridname_test)
 AST_TEST_DEFINE (sip_parse_uri_test)
 AST_TEST_DEFINE (sip_parse_uri_full_test)
void free_via (struct sip_via *v)
const char * get_calleridname (const char *input, char *output, size_t outputsize)
 Get caller id name from SIP headers, copy into output buffer.
int get_comma (char *in, char **out)
char * get_in_brackets (char *tmp)
int get_in_brackets_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 2149 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

#define URI_CMP_NOMATCH   1

Definition at line 2150 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().


Function Documentation

AST_TEST_DEFINE ( parse_via_test   ) 

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

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

AST_TEST_DEFINE ( sip_uri_cmp_test   ) 

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

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

AST_TEST_DEFINE ( sip_parse_options_test   ) 

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

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

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

References ast_free.

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

02270 {
02271    if (!v) {
02272       return;
02273    }
02274 
02275    ast_free(v->via);
02276    ast_free(v);
02277 }

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

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

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

void sip_reqresp_parser_exit ( void   ) 

Definition at line 2570 of file reqresp_parser.c.

Referenced by unload_module().

02571 {
02572 #ifdef HAVE_XLOCALE_H
02573    if (c_locale) {
02574       freelocale(c_locale);
02575       c_locale = NULL;
02576    }
02577 #endif
02578 }

int sip_reqresp_parser_init ( void   ) 

Definition at line 2559 of file reqresp_parser.c.

Referenced by load_module().

02560 {
02561 #ifdef HAVE_XLOCALE_H
02562    c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
02563    if (!c_locale) {
02564       return -1;
02565    }
02566 #endif
02567    return 0;
02568 }

void sip_request_parser_register_tests ( void   ) 

Definition at line 2532 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

02533 {
02534    AST_TEST_REGISTER(get_calleridname_test);
02535    AST_TEST_REGISTER(sip_parse_uri_test);
02536    AST_TEST_REGISTER(get_in_brackets_test);
02537    AST_TEST_REGISTER(get_name_and_number_test);
02538    AST_TEST_REGISTER(sip_parse_uri_full_test);
02539    AST_TEST_REGISTER(parse_name_andor_addr_test);
02540    AST_TEST_REGISTER(parse_contact_header_test);
02541    AST_TEST_REGISTER(sip_parse_options_test);
02542    AST_TEST_REGISTER(sip_uri_cmp_test);
02543    AST_TEST_REGISTER(parse_via_test);
02544 }

void sip_request_parser_unregister_tests ( void   ) 

Definition at line 2545 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

02546 {
02547    AST_TEST_UNREGISTER(sip_parse_uri_test);
02548    AST_TEST_UNREGISTER(get_calleridname_test);
02549    AST_TEST_UNREGISTER(get_in_brackets_test);
02550    AST_TEST_UNREGISTER(get_name_and_number_test);
02551    AST_TEST_UNREGISTER(sip_parse_uri_full_test);
02552    AST_TEST_UNREGISTER(parse_name_andor_addr_test);
02553    AST_TEST_UNREGISTER(parse_contact_header_test);
02554    AST_TEST_UNREGISTER(sip_parse_options_test);
02555    AST_TEST_UNREGISTER(sip_uri_cmp_test);
02556    AST_TEST_UNREGISTER(parse_via_test);
02557 }

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

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

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

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

References ast_sockaddr_cmp(), and ast_sockaddr_parse().

Referenced by sip_uri_cmp().

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

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

References ast_strdupa, and ast_strlen_zero().

Referenced by sip_uri_cmp().

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

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

References ast_strdupa, and ast_strlen_zero().

Referenced by sip_uri_cmp().

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


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1