Mon Mar 19 11:30:52 2012

Asterisk developer's documentation


reqresp_parser.c File Reference

sip request parsing functions and unit tests More...

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

Go to the source code of this file.

Defines

#define URI_CMP_MATCH   0
#define URI_CMP_NOMATCH   1

Functions

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

Variables

locale_t c_locale


Detailed Description

sip request parsing functions and unit tests

Definition in file reqresp_parser.c.


Define Documentation

#define URI_CMP_MATCH   0

Definition at line 2193 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

#define URI_CMP_NOMATCH   1

Definition at line 2194 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().


Function Documentation

AST_TEST_DEFINE ( parse_via_test   ) 

Definition at line 2398 of file reqresp_parser.c.

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

02399 {
02400    int res = AST_TEST_PASS;
02401    int i = 1;
02402    struct sip_via *via;
02403    struct testdata {
02404       char *in;
02405       char *expected_protocol;
02406       char *expected_branch;
02407       char *expected_sent_by;
02408       char *expected_maddr;
02409       unsigned int expected_port;
02410       unsigned char expected_ttl;
02411       int expected_null;
02412       AST_LIST_ENTRY(testdata) list;
02413    };
02414    struct testdata *testdataptr;
02415    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
02416    struct testdata t1 = {
02417       .in = "SIP/2.0/UDP host:port;branch=thebranch",
02418       .expected_protocol = "SIP/2.0/UDP",
02419       .expected_sent_by = "host:port",
02420       .expected_branch = "thebranch",
02421    };
02422    struct testdata t2 = {
02423       .in = "SIP/2.0/UDP host:port",
02424       .expected_protocol = "SIP/2.0/UDP",
02425       .expected_sent_by = "host:port",
02426       .expected_branch = "",
02427    };
02428    struct testdata t3 = {
02429       .in = "SIP/2.0/UDP",
02430       .expected_null = 1,
02431    };
02432    struct testdata t4 = {
02433       .in = "BLAH/BLAH/BLAH host:port;branch=",
02434       .expected_protocol = "BLAH/BLAH/BLAH",
02435       .expected_sent_by = "host:port",
02436       .expected_branch = "",
02437    };
02438    struct testdata t5 = {
02439       .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
02440       .expected_protocol = "SIP/2.0/UDP",
02441       .expected_sent_by = "host:5060",
02442       .expected_port = 5060,
02443       .expected_branch = "thebranch",
02444       .expected_maddr = "224.0.0.1",
02445       .expected_ttl = 1,
02446    };
02447    struct testdata t6 = {
02448       .in = "SIP/2.0/UDP      host:5060;\n   branch=thebranch;\r\n  maddr=224.0.0.1;   ttl=1",
02449       .expected_protocol = "SIP/2.0/UDP",
02450       .expected_sent_by = "host:5060",
02451       .expected_port = 5060,
02452       .expected_branch = "thebranch",
02453       .expected_maddr = "224.0.0.1",
02454       .expected_ttl = 1,
02455    };
02456    struct testdata t7 = {
02457       .in = "SIP/2.0/UDP [::1]:5060",
02458       .expected_protocol = "SIP/2.0/UDP",
02459       .expected_sent_by = "[::1]:5060",
02460       .expected_port = 5060,
02461       .expected_branch = "",
02462    };
02463    switch (cmd) {
02464    case TEST_INIT:
02465       info->name = "parse_via_test";
02466       info->category = "/channels/chan_sip/";
02467       info->summary = "Tests parsing the Via header";
02468       info->description =
02469             "Runs through various test situations in which various "
02470             " parameters parameter must be extracted from a VIA header";
02471       return AST_TEST_NOT_RUN;
02472    case TEST_EXECUTE:
02473       break;
02474    }
02475 
02476    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
02477    AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
02478    AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
02479    AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
02480    AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
02481    AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
02482    AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
02483 
02484 
02485    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
02486       via = parse_via(testdataptr->in);
02487       if (!via) {
02488               if (!testdataptr->expected_null) {
02489             ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02490                "failed to parse header\n",
02491             i, testdataptr->in);
02492             res = AST_TEST_FAIL;
02493          }
02494          i++;
02495          continue;
02496       }
02497 
02498       if (testdataptr->expected_null) {
02499          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02500             "successfully parased invalid via header\n",
02501          i, testdataptr->in);
02502          res = AST_TEST_FAIL;
02503          free_via(via);
02504          i++;
02505          continue;
02506       }
02507 
02508       if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
02509          || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
02510 
02511          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02512             "parsed protocol = \"%s\"\n"
02513             "expected = \"%s\"\n"
02514             "failed to parse protocol\n",
02515          i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
02516          res = AST_TEST_FAIL;
02517       }
02518 
02519       if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
02520          || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
02521 
02522          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02523             "parsed sent_by = \"%s\"\n"
02524             "expected = \"%s\"\n"
02525             "failed to parse sent-by\n",
02526          i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
02527          res = AST_TEST_FAIL;
02528       }
02529 
02530       if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
02531          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02532             "parsed port = \"%d\"\n"
02533             "expected = \"%d\"\n"
02534             "failed to parse port\n",
02535          i, testdataptr->in, via->port, testdataptr->expected_port);
02536          res = AST_TEST_FAIL;
02537       }
02538 
02539       if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
02540          || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
02541 
02542          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02543             "parsed branch = \"%s\"\n"
02544             "expected = \"%s\"\n"
02545             "failed to parse branch\n",
02546          i, testdataptr->in, via->branch, testdataptr->expected_branch);
02547          res = AST_TEST_FAIL;
02548       }
02549 
02550       if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
02551          || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
02552 
02553          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02554             "parsed maddr = \"%s\"\n"
02555             "expected = \"%s\"\n"
02556             "failed to parse maddr\n",
02557          i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
02558          res = AST_TEST_FAIL;
02559       }
02560 
02561       if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
02562          ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
02563             "parsed ttl = \"%d\"\n"
02564             "expected = \"%d\"\n"
02565             "failed to parse ttl\n",
02566          i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
02567          res = AST_TEST_FAIL;
02568       }
02569 
02570       free_via(via);
02571       i++;
02572    }
02573    return res;
02574 }

AST_TEST_DEFINE ( sip_uri_cmp_test   ) 

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

02197 {
02198    static const struct {
02199       const char *uri1;
02200       const char *uri2;
02201       int expected_result;
02202    } uri_cmp_tests [] = {
02203       /* These are identical, so they match */
02204       { "sip:bob@example.com", "sip:bob@example.com", URI_CMP_MATCH },
02205       /* Different usernames. No match */
02206       { "sip:alice@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
02207       /* Different hosts. No match */
02208       { "sip:bob@example.com", "sip:bob@examplez.com", URI_CMP_NOMATCH },
02209       /* Now start using IP addresses. Identical, so they match */
02210       { "sip:bob@1.2.3.4", "sip:bob@1.2.3.4", URI_CMP_MATCH },
02211       /* Two identical IPv4 addresses represented differently. Match */
02212       { "sip:bob@1.2.3.4", "sip:bob@001.002.003.004", URI_CMP_MATCH },
02213       /* Logically equivalent IPv4 Address and hostname. No Match */
02214       { "sip:bob@127.0.0.1", "sip:bob@localhost", URI_CMP_NOMATCH },
02215       /* Logically equivalent IPv6 address and hostname. No Match */
02216       { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
02217       /* Try an IPv6 one as well */
02218       { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
02219       /* Two identical IPv6 addresses represented differently. Match */
02220       { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
02221       /* Different ports. No match */
02222       { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4:5061", URI_CMP_NOMATCH },
02223       /* Same port logically, but only one address specifies it. No match */
02224       { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4", URI_CMP_NOMATCH },
02225       /* And for safety, try with IPv6 */
02226       { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
02227       /* User comparison is case sensitive. No match */
02228       { "sip:bob@example.com", "sip:BOB@example.com", URI_CMP_NOMATCH },
02229       /* Host comparison is case insensitive. Match */
02230       { "sip:bob@example.com", "sip:bob@EXAMPLE.COM", URI_CMP_MATCH },
02231       /* Add headers to the URI. Identical, so they match */
02232       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value2", URI_CMP_MATCH },
02233       /* Headers in URI 1 are not in URI 2. No Match */
02234       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com", URI_CMP_NOMATCH },
02235       /* Header present in both URIs does not have matching values. No match */
02236       { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value3", URI_CMP_NOMATCH },
02237       /* Add parameters to the URI. Identical so they match */
02238       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
02239       /* Same parameters in both URIs but appear in different order. Match */
02240       { "sip:bob@example.com;param2=value2;param1=value1", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
02241       /* params in URI 1 are not in URI 2. Match */
02242       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com", URI_CMP_MATCH },
02243       /* param present in both URIs does not have matching values. No match */
02244       { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value3", URI_CMP_NOMATCH },
02245       /* URI 1 has a maddr param but URI 2 does not. No match */
02246       { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1", URI_CMP_NOMATCH },
02247       /* URI 1 and URI 2 both have identical maddr params. Match */
02248       { "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 },
02249       /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
02250       { "sips:bob@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
02251       /* No URI schemes. No match */
02252       { "bob@example.com", "bob@example.com", URI_CMP_NOMATCH },
02253       /* Crashiness tests. Just an address scheme. No match */
02254       { "sip", "sips", URI_CMP_NOMATCH },
02255       /* Still just an address scheme. Even though they're the same, No match */
02256       { "sip", "sip", URI_CMP_NOMATCH },
02257       /* Empty strings. No match */
02258       { "", "", URI_CMP_NOMATCH },
02259       /* An empty string and a NULL. No match */
02260       { "", NULL, URI_CMP_NOMATCH },
02261    };
02262    int i;
02263    int test_res = AST_TEST_PASS;
02264    switch (cmd) {
02265    case TEST_INIT:
02266       info->name = "sip_uri_cmp_test";
02267       info->category = "/channels/chan_sip/";
02268       info->summary = "Tests comparison of SIP URIs";
02269       info->description = "Several would-be tricky URI comparisons are performed";
02270       return AST_TEST_NOT_RUN;
02271    case TEST_EXECUTE:
02272       break;
02273    }
02274 
02275    for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
02276       int cmp_res1;
02277       int cmp_res2;
02278       if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
02279          /* URI comparison may return -1 or +1 depending on the failure. Standardize
02280           * the return value to be URI_CMP_NOMATCH on any failure
02281           */
02282          cmp_res1 = URI_CMP_NOMATCH;
02283       }
02284       if (cmp_res1 != uri_cmp_tests[i].expected_result) {
02285          ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
02286                "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
02287                uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
02288                cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
02289          test_res = AST_TEST_FAIL;
02290       }
02291 
02292       /* All URI comparisons are commutative, so for the sake of being thorough, we'll
02293        * rerun the comparison with the parameters reversed
02294        */
02295       if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
02296          /* URI comparison may return -1 or +1 depending on the failure. Standardize
02297           * the return value to be URI_CMP_NOMATCH on any failure
02298           */
02299          cmp_res2 = URI_CMP_NOMATCH;
02300       }
02301       if (cmp_res2 != uri_cmp_tests[i].expected_result) {
02302          ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
02303                "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
02304                uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
02305                cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
02306          test_res = AST_TEST_FAIL;
02307       }
02308    }
02309 
02310    return test_res;
02311 }

AST_TEST_DEFINE ( sip_parse_options_test   ) 

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

01707 {
01708    int res = AST_TEST_PASS;
01709    char unsupported[64];
01710    unsigned int option_profile = 0;
01711    struct testdata {
01712       char *name;
01713       char *input_options;
01714       char *expected_unsupported;
01715       unsigned int expected_profile;
01716       AST_LIST_ENTRY(testdata) list;
01717    };
01718 
01719    struct testdata *testdataptr;
01720    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01721 
01722    struct testdata test1 = {
01723       .name = "test_all_unsupported",
01724       .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
01725       .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
01726       .expected_profile = SIP_OPT_UNKNOWN,
01727    };
01728    struct testdata test2 = {
01729       .name = "test_all_unsupported_one_supported",
01730       .input_options = "  unsupported1, replaces,   unsupported3  , , , ,unsupported4",
01731       .expected_unsupported = "unsupported1,unsupported3,unsupported4",
01732       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
01733    };
01734    struct testdata test3 = {
01735       .name = "test_two_supported_two_unsupported",
01736       .input_options = ",,  timer  ,replaces     ,unsupported3,unsupported4",
01737       .expected_unsupported = "unsupported3,unsupported4",
01738       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
01739    };
01740 
01741    struct testdata test4 = {
01742       .name = "test_all_supported",
01743       .input_options = "timer,replaces",
01744       .expected_unsupported = "",
01745       .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
01746    };
01747 
01748    struct testdata test5 = {
01749       .name = "test_all_supported_redundant",
01750       .input_options = "timer,replaces,timer,replace,timer,replaces",
01751       .expected_unsupported = "",
01752       .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
01753    };
01754    struct testdata test6 = {
01755       .name = "test_buffer_overflow",
01756       .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
01757       "____________________________________,__________________________________________"
01758       "________________________________________________",
01759       .expected_unsupported = "unsupported1,unsupported4",
01760       .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
01761    };
01762    struct testdata test7 = {
01763       .name = "test_null_input",
01764       .input_options = NULL,
01765       .expected_unsupported = "",
01766       .expected_profile = 0,
01767    };
01768    struct testdata test8 = {
01769       .name = "test_whitespace_input",
01770       .input_options = "         ",
01771       .expected_unsupported = "",
01772       .expected_profile = 0,
01773    };
01774    struct testdata test9 = {
01775       .name = "test_whitespace_plus_option_input",
01776       .input_options = " , , ,timer , ,  , ,        ,    ",
01777       .expected_unsupported = "",
01778       .expected_profile = SIP_OPT_TIMER,
01779    };
01780 
01781    switch (cmd) {
01782    case TEST_INIT:
01783       info->name = "sip_parse_options_test";
01784       info->category = "/channels/chan_sip/";
01785       info->summary = "Tests parsing of sip options";
01786       info->description =
01787                      "Tests parsing of SIP options from supported and required "
01788                      "header fields.  Verifies when unsupported options are encountered "
01789                      "that they are appended to the unsupported out buffer and that the "
01790                      "correct bit field representnig the option profile is returned.";
01791       return AST_TEST_NOT_RUN;
01792    case TEST_EXECUTE:
01793       break;
01794    }
01795 
01796    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
01797    AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
01798    AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
01799    AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
01800    AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
01801    AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
01802    AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
01803    AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
01804    AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
01805 
01806    /* Test with unsupported char buffer */
01807    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01808       option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
01809       if (option_profile != testdataptr->expected_profile ||
01810          strcmp(unsupported, testdataptr->expected_unsupported)) {
01811          ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
01812             "%s expected bit profile: %x actual bit profile: %x\n",
01813             testdataptr->name,
01814             testdataptr->expected_unsupported,
01815             unsupported,
01816             testdataptr->expected_profile,
01817             option_profile);
01818          res = AST_TEST_FAIL;
01819       } else {
01820          ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
01821             testdataptr->name,
01822             unsupported,
01823             option_profile);
01824       }
01825 
01826       option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
01827       if (option_profile != testdataptr->expected_profile) {
01828          ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
01829             testdataptr->name,
01830             testdataptr->expected_profile,
01831             option_profile);
01832          res = AST_TEST_FAIL;
01833       } else {
01834          ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
01835             testdataptr->name,
01836             option_profile);
01837       }
01838    }
01839 
01840    return res;
01841 }

AST_TEST_DEFINE ( parse_contact_header_test   ) 

Definition at line 1473 of file reqresp_parser.c.

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

01474 {
01475    int res = AST_TEST_PASS;
01476    char contactheader[1024];
01477    int star;
01478    struct contactliststruct contactlist;
01479    struct contactliststruct *contactlistptr=&contactlist;
01480 
01481    struct testdata {
01482       char *desc;
01483       char *contactheader;
01484       int star;
01485       struct contactliststruct *contactlist;
01486 
01487       AST_LIST_ENTRY(testdata) list;
01488    };
01489 
01490    struct testdata *testdataptr;
01491    struct contact *tdcontactptr;
01492    struct contact *contactptr;
01493 
01494    static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
01495    struct contactliststruct contactlist1, contactlist2;
01496 
01497    struct testdata td1 = {
01498       .desc = "single contact",
01499       .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
01500       .contactlist = &contactlist1,
01501       .star = 0
01502    };
01503    struct contact contact11 = {
01504       .name = "name :@;?&,",
01505       .user = "user",
01506       .pass = "secret",
01507       .hostport = "host:5082",
01508       .params.transport = "tcp",
01509       .params.ttl = "",
01510       .params.lr = 0,
01511       .headers = "",
01512       .expires = "3600",
01513       .q = ""
01514    };
01515 
01516    struct testdata td2 = {
01517       .desc = "multiple contacts",
01518       .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
01519       .contactlist = &contactlist2,
01520       .star = 0,
01521    };
01522    struct contact contact21 = {
01523       .name = "",
01524       .user = ",user1,",
01525       .pass = ",secret1,",
01526       .hostport = "host1",
01527       .params.transport = "",
01528       .params.ttl = "7",
01529       .params.lr = 0,
01530       .headers = "",
01531       .expires = "3600",
01532       .q = "1"
01533    };
01534    struct contact contact22 = {
01535       .name = "",
01536       .user = "",
01537       .pass = "",
01538       .hostport = "host2",
01539       .params.transport = "",
01540       .params.ttl = "",
01541       .params.lr = 0,
01542       .headers = "",
01543       .expires = "",
01544       .q = ""
01545    };
01546 
01547    struct testdata td3 = {
01548       .desc = "star - all contacts",
01549       .contactheader = "*",
01550       .star = 1,
01551       .contactlist = NULL
01552    };
01553 
01554    AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
01555    AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
01556    AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
01557 
01558    AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
01559 
01560    AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
01561    AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
01562 
01563 
01564    switch (cmd) {
01565    case TEST_INIT:
01566       info->name = "parse_contact_header_test";
01567       info->category = "/channels/chan_sip/";
01568       info->summary = "tests parsing of sip contact header";
01569       info->description =
01570          "Tests parsing of a contact header including those with multiple contacts "
01571          "Verifies output matches expected behavior.";
01572       return AST_TEST_NOT_RUN;
01573    case TEST_EXECUTE:
01574       break;
01575    }
01576 
01577    AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
01578       ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
01579       star = parse_contact_header(contactheader,contactlistptr);
01580       if (testdataptr->star) {
01581          /* expecting star rather than list of contacts */
01582          if (!star) {
01583             ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01584             res = AST_TEST_FAIL;
01585             break;
01586          }
01587       } else {
01588          contactptr = AST_LIST_FIRST(contactlistptr);
01589          AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
01590             if (!contactptr ||
01591                strcmp(tdcontactptr->name, contactptr->name) ||
01592                strcmp(tdcontactptr->user, contactptr->user) ||
01593                strcmp(tdcontactptr->pass, contactptr->pass) ||
01594                strcmp(tdcontactptr->hostport, contactptr->hostport) ||
01595                strcmp(tdcontactptr->headers, contactptr->headers) ||
01596                strcmp(tdcontactptr->expires, contactptr->expires) ||
01597                strcmp(tdcontactptr->q, contactptr->q) ||
01598                strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
01599                strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
01600                (tdcontactptr->params.lr != contactptr->params.lr)
01601                ) {
01602                ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
01603                res = AST_TEST_FAIL;
01604                break;
01605             }
01606 
01607             contactptr = AST_LIST_NEXT(contactptr,list);
01608          }
01609       }
01610    }
01611 
01612    return res;
01613 }

AST_TEST_DEFINE ( parse_name_andor_addr_test   ) 

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

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

AST_TEST_DEFINE ( get_in_brackets_test   ) 

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

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

AST_TEST_DEFINE ( get_name_and_number_test   ) 

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

00909 {
00910    int res = AST_TEST_PASS;
00911    char *name = NULL;
00912    char *number = NULL;
00913    const char *in1 = "NAME <sip:NUMBER@place>";
00914    const char *in2 = "\"NA><ME\" <sip:NUMBER@place>";
00915    const char *in3 = "NAME";
00916    const char *in4 = "<sip:NUMBER@place>";
00917    const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
00918 
00919    switch (cmd) {
00920    case TEST_INIT:
00921       info->name = "sip_get_name_and_number_test";
00922       info->category = "/channels/chan_sip/";
00923       info->summary = "Tests getting name and number from sip header";
00924       info->description =
00925             "Runs through various test situations in which a name and "
00926             "and number can be retrieved from a sip header.";
00927       return AST_TEST_NOT_RUN;
00928    case TEST_EXECUTE:
00929       break;
00930    }
00931 
00932    /* Test 1. get name and number */
00933    number = name = NULL;
00934    if ((get_name_and_number(in1, &name, &number)) ||
00935       strcmp(name, "NAME") ||
00936       strcmp(number, "NUMBER")) {
00937 
00938       ast_test_status_update(test, "Test 1, simple get name and number failed.\n");
00939       res = AST_TEST_FAIL;
00940    }
00941    ast_free(name);
00942    ast_free(number);
00943 
00944    /* Test 2. get quoted name and number */
00945    number = name = NULL;
00946    if ((get_name_and_number(in2, &name, &number)) ||
00947       strcmp(name, "NA><ME") ||
00948       strcmp(number, "NUMBER")) {
00949 
00950       ast_test_status_update(test, "Test 2, get quoted name and number failed.\n");
00951       res = AST_TEST_FAIL;
00952    }
00953    ast_free(name);
00954    ast_free(number);
00955 
00956    /* Test 3. name only */
00957    number = name = NULL;
00958    if (!(get_name_and_number(in3, &name, &number))) {
00959 
00960       ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n");
00961       res = AST_TEST_FAIL;
00962    }
00963    ast_free(name);
00964    ast_free(number);
00965 
00966    /* Test 4. number only */
00967    number = name = NULL;
00968    if ((get_name_and_number(in4, &name, &number)) ||
00969       !ast_strlen_zero(name) ||
00970       strcmp(number, "NUMBER")) {
00971 
00972       ast_test_status_update(test, "Test 4, get number with no name present failed.\n");
00973       res = AST_TEST_FAIL;
00974    }
00975    ast_free(name);
00976    ast_free(number);
00977 
00978    /* Test 5. malformed string, since number can not be parsed, this should return an error.  */
00979    number = name = NULL;
00980    if (!(get_name_and_number(in5, &name, &number)) ||
00981       !ast_strlen_zero(name) ||
00982       !ast_strlen_zero(number)) {
00983 
00984       ast_test_status_update(test, "Test 5, processing malformed string failed.\n");
00985       res = AST_TEST_FAIL;
00986    }
00987    ast_free(name);
00988    ast_free(number);
00989 
00990    /* Test 6. NULL output parameters */
00991    number = name = NULL;
00992    if (!(get_name_and_number(in5, NULL, NULL))) {
00993 
00994       ast_test_status_update(test, "Test 6, NULL output parameters failed.\n");
00995       res = AST_TEST_FAIL;
00996    }
00997 
00998    /* Test 7. NULL input parameter */
00999    number = name = NULL;
01000    if (!(get_name_and_number(NULL, &name, &number)) ||
01001       !ast_strlen_zero(name) ||
01002       !ast_strlen_zero(number)) {
01003 
01004       ast_test_status_update(test, "Test 7, NULL input parameter failed.\n");
01005       res = AST_TEST_FAIL;
01006    }
01007    ast_free(name);
01008    ast_free(number);
01009 
01010    return res;
01011 }

AST_TEST_DEFINE ( get_calleridname_test   ) 

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

00786 {
00787    int res = AST_TEST_PASS;
00788    const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
00789    const char *in2 = " token text with no quotes <stuff>";
00790    const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
00791    const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
00792    const char *noendquote = " \"quoted-text no end <stuff>";
00793    const char *addrspec = " sip:blah@blah";
00794    const char *no_quotes_no_brackets = "blah@blah";
00795    const char *after_dname;
00796    char dname[40];
00797 
00798    switch (cmd) {
00799    case TEST_INIT:
00800       info->name = "sip_get_calleridname_test";
00801       info->category = "/channels/chan_sip/";
00802       info->summary = "decodes callerid name from sip header";
00803       info->description = "Decodes display-name field of sip header.  Checks for valid output and expected failure cases.";
00804       return AST_TEST_NOT_RUN;
00805    case TEST_EXECUTE:
00806       break;
00807    }
00808 
00809    /* quoted-text with backslash escaped quote */
00810    after_dname = get_calleridname(in1, dname, sizeof(dname));
00811    ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname);
00812    if (strcmp(dname, " quoted-text internal \" quote ")) {
00813       ast_test_status_update(test, "display-name1 test failed\n");
00814       res = AST_TEST_FAIL;
00815    }
00816 
00817    /* token text */
00818    after_dname = get_calleridname(in2, dname, sizeof(dname));
00819    ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname);
00820    if (strcmp(dname, "token text with no quotes")) {
00821       ast_test_status_update(test, "display-name2 test failed\n");
00822       res = AST_TEST_FAIL;
00823    }
00824 
00825    /* quoted-text buffer overflow */
00826    after_dname = get_calleridname(overflow1, dname, sizeof(dname));
00827    ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
00828    if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
00829       ast_test_status_update(test, "overflow display-name1 test failed\n");
00830       res = AST_TEST_FAIL;
00831    }
00832 
00833    /* non-quoted-text buffer overflow */
00834    after_dname = get_calleridname(overflow2, dname, sizeof(dname));
00835    ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
00836    if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
00837       ast_test_status_update(test, "overflow display-name2 test failed\n");
00838       res = AST_TEST_FAIL;
00839    }
00840 
00841    /* quoted-text buffer with no terminating end quote */
00842    after_dname = get_calleridname(noendquote, dname, sizeof(dname));
00843    ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
00844    if (*dname != '\0' && after_dname != noendquote) {
00845       ast_test_status_update(test, "no end quote for quoted-text display-name failed\n");
00846       res = AST_TEST_FAIL;
00847    }
00848 
00849    /* addr-spec rather than display-name. */
00850    after_dname = get_calleridname(addrspec, dname, sizeof(dname));
00851    ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
00852    if (*dname != '\0' && after_dname != addrspec) {
00853       ast_test_status_update(test, "detection of addr-spec failed\n");
00854       res = AST_TEST_FAIL;
00855    }
00856 
00857    /* no quotes, no brackets */
00858    after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname));
00859    ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname);
00860    if (*dname != '\0' && after_dname != no_quotes_no_brackets) {
00861       ast_test_status_update(test, "detection of addr-spec failed\n");
00862       res = AST_TEST_FAIL;
00863    }
00864 
00865    return res;
00866 }

AST_TEST_DEFINE ( sip_parse_uri_test   ) 

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

00511 {
00512    int res = AST_TEST_PASS;
00513    char *name, *pass, *hostport, *transport;
00514    char uri1[] = "sip:name@host";
00515    char uri2[] = "sip:name@host;transport=tcp";
00516    char uri3[] = "sip:name:secret@host;transport=tcp";
00517    char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00518    /* test 5 is for NULL input */
00519    char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00520    char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00521    char uri8[] = "sip:host";
00522    char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00523    char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
00524    char uri11[] = "host";
00525 
00526    switch (cmd) {
00527    case TEST_INIT:
00528       info->name = "sip_uri_parse_test";
00529       info->category = "/channels/chan_sip/";
00530       info->summary = "tests sip uri parsing";
00531       info->description =
00532                      "Tests parsing of various URIs "
00533                      "Verifies output matches expected behavior.";
00534       return AST_TEST_NOT_RUN;
00535    case TEST_EXECUTE:
00536       break;
00537    }
00538 
00539    /* Test 1, simple URI */
00540    name = pass = hostport = transport = NULL;
00541    if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00542          strcmp(name, "name")        ||
00543          !ast_strlen_zero(pass)      ||
00544          strcmp(hostport, "host")      ||
00545          !ast_strlen_zero(transport)) {
00546       ast_test_status_update(test, "Test 1: simple uri failed. \n");
00547       res = AST_TEST_FAIL;
00548    }
00549 
00550    /* Test 2, add tcp transport */
00551    name = pass = hostport = transport = NULL;
00552    if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00553          strcmp(name, "name")        ||
00554          !ast_strlen_zero(pass)      ||
00555          strcmp(hostport, "host")    ||
00556          strcmp(transport, "tcp")) {
00557       ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n");
00558       res = AST_TEST_FAIL;
00559    }
00560 
00561    /* Test 3, add secret */
00562    name = pass = hostport = transport = NULL;
00563    if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00564          strcmp(name, "name")        ||
00565          strcmp(pass, "secret")      ||
00566          strcmp(hostport, "host")    ||
00567          strcmp(transport, "tcp")) {
00568       ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n");
00569       res = AST_TEST_FAIL;
00570    }
00571 
00572    /* Test 4, add port and unparsed header field*/
00573    name = pass = hostport = transport = NULL;
00574    if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00575          strcmp(name, "name")        ||
00576          strcmp(pass, "secret")      ||
00577          strcmp(hostport, "host:port") ||
00578          strcmp(transport, "tcp")) {
00579       ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n");
00580       res = AST_TEST_FAIL;
00581    }
00582 
00583    /* Test 5, verify parse_uri does not crash when given a NULL uri */
00584    name = pass = hostport = transport = NULL;
00585    if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) {
00586       ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n");
00587       res = AST_TEST_FAIL;
00588    }
00589 
00590    /* Test 6, verify parse_uri does not crash when given a NULL output parameters */
00591    name = pass = hostport = transport = NULL;
00592    if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) {
00593       ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n");
00594       res = AST_TEST_FAIL;
00595    }
00596 
00597    /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */
00598    name = pass = hostport = transport = NULL;
00599    if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) ||
00600          strcmp(name, "name:secret")        ||
00601          strcmp(hostport, "host:port")) {
00602 
00603       ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n");
00604       res = AST_TEST_FAIL;
00605    }
00606 
00607    /* Test 8, verify parse_uri can handle a hostport only uri */
00608    name = pass = hostport = transport = NULL;
00609    if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00610          strcmp(hostport, "host") ||
00611          !ast_strlen_zero(name)) {
00612       ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n");
00613       res = AST_TEST_FAIL;
00614    }
00615 
00616    /* Test 9, add port and unparsed header field with hostport only uri*/
00617    name = pass = hostport = transport = NULL;
00618    if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00619          !ast_strlen_zero(name)        ||
00620          !ast_strlen_zero(pass)      ||
00621          strcmp(hostport, "host:port")    ||
00622          strcmp(transport, "tcp")) {
00623       ast_test_status_update(test, "Test 9: hostport only uri failed \n");
00624       res = AST_TEST_FAIL;
00625    }
00626 
00627    /* Test 10, handle invalid/missing "sip:,sips:" scheme
00628     * we expect parse_uri to return an error, but still parse
00629     * the results correctly here */
00630    name = pass = hostport = transport = NULL;
00631    if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00632          !ast_strlen_zero(name)        ||
00633          !ast_strlen_zero(pass)      ||
00634          strcmp(hostport, "host:port")    ||
00635          strcmp(transport, "tcp")) {
00636       ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n");
00637       res = AST_TEST_FAIL;
00638    }
00639 
00640    /* Test 11, simple hostport only URI with missing scheme
00641     * we expect parse_uri to return an error, but still parse
00642     * the results correctly here */
00643    name = pass = hostport = transport = NULL;
00644    if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) ||
00645          !ast_strlen_zero(name)      ||
00646          !ast_strlen_zero(pass)      ||
00647          strcmp(hostport, "host")      ||
00648          !ast_strlen_zero(transport)) {
00649       ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n");
00650       res = AST_TEST_FAIL;
00651    }
00652 
00653    return res;
00654 }

AST_TEST_DEFINE ( sip_parse_uri_fully_test   ) 

Definition at line 220 of file reqresp_parser.c.

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

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

void free_via ( struct sip_via *  v  ) 

Definition at line 2313 of file reqresp_parser.c.

References ast_free.

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

02314 {
02315    if (!v) {
02316       return;
02317    }
02318 
02319    ast_free(v->via);
02320    ast_free(v);
02321 }

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

00661 {
00662    /* From RFC3261:
00663     *
00664     * From           =  ( "From" / "f" ) HCOLON from-spec
00665     * from-spec      =  ( name-addr / addr-spec ) *( SEMI from-param )
00666     * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
00667     * display-name   =  *(token LWS)/ quoted-string
00668     * token          =  1*(alphanum / "-" / "." / "!" / "%" / "*"
00669     *                     / "_" / "+" / "`" / "'" / "~" )
00670     * quoted-string  =  SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
00671     * qdtext         =  LWS / %x21 / %x23-5B / %x5D-7E
00672     *                     / UTF8-NONASCII
00673     * quoted-pair    =  "\" (%x00-09 / %x0B-0C / %x0E-7F)
00674     *
00675     * HCOLON         = *WSP ":" SWS
00676     * SWS            = [LWS]
00677     * LWS            = *[*WSP CRLF] 1*WSP
00678     * WSP            = (SP / HTAB)
00679     *
00680     * Deviations from it:
00681     * - following CRLF's in LWS is not done (here at least)
00682     * - ascii NUL is never legal as it terminates the C-string
00683     * - utf8-nonascii is not checked for validity
00684     */
00685    char *orig_output = output;
00686    const char *orig_input = input;
00687 
00688    if (!output || !outputsize) {
00689       /* Bad output parameters.  Should never happen. */
00690       return input;
00691    }
00692 
00693    /* clear any empty characters in the beginning */
00694    input = ast_skip_blanks(input);
00695 
00696    /* make sure the output buffer is initilized */
00697    *orig_output = '\0';
00698 
00699    /* make room for '\0' at the end of the output buffer */
00700    --outputsize;
00701 
00702    /* no data at all or no display name? */
00703    if (!input || *input == '<') {
00704       return input;
00705    }
00706 
00707    /* quoted-string rules */
00708    if (input[0] == '"') {
00709       input++; /* skip the first " */
00710 
00711       for (; *input; ++input) {
00712          if (*input == '"') {  /* end of quoted-string */
00713             break;
00714          } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
00715             ++input;
00716             if (!*input) {
00717                break;
00718             }
00719             if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
00720                continue;  /* not a valid quoted-pair, so skip it */
00721             }
00722          } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
00723             || *input == 0x7f) {
00724             continue; /* skip this invalid character. */
00725          }
00726 
00727          if (0 < outputsize) {
00728             /* We still have room for the output display-name. */
00729             *output++ = *input;
00730             --outputsize;
00731          }
00732       }
00733 
00734       /* if this is successful, input should be at the ending quote */
00735       if (*input != '"') {
00736          ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
00737          *orig_output = '\0';
00738          return orig_input;
00739       }
00740 
00741       /* make sure input is past the last quote */
00742       ++input;
00743 
00744       /* terminate output */
00745       *output = '\0';
00746    } else {  /* either an addr-spec or tokenLWS-combo */
00747       for (; *input; ++input) {
00748          /* token or WSP (without LWS) */
00749          if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
00750             || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
00751             || *input == '!' || *input == '%' || *input == '*' || *input == '_'
00752             || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
00753             || *input == 0x9 || *input == ' ') {
00754             if (0 < outputsize) {
00755                /* We still have room for the output display-name. */
00756                *output++ = *input;
00757                --outputsize;
00758             }
00759          } else if (*input == '<') {   /* end of tokenLWS-combo */
00760             /* we could assert that the previous char is LWS, but we don't care */
00761             break;
00762          } else if (*input == ':') {
00763             /* This invalid character which indicates this is addr-spec rather than display-name. */
00764             *orig_output = '\0';
00765             return orig_input;
00766          } else {         /* else, invalid character we can skip. */
00767             continue;    /* skip this character */
00768          }
00769       }
00770 
00771       if (*input != '<') {   /* if we never found the start of addr-spec then this is invalid */
00772          *orig_output = '\0';
00773          return orig_input;
00774       }
00775 
00776       /* terminate output while trimming any trailing whitespace */
00777       do {
00778          *output-- = '\0';
00779       } while (orig_output <= output && (*output == 0x9 || *output == ' '));
00780    }
00781 
00782    return input;
00783 }

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

Definition at line 1378 of file reqresp_parser.c.

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

Referenced by parse_contact_header().

01379 {
01380    char *c;
01381    char *parse = in;
01382    if (out) {
01383       *out = in;
01384    }
01385 
01386    /* Skip any quoted text */
01387    while (*parse) {
01388       if ((c = strchr(parse, '"'))) {
01389          in = (char *)find_closing_quote((const char *)c + 1, NULL);
01390          if (!*in) {
01391             ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
01392             return -1;
01393          } else {
01394             break;
01395          }
01396       } else {
01397          break;
01398       }
01399       parse++;
01400    }
01401    parse = in;
01402 
01403    /* Skip any userinfo components of a uri as they may contain commas */
01404    if ((c = strchr(parse,'@'))) {
01405       parse = c+1;
01406    }
01407    if ((out) && (c = strchr(parse,','))) {
01408       *c++ = '\0';
01409       *out = c;
01410       return 0;
01411    }
01412    return 1;
01413 }

char* get_in_brackets ( char *  tmp  ) 

Definition at line 1081 of file reqresp_parser.c.

References get_in_brackets_full().

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

01082 {
01083    char *out;
01084 
01085    if ((get_in_brackets_full(tmp, &out, NULL))) {
01086       return tmp;
01087    }
01088    return out;
01089 }

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

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

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

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

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

00869 {
00870    char header[256];
00871    char tmp_name[50];
00872    char *tmp_number = NULL;
00873    char *hostport = NULL;
00874    char *dummy = NULL;
00875 
00876    if (!name || !number || ast_strlen_zero(hdr)) {
00877       return -1;
00878    }
00879 
00880    *number = NULL;
00881    *name = NULL;
00882    ast_copy_string(header, hdr, sizeof(header));
00883 
00884    /* strip the display-name portion off the beginning of the header. */
00885    get_calleridname(header, tmp_name, sizeof(tmp_name));
00886 
00887    /* get uri within < > brackets */
00888    tmp_number = get_in_brackets(header);
00889 
00890    /* parse out the number here */
00891    if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
00892       ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
00893       return -1;
00894    }
00895 
00896    /* number is not option, and must be present at this point */
00897    *number = ast_strdup(tmp_number);
00898    ast_uri_decode(*number);
00899 
00900    /* name is optional and may not be present at this point */
00901    if (!ast_strlen_zero(tmp_name)) {
00902       *name = ast_strdup(tmp_name);
00903    }
00904 
00905    return 0;
00906 }

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

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

01416 {
01417    int res;
01418    int last;
01419    char *comma;
01420    char *residue;
01421    char *param;
01422    char *value;
01423    struct contact *split_contact = NULL;
01424 
01425    if (*contactheader == '*') {
01426       return 1;
01427    }
01428 
01429    split_contact = ast_calloc(1, sizeof(*split_contact));
01430 
01431    AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
01432    while ((last = get_comma(contactheader, &comma)) != -1) {
01433       res = parse_name_andor_addr(contactheader, "sip:,sips:",
01434          &split_contact->name, &split_contact->user,
01435          &split_contact->pass, &split_contact->hostport,
01436          &split_contact->params, &split_contact->headers,
01437          &residue);
01438       if (res == -1) {
01439          return res;
01440       }
01441 
01442       /* parse contact params */
01443       split_contact->expires = split_contact->q = "";
01444 
01445       while ((value = strchr(residue,'='))) {
01446          *value++ = '\0';
01447 
01448          param = residue;
01449          if ((residue = strchr(value,';'))) {
01450             *residue++ = '\0';
01451          } else {
01452             residue = "";
01453          }
01454 
01455          if (!strcmp(param,"expires")) {
01456             split_contact->expires = value;
01457          } else if (!strcmp(param,"q")) {
01458             split_contact->q = value;
01459          }
01460       }
01461 
01462       if (last) {
01463          return 0;
01464       }
01465       contactheader = comma;
01466 
01467       split_contact = ast_calloc(1, sizeof(*split_contact));
01468       AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
01469    }
01470    return last;
01471 }

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

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

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

01628 {
01629    char *next, *sep;
01630    char *temp;
01631    int i, found, supported;
01632    unsigned int profile = 0;
01633 
01634    char *out = unsupported;
01635    size_t outlen = unsupported_len;
01636    char *cur_out = out;
01637 
01638    if (out && (outlen > 0)) {
01639       memset(out, 0, outlen);
01640    }
01641 
01642    if (ast_strlen_zero(options) )
01643       return 0;
01644 
01645    temp = ast_strdupa(options);
01646 
01647    ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
01648 
01649    for (next = temp; next; next = sep) {
01650       found = FALSE;
01651       supported = FALSE;
01652       if ((sep = strchr(next, ',')) != NULL) {
01653          *sep++ = '\0';
01654       }
01655 
01656       /* trim leading and trailing whitespace */
01657       next = ast_strip(next);
01658 
01659       if (ast_strlen_zero(next)) {
01660          continue; /* if there is a blank argument in there just skip it */
01661       }
01662 
01663       ast_debug(3, "Found SIP option: -%s-\n", next);
01664       for (i = 0; i < ARRAY_LEN(sip_options); i++) {
01665          if (!strcasecmp(next, sip_options[i].text)) {
01666             profile |= sip_options[i].id;
01667             if (sip_options[i].supported == SUPPORTED) {
01668                supported = TRUE;
01669             }
01670             found = TRUE;
01671             ast_debug(3, "Matched SIP option: %s\n", next);
01672             break;
01673          }
01674       }
01675 
01676       /* If option is not supported, add to unsupported out buffer */
01677       if (!supported && out && outlen) {
01678          size_t copylen = strlen(next);
01679          size_t cur_outlen = strlen(out);
01680          /* Check to see if there is enough room to store this option.
01681           * Copy length is string length plus 2 for the ',' and '\0' */
01682          if ((cur_outlen + copylen + 2) < outlen) {
01683             /* if this isn't the first item, add the ',' */
01684             if (cur_outlen) {
01685                *cur_out = ',';
01686                cur_out++;
01687                cur_outlen++;
01688             }
01689             ast_copy_string(cur_out, next, (outlen - cur_outlen));
01690             cur_out += copylen;
01691          }
01692       }
01693 
01694       if (!found) {
01695          profile |= SIP_OPT_UNKNOWN;
01696          if (!strncasecmp(next, "x-", 2))
01697             ast_debug(3, "Found private SIP option, not supported: %s\n", next);
01698          else
01699             ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
01700       }
01701    }
01702 
01703    return profile;
01704 }

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

Definition at line 496 of file reqresp_parser.c.

References parse_uri_full().

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

00497                                             {
00498    int ret;
00499    char *headers;
00500    struct uriparams params;
00501 
00502    headers = NULL;
00503    ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
00504    if (transport) {
00505       *transport=params.transport;
00506    }
00507    return ret;
00508 }

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

* parses a URI in its components.

Definition at line 35 of file reqresp_parser.c.

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

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

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

struct sip_via* parse_via ( const char *  header  ) 

Definition at line 2323 of file reqresp_parser.c.

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

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

02324 {
02325    struct sip_via *v = ast_calloc(1, sizeof(*v));
02326    char *via, *parm;
02327 
02328    if (!v) {
02329       return NULL;
02330    }
02331 
02332    v->via = ast_strdup(header);
02333    v->ttl = 1;
02334 
02335    via = v->via;
02336 
02337    if (ast_strlen_zero(via)) {
02338       ast_log(LOG_ERROR, "received request without a Via header\n");
02339       free_via(v);
02340       return NULL;
02341    }
02342 
02343    /* seperate the first via-parm */
02344    via = strsep(&via, ",");
02345 
02346    /* chop off sent-protocol */
02347    v->protocol = strsep(&via, " \t\r\n");
02348    if (ast_strlen_zero(v->protocol)) {
02349       ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
02350       free_via(v);
02351       return NULL;
02352    }
02353    v->protocol = ast_skip_blanks(v->protocol);
02354 
02355    if (via) {
02356       via = ast_skip_blanks(via);
02357    }
02358 
02359    /* chop off sent-by */
02360    v->sent_by = strsep(&via, "; \t\r\n");
02361    if (ast_strlen_zero(v->sent_by)) {
02362       ast_log(LOG_ERROR, "missing sent-by in Via header\n");
02363       free_via(v);
02364       return NULL;
02365    }
02366    v->sent_by = ast_skip_blanks(v->sent_by);
02367 
02368    /* store the port, we have to handle ipv6 addresses containing ':'
02369     * characters gracefully */
02370    if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) {
02371       char *endptr;
02372 
02373       v->port = strtol(++parm, &endptr, 10);
02374    }
02375 
02376    /* evaluate any via-parms */
02377    while ((parm = strsep(&via, "; \t\r\n"))) {
02378       char *c;
02379       if ((c = strstr(parm, "maddr="))) {
02380          v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
02381       } else if ((c = strstr(parm, "branch="))) {
02382          v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
02383       } else if ((c = strstr(parm, "ttl="))) {
02384          char *endptr;
02385          c = ast_skip_blanks(c + sizeof("ttl=") - 1);
02386          v->ttl = strtol(c, &endptr, 10);
02387 
02388          /* make sure we got a valid ttl value */
02389          if (c == endptr) {
02390             v->ttl = 1;
02391          }
02392       }
02393    }
02394 
02395    return v;
02396 }

void sip_reqresp_parser_exit ( void   ) 

Definition at line 2614 of file reqresp_parser.c.

02615 {
02616 #ifdef HAVE_XLOCALE_H
02617    if (c_locale) {
02618       freelocale(c_locale);
02619       c_locale = NULL;
02620    }
02621 #endif
02622 }

int sip_reqresp_parser_init ( void   ) 

Definition at line 2603 of file reqresp_parser.c.

Referenced by load_module().

02604 {
02605 #ifdef HAVE_XLOCALE_H
02606    c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
02607    if (!c_locale) {
02608       return -1;
02609    }
02610 #endif
02611    return 0;
02612 }

void sip_request_parser_register_tests ( void   ) 

Definition at line 2576 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

02577 {
02578    AST_TEST_REGISTER(get_calleridname_test);
02579    AST_TEST_REGISTER(sip_parse_uri_test);
02580    AST_TEST_REGISTER(get_in_brackets_test);
02581    AST_TEST_REGISTER(get_name_and_number_test);
02582    AST_TEST_REGISTER(sip_parse_uri_fully_test);
02583    AST_TEST_REGISTER(parse_name_andor_addr_test);
02584    AST_TEST_REGISTER(parse_contact_header_test);
02585    AST_TEST_REGISTER(sip_parse_options_test);
02586    AST_TEST_REGISTER(sip_uri_cmp_test);
02587    AST_TEST_REGISTER(parse_via_test);
02588 }

void sip_request_parser_unregister_tests ( void   ) 

Definition at line 2589 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

02590 {
02591    AST_TEST_UNREGISTER(sip_parse_uri_test);
02592    AST_TEST_UNREGISTER(get_calleridname_test);
02593    AST_TEST_UNREGISTER(get_in_brackets_test);
02594    AST_TEST_UNREGISTER(get_name_and_number_test);
02595    AST_TEST_UNREGISTER(sip_parse_uri_fully_test);
02596    AST_TEST_UNREGISTER(parse_name_andor_addr_test);
02597    AST_TEST_UNREGISTER(parse_contact_header_test);
02598    AST_TEST_UNREGISTER(sip_parse_options_test);
02599    AST_TEST_UNREGISTER(sip_uri_cmp_test);
02600    AST_TEST_UNREGISTER(parse_via_test);
02601 }

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

Definition at line 2089 of file reqresp_parser.c.

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

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

02090 {
02091    char *uri1;
02092    char *uri2;
02093    char *uri_scheme1;
02094    char *uri_scheme2;
02095    char *host1;
02096    char *host2;
02097    char *params1;
02098    char *params2;
02099    char *headers1;
02100    char *headers2;
02101 
02102    /* XXX It would be really nice if we could just use parse_uri_full() here
02103     * to separate the components of the URI, but unfortunately it is written
02104     * in a way that can cause URI parameters to be discarded.
02105     */
02106 
02107    if (!input1 || !input2) {
02108       return 1;
02109    }
02110 
02111    uri1 = ast_strdupa(input1);
02112    uri2 = ast_strdupa(input2);
02113 
02114    ast_uri_decode(uri1);
02115    ast_uri_decode(uri2);
02116 
02117    uri_scheme1 = strsep(&uri1, ":");
02118    uri_scheme2 = strsep(&uri2, ":");
02119 
02120    if (strcmp(uri_scheme1, uri_scheme2)) {
02121       return 1;
02122    }
02123 
02124    /* This function is tailored for SIP and SIPS URIs. There's no
02125     * need to check uri_scheme2 since we have determined uri_scheme1
02126     * and uri_scheme2 are equivalent already.
02127     */
02128    if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
02129       return 1;
02130    }
02131 
02132    if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
02133       return 1;
02134    }
02135 
02136    if ((host1 = strchr(uri1, '@'))) {
02137       *host1++ = '\0';
02138    }
02139    if ((host2 = strchr(uri2, '@'))) {
02140       *host2++ = '\0';
02141    }
02142 
02143    /* Check for mismatched username and passwords. This is the
02144     * only case-sensitive comparison of a SIP URI
02145     */
02146    if ((host1 && !host2) ||
02147          (host2 && !host1) ||
02148          (host1 && host2 && strcmp(uri1, uri2))) {
02149       return 1;
02150    }
02151 
02152    if (!host1) {
02153       host1 = uri1;
02154    }
02155    if (!host2) {
02156       host2 = uri2;
02157    }
02158 
02159    /* Strip off the parameters and headers so we can compare
02160     * host and port
02161     */
02162 
02163    if ((params1 = strchr(host1, ';'))) {
02164       *params1++ = '\0';
02165    }
02166    if ((params2 = strchr(host2, ';'))) {
02167       *params2++ = '\0';
02168    }
02169 
02170    /* Headers come after parameters, but there may be headers without
02171     * parameters, thus the S_OR
02172     */
02173    if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
02174       *headers1++ = '\0';
02175    }
02176    if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
02177       *headers2++ = '\0';
02178    }
02179 
02180    if (sip_uri_domain_cmp(host1, host2)) {
02181       return 1;
02182    }
02183 
02184    /* Headers have easier rules to follow, so do those first */
02185    if (sip_uri_headers_cmp(headers1, headers2)) {
02186       return 1;
02187    }
02188 
02189    /* And now the parameters. Ugh */
02190    return sip_uri_params_cmp(params1, params2);
02191 }

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

References ast_sockaddr_cmp(), and ast_sockaddr_parse().

Referenced by sip_uri_cmp().

02052 {
02053    struct ast_sockaddr addr1;
02054    struct ast_sockaddr addr2;
02055    int addr1_parsed;
02056    int addr2_parsed;
02057 
02058    addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
02059    addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
02060 
02061    if (addr1_parsed != addr2_parsed) {
02062       /* One domain was an IP address and the other had
02063        * a host name. FAIL!
02064        */
02065       return 1;
02066    }
02067 
02068    /* Both are host names. A string comparison will work
02069     * perfectly here. Specifying the "C" locale ensures that
02070     * The LC_CTYPE conventions use those defined in ANSI C,
02071     * i.e. ASCII.
02072     */
02073    if (!addr1_parsed) {
02074 #ifdef HAVE_XLOCALE_H
02075       if(!c_locale) {
02076          return strcasecmp(host1, host2);
02077       } else {
02078          return strcasecmp_l(host1, host2, c_locale);
02079       }
02080 #else
02081       return strcasecmp(host1, host2);
02082 #endif
02083    }
02084 
02085    /* Both contain IP addresses */
02086    return ast_sockaddr_cmp(&addr1, &addr2);
02087 }

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

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

Referenced by sip_uri_cmp().

01987 {
01988    char *headers1 = NULL;
01989    char *headers2 = NULL;
01990    int zerolength1 = 0;
01991    int zerolength2 = 0;
01992    int different = 0;
01993    char *header1;
01994 
01995    if (ast_strlen_zero(input1)) {
01996       zerolength1 = 1;
01997    } else {
01998       headers1 = ast_strdupa(input1);
01999    }
02000 
02001    if (ast_strlen_zero(input2)) {
02002       zerolength2 = 1;
02003    } else {
02004       headers2 = ast_strdupa(input2);
02005    }
02006 
02007    /* If one URI contains no headers and the other
02008     * does, then they cannot possibly match
02009     */
02010    if (zerolength1 != zerolength2) {
02011       return 1;
02012    }
02013 
02014    if (zerolength1 && zerolength2)
02015       return 0;
02016 
02017    /* At this point, we can definitively state that both inputs are
02018     * not zero-length. First, one more optimization. If the length
02019     * of the headers is not equal, then we definitely have no match
02020     */
02021    if (strlen(headers1) != strlen(headers2)) {
02022       return 1;
02023    }
02024 
02025    for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
02026       if (!strcasestr(headers2, header1)) {
02027          different = 1;
02028          break;
02029       }
02030    }
02031 
02032    return different;
02033 }

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

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

Referenced by sip_uri_cmp().

01861 {
01862    char *params1 = NULL;
01863    char *params2 = NULL;
01864    char *pos1;
01865    char *pos2;
01866    int zerolength1 = 0;
01867    int zerolength2 = 0;
01868    int maddrmatch = 0;
01869    int ttlmatch = 0;
01870    int usermatch = 0;
01871    int methodmatch = 0;
01872 
01873    if (ast_strlen_zero(input1)) {
01874       zerolength1 = 1;
01875    } else {
01876       params1 = ast_strdupa(input1);
01877    }
01878    if (ast_strlen_zero(input2)) {
01879       zerolength2 = 1;
01880    } else {
01881       params2 = ast_strdupa(input2);
01882    }
01883 
01884    /* Quick optimization. If both params are zero-length, then
01885     * they match
01886     */
01887    if (zerolength1 && zerolength2) {
01888       return 0;
01889    }
01890 
01891    for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
01892       char *value1 = pos1;
01893       char *name1 = strsep(&value1, "=");
01894       char *params2dup = NULL;
01895       int matched = 0;
01896       if (!value1) {
01897          value1 = "";
01898       }
01899       /* Checkpoint reached. We have the name and value parsed for param1
01900        * We have to duplicate params2 each time through this loop
01901        * or else the inner loop below will not work properly.
01902        */
01903       if (!zerolength2) {
01904          params2dup = ast_strdupa(params2);
01905       }
01906       for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
01907          char *name2 = pos2;
01908          char *value2 = strchr(pos2, '=');
01909          if (!value2) {
01910             value2 = "";
01911          } else {
01912             *value2++ = '\0';
01913          }
01914          if (!strcasecmp(name1, name2)) {
01915             if (strcasecmp(value1, value2)) {
01916                goto fail;
01917             } else {
01918                matched = 1;
01919                break;
01920             }
01921          }
01922       }
01923       /* Check to see if the parameter is one of the 'must-match' parameters */
01924       if (!strcasecmp(name1, "maddr")) {
01925          if (matched) {
01926             maddrmatch = 1;
01927          } else {
01928             goto fail;
01929          }
01930       } else if (!strcasecmp(name1, "ttl")) {
01931          if (matched) {
01932             ttlmatch = 1;
01933          } else {
01934             goto fail;
01935          }
01936       } else if (!strcasecmp(name1, "user")) {
01937          if (matched) {
01938             usermatch = 1;
01939          } else {
01940             goto fail;
01941          }
01942       } else if (!strcasecmp(name1, "method")) {
01943          if (matched) {
01944             methodmatch = 1;
01945          } else {
01946             goto fail;
01947          }
01948       }
01949    }
01950 
01951    /* We've made it out of that horrible O(m*n) construct and there are no
01952     * failures yet. We're not done yet, though, because params2 could have
01953     * an maddr, ttl, user, or method header and params1 did not.
01954     */
01955    for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
01956       char *value2 = pos2;
01957       char *name2 = strsep(&value2, "=");
01958       if (!value2) {
01959          value2 = "";
01960       }
01961       if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
01962             (!strcasecmp(name2, "ttl") && !ttlmatch) ||
01963             (!strcasecmp(name2, "user") && !usermatch) ||
01964             (!strcasecmp(name2, "method") && !methodmatch)) {
01965          goto fail;
01966       }
01967    }
01968    return 0;
01969 
01970 fail:
01971    return 1;
01972 }


Variable Documentation

locale_t c_locale

Definition at line 31 of file reqresp_parser.c.


Generated on Mon Mar 19 11:30:53 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7