sip request parsing functions and unit tests More...
#include "asterisk.h"
#include "include/sip.h"
#include "include/sip_utils.h"
#include "include/reqresp_parser.h"
Go to the source code of this file.
Defines | |
#define | URI_CMP_MATCH 0 |
#define | URI_CMP_NOMATCH 1 |
Functions | |
AST_TEST_DEFINE (parse_via_test) | |
AST_TEST_DEFINE (sip_uri_cmp_test) | |
AST_TEST_DEFINE (sip_parse_options_test) | |
AST_TEST_DEFINE (parse_contact_header_test) | |
AST_TEST_DEFINE (parse_name_andor_addr_test) | |
AST_TEST_DEFINE (get_in_brackets_test) | |
AST_TEST_DEFINE (get_name_and_number_test) | |
AST_TEST_DEFINE (get_calleridname_test) | |
AST_TEST_DEFINE (sip_parse_uri_test) | |
AST_TEST_DEFINE (sip_parse_uri_full_test) | |
void | free_via (struct sip_via *v) |
const char * | get_calleridname (const char *input, char *output, size_t outputsize) |
Get caller id name from SIP headers, copy into output buffer. | |
int | get_comma (char *in, char **out) |
char * | get_in_brackets (char *tmp) |
int | get_in_brackets_const (const char *src, const char **start, int *length) |
int | get_in_brackets_full (char *tmp, char **out, char **residue) |
int | get_name_and_number (const char *hdr, char **name, char **number) |
int | parse_contact_header (char *contactheader, struct contactliststruct *contactlist) |
int | parse_name_andor_addr (char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue) |
unsigned int | parse_sip_options (const char *options, char *unsupported, size_t unsupported_len) |
Parse supported header in incoming packet. | |
int | parse_uri (char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport) |
int | parse_uri_full (char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue) |
* parses a URI in its components. | |
struct sip_via * | parse_via (const char *header) |
void | sip_reqresp_parser_exit (void) |
int | sip_reqresp_parser_init (void) |
void | sip_request_parser_register_tests (void) |
void | sip_request_parser_unregister_tests (void) |
int | sip_uri_cmp (const char *input1, const char *input2) |
static int | sip_uri_domain_cmp (const char *host1, const char *host2) |
Compare domain sections of SIP URIs. | |
static int | sip_uri_headers_cmp (const char *input1, const char *input2) |
helper routine for sip_uri_cmp to compare URI headers | |
static int | sip_uri_params_cmp (const char *input1, const char *input2) |
helper routine for sip_uri_cmp to compare URI parameters |
sip request parsing functions and unit tests
Definition in file reqresp_parser.c.
#define URI_CMP_MATCH 0 |
Definition at line 2149 of file reqresp_parser.c.
Referenced by AST_TEST_DEFINE().
#define URI_CMP_NOMATCH 1 |
Definition at line 2150 of file reqresp_parser.c.
Referenced by AST_TEST_DEFINE().
AST_TEST_DEFINE | ( | parse_via_test | ) |
Definition at line 2354 of file reqresp_parser.c.
References AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, free_via(), parse_via(), TEST_EXECUTE, and TEST_INIT.
02355 { 02356 int res = AST_TEST_PASS; 02357 int i = 1; 02358 struct sip_via *via; 02359 struct testdata { 02360 char *in; 02361 char *expected_protocol; 02362 char *expected_branch; 02363 char *expected_sent_by; 02364 char *expected_maddr; 02365 unsigned int expected_port; 02366 unsigned char expected_ttl; 02367 int expected_null; 02368 AST_LIST_ENTRY(testdata) list; 02369 }; 02370 struct testdata *testdataptr; 02371 static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist; 02372 struct testdata t1 = { 02373 .in = "SIP/2.0/UDP host:port;branch=thebranch", 02374 .expected_protocol = "SIP/2.0/UDP", 02375 .expected_sent_by = "host:port", 02376 .expected_branch = "thebranch", 02377 }; 02378 struct testdata t2 = { 02379 .in = "SIP/2.0/UDP host:port", 02380 .expected_protocol = "SIP/2.0/UDP", 02381 .expected_sent_by = "host:port", 02382 .expected_branch = "", 02383 }; 02384 struct testdata t3 = { 02385 .in = "SIP/2.0/UDP", 02386 .expected_null = 1, 02387 }; 02388 struct testdata t4 = { 02389 .in = "BLAH/BLAH/BLAH host:port;branch=", 02390 .expected_protocol = "BLAH/BLAH/BLAH", 02391 .expected_sent_by = "host:port", 02392 .expected_branch = "", 02393 }; 02394 struct testdata t5 = { 02395 .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1", 02396 .expected_protocol = "SIP/2.0/UDP", 02397 .expected_sent_by = "host:5060", 02398 .expected_port = 5060, 02399 .expected_branch = "thebranch", 02400 .expected_maddr = "224.0.0.1", 02401 .expected_ttl = 1, 02402 }; 02403 struct testdata t6 = { 02404 .in = "SIP/2.0/UDP host:5060;\n branch=thebranch;\r\n maddr=224.0.0.1; ttl=1", 02405 .expected_protocol = "SIP/2.0/UDP", 02406 .expected_sent_by = "host:5060", 02407 .expected_port = 5060, 02408 .expected_branch = "thebranch", 02409 .expected_maddr = "224.0.0.1", 02410 .expected_ttl = 1, 02411 }; 02412 struct testdata t7 = { 02413 .in = "SIP/2.0/UDP [::1]:5060", 02414 .expected_protocol = "SIP/2.0/UDP", 02415 .expected_sent_by = "[::1]:5060", 02416 .expected_port = 5060, 02417 .expected_branch = "", 02418 }; 02419 switch (cmd) { 02420 case TEST_INIT: 02421 info->name = "parse_via_test"; 02422 info->category = "/channels/chan_sip/"; 02423 info->summary = "Tests parsing the Via header"; 02424 info->description = 02425 "Runs through various test situations in which various " 02426 " parameters parameter must be extracted from a VIA header"; 02427 return AST_TEST_NOT_RUN; 02428 case TEST_EXECUTE: 02429 break; 02430 } 02431 02432 AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1); 02433 AST_LIST_INSERT_TAIL(&testdatalist, &t2, list); 02434 AST_LIST_INSERT_TAIL(&testdatalist, &t3, list); 02435 AST_LIST_INSERT_TAIL(&testdatalist, &t4, list); 02436 AST_LIST_INSERT_TAIL(&testdatalist, &t5, list); 02437 AST_LIST_INSERT_TAIL(&testdatalist, &t6, list); 02438 AST_LIST_INSERT_TAIL(&testdatalist, &t7, list); 02439 02440 02441 AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { 02442 via = parse_via(testdataptr->in); 02443 if (!via) { 02444 if (!testdataptr->expected_null) { 02445 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02446 "failed to parse header\n", 02447 i, testdataptr->in); 02448 res = AST_TEST_FAIL; 02449 } 02450 i++; 02451 continue; 02452 } 02453 02454 if (testdataptr->expected_null) { 02455 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02456 "successfully parased invalid via header\n", 02457 i, testdataptr->in); 02458 res = AST_TEST_FAIL; 02459 free_via(via); 02460 i++; 02461 continue; 02462 } 02463 02464 if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol)) 02465 || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) { 02466 02467 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02468 "parsed protocol = \"%s\"\n" 02469 "expected = \"%s\"\n" 02470 "failed to parse protocol\n", 02471 i, testdataptr->in, via->protocol, testdataptr->expected_protocol); 02472 res = AST_TEST_FAIL; 02473 } 02474 02475 if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by)) 02476 || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) { 02477 02478 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02479 "parsed sent_by = \"%s\"\n" 02480 "expected = \"%s\"\n" 02481 "failed to parse sent-by\n", 02482 i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by); 02483 res = AST_TEST_FAIL; 02484 } 02485 02486 if (testdataptr->expected_port && testdataptr->expected_port != via->port) { 02487 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02488 "parsed port = \"%u\"\n" 02489 "expected = \"%u\"\n" 02490 "failed to parse port\n", 02491 i, testdataptr->in, via->port, testdataptr->expected_port); 02492 res = AST_TEST_FAIL; 02493 } 02494 02495 if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch)) 02496 || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) { 02497 02498 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02499 "parsed branch = \"%s\"\n" 02500 "expected = \"%s\"\n" 02501 "failed to parse branch\n", 02502 i, testdataptr->in, via->branch, testdataptr->expected_branch); 02503 res = AST_TEST_FAIL; 02504 } 02505 02506 if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr)) 02507 || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) { 02508 02509 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02510 "parsed maddr = \"%s\"\n" 02511 "expected = \"%s\"\n" 02512 "failed to parse maddr\n", 02513 i, testdataptr->in, via->maddr, testdataptr->expected_maddr); 02514 res = AST_TEST_FAIL; 02515 } 02516 02517 if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) { 02518 ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n" 02519 "parsed ttl = \"%d\"\n" 02520 "expected = \"%d\"\n" 02521 "failed to parse ttl\n", 02522 i, testdataptr->in, via->ttl, testdataptr->expected_ttl); 02523 res = AST_TEST_FAIL; 02524 } 02525 02526 free_via(via); 02527 i++; 02528 } 02529 return res; 02530 }
AST_TEST_DEFINE | ( | sip_uri_cmp_test | ) |
Definition at line 2152 of file reqresp_parser.c.
References ARRAY_LEN, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_uri_cmp(), TEST_EXECUTE, TEST_INIT, URI_CMP_MATCH, and URI_CMP_NOMATCH.
02153 { 02154 static const struct { 02155 const char *uri1; 02156 const char *uri2; 02157 int expected_result; 02158 } uri_cmp_tests [] = { 02159 /* These are identical, so they match */ 02160 { "sip:bob@example.com", "sip:bob@example.com", URI_CMP_MATCH }, 02161 /* Different usernames. No match */ 02162 { "sip:alice@example.com", "sip:bob@example.com", URI_CMP_NOMATCH }, 02163 /* Different hosts. No match */ 02164 { "sip:bob@example.com", "sip:bob@examplez.com", URI_CMP_NOMATCH }, 02165 /* Now start using IP addresses. Identical, so they match */ 02166 { "sip:bob@1.2.3.4", "sip:bob@1.2.3.4", URI_CMP_MATCH }, 02167 /* Two identical IPv4 addresses represented differently. Match */ 02168 { "sip:bob@1.2.3.4", "sip:bob@001.002.003.004", URI_CMP_MATCH }, 02169 /* Logically equivalent IPv4 Address and hostname. No Match */ 02170 { "sip:bob@127.0.0.1", "sip:bob@localhost", URI_CMP_NOMATCH }, 02171 /* Logically equivalent IPv6 address and hostname. No Match */ 02172 { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH }, 02173 /* Try an IPv6 one as well */ 02174 { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH }, 02175 /* Two identical IPv6 addresses represented differently. Match */ 02176 { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH }, 02177 /* Different ports. No match */ 02178 { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4:5061", URI_CMP_NOMATCH }, 02179 /* Same port logically, but only one address specifies it. No match */ 02180 { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4", URI_CMP_NOMATCH }, 02181 /* And for safety, try with IPv6 */ 02182 { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH }, 02183 /* User comparison is case sensitive. No match */ 02184 { "sip:bob@example.com", "sip:BOB@example.com", URI_CMP_NOMATCH }, 02185 /* Host comparison is case insensitive. Match */ 02186 { "sip:bob@example.com", "sip:bob@EXAMPLE.COM", URI_CMP_MATCH }, 02187 /* Add headers to the URI. Identical, so they match */ 02188 { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value2", URI_CMP_MATCH }, 02189 /* Headers in URI 1 are not in URI 2. No Match */ 02190 { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com", URI_CMP_NOMATCH }, 02191 /* Header present in both URIs does not have matching values. No match */ 02192 { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value3", URI_CMP_NOMATCH }, 02193 /* Add parameters to the URI. Identical so they match */ 02194 { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH }, 02195 /* Same parameters in both URIs but appear in different order. Match */ 02196 { "sip:bob@example.com;param2=value2;param1=value1", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH }, 02197 /* params in URI 1 are not in URI 2. Match */ 02198 { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com", URI_CMP_MATCH }, 02199 /* param present in both URIs does not have matching values. No match */ 02200 { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value3", URI_CMP_NOMATCH }, 02201 /* URI 1 has a maddr param but URI 2 does not. No match */ 02202 { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1", URI_CMP_NOMATCH }, 02203 /* URI 1 and URI 2 both have identical maddr params. Match */ 02204 { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1;maddr=192.168.0.1", URI_CMP_MATCH }, 02205 /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */ 02206 { "sips:bob@example.com", "sip:bob@example.com", URI_CMP_NOMATCH }, 02207 /* No URI schemes. No match */ 02208 { "bob@example.com", "bob@example.com", URI_CMP_NOMATCH }, 02209 /* Crashiness tests. Just an address scheme. No match */ 02210 { "sip", "sips", URI_CMP_NOMATCH }, 02211 /* Still just an address scheme. Even though they're the same, No match */ 02212 { "sip", "sip", URI_CMP_NOMATCH }, 02213 /* Empty strings. No match */ 02214 { "", "", URI_CMP_NOMATCH }, 02215 /* An empty string and a NULL. No match */ 02216 { "", NULL, URI_CMP_NOMATCH }, 02217 }; 02218 int i; 02219 int test_res = AST_TEST_PASS; 02220 switch (cmd) { 02221 case TEST_INIT: 02222 info->name = "sip_uri_cmp_test"; 02223 info->category = "/channels/chan_sip/"; 02224 info->summary = "Tests comparison of SIP URIs"; 02225 info->description = "Several would-be tricky URI comparisons are performed"; 02226 return AST_TEST_NOT_RUN; 02227 case TEST_EXECUTE: 02228 break; 02229 } 02230 02231 for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) { 02232 int cmp_res1; 02233 int cmp_res2; 02234 if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) { 02235 /* URI comparison may return -1 or +1 depending on the failure. Standardize 02236 * the return value to be URI_CMP_NOMATCH on any failure 02237 */ 02238 cmp_res1 = URI_CMP_NOMATCH; 02239 } 02240 if (cmp_res1 != uri_cmp_tests[i].expected_result) { 02241 ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. " 02242 "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2, 02243 uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match", 02244 cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match"); 02245 test_res = AST_TEST_FAIL; 02246 } 02247 02248 /* All URI comparisons are commutative, so for the sake of being thorough, we'll 02249 * rerun the comparison with the parameters reversed 02250 */ 02251 if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) { 02252 /* URI comparison may return -1 or +1 depending on the failure. Standardize 02253 * the return value to be URI_CMP_NOMATCH on any failure 02254 */ 02255 cmp_res2 = URI_CMP_NOMATCH; 02256 } 02257 if (cmp_res2 != uri_cmp_tests[i].expected_result) { 02258 ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. " 02259 "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1, 02260 uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match", 02261 cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match"); 02262 test_res = AST_TEST_FAIL; 02263 } 02264 } 02265 02266 return test_res; 02267 }
AST_TEST_DEFINE | ( | sip_parse_options_test | ) |
Definition at line 1661 of file reqresp_parser.c.
References ARRAY_LEN, AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, name, parse_sip_options(), TEST_EXECUTE, and TEST_INIT.
01662 { 01663 int res = AST_TEST_PASS; 01664 char unsupported[64]; 01665 unsigned int option_profile = 0; 01666 struct testdata { 01667 char *name; 01668 char *input_options; 01669 char *expected_unsupported; 01670 unsigned int expected_profile; 01671 AST_LIST_ENTRY(testdata) list; 01672 }; 01673 01674 struct testdata *testdataptr; 01675 static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist; 01676 01677 struct testdata test1 = { 01678 .name = "test_all_unsupported", 01679 .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4", 01680 .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4", 01681 .expected_profile = SIP_OPT_UNKNOWN, 01682 }; 01683 struct testdata test2 = { 01684 .name = "test_all_unsupported_one_supported", 01685 .input_options = " unsupported1, replaces, unsupported3 , , , ,unsupported4", 01686 .expected_unsupported = "unsupported1,unsupported3,unsupported4", 01687 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES 01688 }; 01689 struct testdata test3 = { 01690 .name = "test_two_supported_two_unsupported", 01691 .input_options = ",, timer ,replaces ,unsupported3,unsupported4", 01692 .expected_unsupported = "unsupported3,unsupported4", 01693 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER, 01694 }; 01695 01696 struct testdata test4 = { 01697 .name = "test_all_supported", 01698 .input_options = "timer,replaces", 01699 .expected_unsupported = "", 01700 .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER, 01701 }; 01702 01703 struct testdata test5 = { 01704 .name = "test_all_supported_redundant", 01705 .input_options = "timer,replaces,timer,replace,timer,replaces", 01706 .expected_unsupported = "", 01707 .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER, 01708 }; 01709 struct testdata test6 = { 01710 .name = "test_buffer_overflow", 01711 .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____" 01712 "____________________________________,__________________________________________" 01713 "________________________________________________", 01714 .expected_unsupported = "unsupported1,unsupported4", 01715 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER, 01716 }; 01717 struct testdata test7 = { 01718 .name = "test_null_input", 01719 .input_options = NULL, 01720 .expected_unsupported = "", 01721 .expected_profile = 0, 01722 }; 01723 struct testdata test8 = { 01724 .name = "test_whitespace_input", 01725 .input_options = " ", 01726 .expected_unsupported = "", 01727 .expected_profile = 0, 01728 }; 01729 struct testdata test9 = { 01730 .name = "test_whitespace_plus_option_input", 01731 .input_options = " , , ,timer , , , , , ", 01732 .expected_unsupported = "", 01733 .expected_profile = SIP_OPT_TIMER, 01734 }; 01735 01736 switch (cmd) { 01737 case TEST_INIT: 01738 info->name = "sip_parse_options_test"; 01739 info->category = "/channels/chan_sip/"; 01740 info->summary = "Tests parsing of sip options"; 01741 info->description = 01742 "Tests parsing of SIP options from supported and required " 01743 "header fields. Verifies when unsupported options are encountered " 01744 "that they are appended to the unsupported out buffer and that the " 01745 "correct bit field representnig the option profile is returned."; 01746 return AST_TEST_NOT_RUN; 01747 case TEST_EXECUTE: 01748 break; 01749 } 01750 01751 AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1); 01752 AST_LIST_INSERT_TAIL(&testdatalist, &test2, list); 01753 AST_LIST_INSERT_TAIL(&testdatalist, &test3, list); 01754 AST_LIST_INSERT_TAIL(&testdatalist, &test4, list); 01755 AST_LIST_INSERT_TAIL(&testdatalist, &test5, list); 01756 AST_LIST_INSERT_TAIL(&testdatalist, &test6, list); 01757 AST_LIST_INSERT_TAIL(&testdatalist, &test7, list); 01758 AST_LIST_INSERT_TAIL(&testdatalist, &test8, list); 01759 AST_LIST_INSERT_TAIL(&testdatalist, &test9, list); 01760 01761 /* Test with unsupported char buffer */ 01762 AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { 01763 memset(unsupported, 0, sizeof(unsupported)); 01764 option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported)); 01765 if (option_profile != testdataptr->expected_profile || 01766 strcmp(unsupported, testdataptr->expected_unsupported)) { 01767 ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:" 01768 "%s expected bit profile: %x actual bit profile: %x\n", 01769 testdataptr->name, 01770 testdataptr->expected_unsupported, 01771 unsupported, 01772 testdataptr->expected_profile, 01773 option_profile); 01774 res = AST_TEST_FAIL; 01775 } else { 01776 ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n", 01777 testdataptr->name, 01778 unsupported, 01779 option_profile); 01780 } 01781 01782 option_profile = parse_sip_options(testdataptr->input_options, NULL, 0); 01783 if (option_profile != testdataptr->expected_profile) { 01784 ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n", 01785 testdataptr->name, 01786 testdataptr->expected_profile, 01787 option_profile); 01788 res = AST_TEST_FAIL; 01789 } else { 01790 ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n", 01791 testdataptr->name, 01792 option_profile); 01793 } 01794 } 01795 01796 return res; 01797 }
AST_TEST_DEFINE | ( | parse_contact_header_test | ) |
Definition at line 1429 of file reqresp_parser.c.
References ast_copy_string(), ast_free, AST_LIST_ENTRY, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, parse_contact_header(), TEST_EXECUTE, and TEST_INIT.
01430 { 01431 int res = AST_TEST_PASS; 01432 char contactheader[1024]; 01433 int star; 01434 struct contactliststruct contactlist; 01435 struct contactliststruct *contactlistptr=&contactlist; 01436 01437 struct testdata { 01438 char *desc; 01439 char *contactheader; 01440 int star; 01441 struct contactliststruct *contactlist; 01442 01443 AST_LIST_ENTRY(testdata) list; 01444 }; 01445 01446 struct testdata *testdataptr; 01447 struct contact *tdcontactptr; 01448 struct contact *contactptr; 01449 01450 static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist; 01451 struct contactliststruct contactlist1, contactlist2; 01452 01453 struct testdata td1 = { 01454 .desc = "single contact", 01455 .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600", 01456 .contactlist = &contactlist1, 01457 .star = 0 01458 }; 01459 struct contact contact11 = { 01460 .name = "name :@;?&,", 01461 .user = "user", 01462 .pass = "secret", 01463 .hostport = "host:5082", 01464 .params.transport = "tcp", 01465 .params.ttl = "", 01466 .params.lr = 0, 01467 .headers = "", 01468 .expires = "3600", 01469 .q = "" 01470 }; 01471 01472 struct testdata td2 = { 01473 .desc = "multiple contacts", 01474 .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2", 01475 .contactlist = &contactlist2, 01476 .star = 0, 01477 }; 01478 struct contact contact21 = { 01479 .name = "", 01480 .user = ",user1,", 01481 .pass = ",secret1,", 01482 .hostport = "host1", 01483 .params.transport = "", 01484 .params.ttl = "7", 01485 .params.lr = 0, 01486 .headers = "", 01487 .expires = "3600", 01488 .q = "1" 01489 }; 01490 struct contact contact22 = { 01491 .name = "", 01492 .user = "", 01493 .pass = "", 01494 .hostport = "host2", 01495 .params.transport = "", 01496 .params.ttl = "", 01497 .params.lr = 0, 01498 .headers = "", 01499 .expires = "", 01500 .q = "" 01501 }; 01502 01503 struct testdata td3 = { 01504 .desc = "star - all contacts", 01505 .contactheader = "*", 01506 .star = 1, 01507 .contactlist = NULL 01508 }; 01509 01510 AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1); 01511 AST_LIST_INSERT_TAIL(&testdatalist, &td2, list); 01512 AST_LIST_INSERT_TAIL(&testdatalist, &td3, list); 01513 01514 AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11); 01515 01516 AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21); 01517 AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list); 01518 01519 01520 switch (cmd) { 01521 case TEST_INIT: 01522 info->name = "parse_contact_header_test"; 01523 info->category = "/channels/chan_sip/"; 01524 info->summary = "tests parsing of sip contact header"; 01525 info->description = 01526 "Tests parsing of a contact header including those with multiple contacts " 01527 "Verifies output matches expected behavior."; 01528 return AST_TEST_NOT_RUN; 01529 case TEST_EXECUTE: 01530 break; 01531 } 01532 01533 AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { 01534 ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader)); 01535 star = parse_contact_header(contactheader,contactlistptr); 01536 if (testdataptr->star) { 01537 /* expecting star rather than list of contacts */ 01538 if (!star) { 01539 ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc); 01540 res = AST_TEST_FAIL; 01541 break; 01542 } 01543 } else { 01544 contactptr = AST_LIST_FIRST(contactlistptr); 01545 AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) { 01546 if (!contactptr || 01547 strcmp(tdcontactptr->name, contactptr->name) || 01548 strcmp(tdcontactptr->user, contactptr->user) || 01549 strcmp(tdcontactptr->pass, contactptr->pass) || 01550 strcmp(tdcontactptr->hostport, contactptr->hostport) || 01551 strcmp(tdcontactptr->headers, contactptr->headers) || 01552 strcmp(tdcontactptr->expires, contactptr->expires) || 01553 strcmp(tdcontactptr->q, contactptr->q) || 01554 strcmp(tdcontactptr->params.transport, contactptr->params.transport) || 01555 strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) || 01556 (tdcontactptr->params.lr != contactptr->params.lr) 01557 ) { 01558 ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc); 01559 res = AST_TEST_FAIL; 01560 break; 01561 } 01562 01563 contactptr = AST_LIST_NEXT(contactptr,list); 01564 } 01565 01566 while ((contactptr = AST_LIST_REMOVE_HEAD(contactlistptr,list))) { 01567 ast_free(contactptr); 01568 } 01569 } 01570 } 01571 01572 return res; 01573 }
AST_TEST_DEFINE | ( | parse_name_andor_addr_test | ) |
Definition at line 1204 of file reqresp_parser.c.
References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, name, parse_name_andor_addr(), pass, TEST_EXECUTE, and TEST_INIT.
01205 { 01206 int res = AST_TEST_PASS; 01207 char uri[1024]; 01208 char *name, *user, *pass, *hostport, *headers, *residue; 01209 struct uriparams params; 01210 01211 struct testdata { 01212 char *desc; 01213 char *uri; 01214 char *name; 01215 char *user; 01216 char *pass; 01217 char *hostport; 01218 char *headers; 01219 char *residue; 01220 struct uriparams params; 01221 AST_LIST_ENTRY(testdata) list; 01222 }; 01223 01224 struct testdata *testdataptr; 01225 01226 static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist; 01227 01228 struct testdata td1 = { 01229 .desc = "quotes and brackets", 01230 .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag", 01231 .name = "name :@ ", 01232 .user = "user", 01233 .pass = "secret", 01234 .hostport = "host:5060", 01235 .headers = "", 01236 .residue = "tag=tag", 01237 .params.transport = "tcp", 01238 .params.lr = 0, 01239 .params.user = "" 01240 }; 01241 01242 struct testdata td2 = { 01243 .desc = "no quotes", 01244 .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600", 01245 .name = "givenname familyname", 01246 .user = "user", 01247 .pass = "secret", 01248 .hostport = "host:5060", 01249 .headers = "", 01250 .residue = "expires=3600", 01251 .params.transport = "tcp", 01252 .params.lr = 0, 01253 .params.user = "" 01254 }; 01255 01256 struct testdata td3 = { 01257 .desc = "no brackets", 01258 .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1", 01259 .name = "", 01260 .user = "user", 01261 .pass = "secret", 01262 .hostport = "host:5060", 01263 .headers = "", 01264 .residue = "q=1", 01265 .params.transport = "tcp", 01266 .params.lr = 0, 01267 .params.user = "" 01268 }; 01269 01270 struct testdata td4 = { 01271 .desc = "just host", 01272 .uri = "sips:host", 01273 .name = "", 01274 .user = "", 01275 .pass = "", 01276 .hostport = "host", 01277 .headers = "", 01278 .residue = "", 01279 .params.transport = "", 01280 .params.lr = 0, 01281 .params.user = "" 01282 }; 01283 01284 01285 AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1); 01286 AST_LIST_INSERT_TAIL(&testdatalist, &td2, list); 01287 AST_LIST_INSERT_TAIL(&testdatalist, &td3, list); 01288 AST_LIST_INSERT_TAIL(&testdatalist, &td4, list); 01289 01290 01291 switch (cmd) { 01292 case TEST_INIT: 01293 info->name = "parse_name_andor_addr_test"; 01294 info->category = "/channels/chan_sip/"; 01295 info->summary = "tests parsing of name_andor_addr abnf structure"; 01296 info->description = 01297 "Tests parsing of abnf name-andor-addr = name-addr / addr-spec " 01298 "Verifies output matches expected behavior."; 01299 return AST_TEST_NOT_RUN; 01300 case TEST_EXECUTE: 01301 break; 01302 } 01303 01304 AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { 01305 name = user = pass = hostport = headers = residue = NULL; 01306 params.transport = params.user = params.method = params.ttl = params.maddr = NULL; 01307 params.lr = 0; 01308 ast_copy_string(uri,testdataptr->uri,sizeof(uri)); 01309 if (parse_name_andor_addr(uri, "sip:,sips:", 01310 &name, 01311 &user, 01312 &pass, 01313 &hostport, 01314 ¶ms, 01315 &headers, 01316 &residue) || 01317 (name && strcmp(testdataptr->name, name)) || 01318 (user && strcmp(testdataptr->user, user)) || 01319 (pass && strcmp(testdataptr->pass, pass)) || 01320 (hostport && strcmp(testdataptr->hostport, hostport)) || 01321 (headers && strcmp(testdataptr->headers, headers)) || 01322 (residue && strcmp(testdataptr->residue, residue)) || 01323 (strcmp(testdataptr->params.transport,params.transport)) || 01324 (strcmp(testdataptr->params.user,params.user)) 01325 ) { 01326 ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc); 01327 res = AST_TEST_FAIL; 01328 } 01329 } 01330 01331 return res; 01332 }
AST_TEST_DEFINE | ( | get_in_brackets_test | ) |
Definition at line 1082 of file reqresp_parser.c.
References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_in_brackets(), TEST_EXECUTE, and TEST_INIT.
01083 { 01084 int res = AST_TEST_PASS; 01085 char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah"; 01086 char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; 01087 char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; 01088 char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; 01089 char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; 01090 char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah"; 01091 char no_name_no_brackets[] = "sip:name@host"; 01092 char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; 01093 char *uri = NULL; 01094 01095 switch (cmd) { 01096 case TEST_INIT: 01097 info->name = "sip_get_in_brackets_test"; 01098 info->category = "/channels/chan_sip/"; 01099 info->summary = "Tests getting a sip uri in <> brackets within a sip header."; 01100 info->description = 01101 "Runs through various test situations in which a sip uri " 01102 "in angle brackets needs to be retrieved"; 01103 return AST_TEST_NOT_RUN; 01104 case TEST_EXECUTE: 01105 break; 01106 } 01107 01108 /* Test 1, simple get in brackets */ 01109 if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) { 01110 ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri); 01111 res = AST_TEST_FAIL; 01112 } 01113 01114 /* Test 2, starts with quoted string */ 01115 if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) { 01116 ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri); 01117 res = AST_TEST_FAIL; 01118 } 01119 01120 /* Test 3, missing end quote */ 01121 if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) { 01122 ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri); 01123 res = AST_TEST_FAIL; 01124 } 01125 01126 /* Test 4, starts with a name not in quotes */ 01127 if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) { 01128 ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri); 01129 res = AST_TEST_FAIL; 01130 } 01131 01132 /* Test 5, no end bracket, should just return everything after the first '<' */ 01133 if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) { 01134 ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri); 01135 res = AST_TEST_FAIL; 01136 } 01137 01138 /* Test 6, NULL input */ 01139 if (get_in_brackets(NULL)) { 01140 ast_test_status_update(test, "Test 6, NULL input failed.\n"); 01141 res = AST_TEST_FAIL; 01142 } 01143 01144 /* Test 7, no name, and no brackets. */ 01145 if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) { 01146 ast_test_status_update(test, "Test 7 failed. %s\n", uri); 01147 res = AST_TEST_FAIL; 01148 } 01149 01150 /* Test 8, no start bracket, but with ending bracket. */ 01151 if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) { 01152 ast_test_status_update(test, "Test 8 failed. %s\n", uri); 01153 res = AST_TEST_FAIL; 01154 } 01155 01156 return res; 01157 }
AST_TEST_DEFINE | ( | get_name_and_number_test | ) |
Definition at line 846 of file reqresp_parser.c.
References ast_free, ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_name_and_number(), name, TEST_EXECUTE, and TEST_INIT.
00847 { 00848 int res = AST_TEST_PASS; 00849 char *name = NULL; 00850 char *number = NULL; 00851 const char *in1 = "NAME <sip:NUMBER@place>"; 00852 const char *in2 = "\"NA><ME\" <sip:NUMBER@place>"; 00853 const char *in3 = "NAME"; 00854 const char *in4 = "<sip:NUMBER@place>"; 00855 const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>"; 00856 00857 switch (cmd) { 00858 case TEST_INIT: 00859 info->name = "sip_get_name_and_number_test"; 00860 info->category = "/channels/chan_sip/"; 00861 info->summary = "Tests getting name and number from sip header"; 00862 info->description = 00863 "Runs through various test situations in which a name and " 00864 "and number can be retrieved from a sip header."; 00865 return AST_TEST_NOT_RUN; 00866 case TEST_EXECUTE: 00867 break; 00868 } 00869 00870 /* Test 1. get name and number */ 00871 number = name = NULL; 00872 if ((get_name_and_number(in1, &name, &number)) || 00873 strcmp(name, "NAME") || 00874 strcmp(number, "NUMBER")) { 00875 00876 ast_test_status_update(test, "Test 1, simple get name and number failed.\n"); 00877 res = AST_TEST_FAIL; 00878 } 00879 ast_free(name); 00880 ast_free(number); 00881 00882 /* Test 2. get quoted name and number */ 00883 number = name = NULL; 00884 if ((get_name_and_number(in2, &name, &number)) || 00885 strcmp(name, "NA><ME") || 00886 strcmp(number, "NUMBER")) { 00887 00888 ast_test_status_update(test, "Test 2, get quoted name and number failed.\n"); 00889 res = AST_TEST_FAIL; 00890 } 00891 ast_free(name); 00892 ast_free(number); 00893 00894 /* Test 3. name only */ 00895 number = name = NULL; 00896 if (!(get_name_and_number(in3, &name, &number))) { 00897 00898 ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n"); 00899 res = AST_TEST_FAIL; 00900 } 00901 ast_free(name); 00902 ast_free(number); 00903 00904 /* Test 4. number only */ 00905 number = name = NULL; 00906 if ((get_name_and_number(in4, &name, &number)) || 00907 !ast_strlen_zero(name) || 00908 strcmp(number, "NUMBER")) { 00909 00910 ast_test_status_update(test, "Test 4, get number with no name present failed.\n"); 00911 res = AST_TEST_FAIL; 00912 } 00913 ast_free(name); 00914 ast_free(number); 00915 00916 /* Test 5. malformed string, since number can not be parsed, this should return an error. */ 00917 number = name = NULL; 00918 if (!(get_name_and_number(in5, &name, &number)) || 00919 !ast_strlen_zero(name) || 00920 !ast_strlen_zero(number)) { 00921 00922 ast_test_status_update(test, "Test 5, processing malformed string failed.\n"); 00923 res = AST_TEST_FAIL; 00924 } 00925 ast_free(name); 00926 ast_free(number); 00927 00928 /* Test 6. NULL output parameters */ 00929 number = name = NULL; 00930 if (!(get_name_and_number(in5, NULL, NULL))) { 00931 00932 ast_test_status_update(test, "Test 6, NULL output parameters failed.\n"); 00933 res = AST_TEST_FAIL; 00934 } 00935 00936 /* Test 7. NULL input parameter */ 00937 number = name = NULL; 00938 if (!(get_name_and_number(NULL, &name, &number)) || 00939 !ast_strlen_zero(name) || 00940 !ast_strlen_zero(number)) { 00941 00942 ast_test_status_update(test, "Test 7, NULL input parameter failed.\n"); 00943 res = AST_TEST_FAIL; 00944 } 00945 ast_free(name); 00946 ast_free(number); 00947 00948 return res; 00949 }
AST_TEST_DEFINE | ( | get_calleridname_test | ) |
Definition at line 723 of file reqresp_parser.c.
References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_calleridname(), TEST_EXECUTE, and TEST_INIT.
00724 { 00725 int res = AST_TEST_PASS; 00726 const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>"; 00727 const char *in2 = " token text with no quotes <stuff>"; 00728 const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>"; 00729 const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>"; 00730 const char *noendquote = " \"quoted-text no end <stuff>"; 00731 const char *addrspec = " sip:blah@blah"; 00732 const char *no_quotes_no_brackets = "blah@blah"; 00733 const char *after_dname; 00734 char dname[40]; 00735 00736 switch (cmd) { 00737 case TEST_INIT: 00738 info->name = "sip_get_calleridname_test"; 00739 info->category = "/channels/chan_sip/"; 00740 info->summary = "decodes callerid name from sip header"; 00741 info->description = "Decodes display-name field of sip header. Checks for valid output and expected failure cases."; 00742 return AST_TEST_NOT_RUN; 00743 case TEST_EXECUTE: 00744 break; 00745 } 00746 00747 /* quoted-text with backslash escaped quote */ 00748 after_dname = get_calleridname(in1, dname, sizeof(dname)); 00749 ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname); 00750 if (strcmp(dname, " quoted-text internal \" quote ")) { 00751 ast_test_status_update(test, "display-name1 test failed\n"); 00752 res = AST_TEST_FAIL; 00753 } 00754 00755 /* token text */ 00756 after_dname = get_calleridname(in2, dname, sizeof(dname)); 00757 ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname); 00758 if (strcmp(dname, "token text with no quotes")) { 00759 ast_test_status_update(test, "display-name2 test failed\n"); 00760 res = AST_TEST_FAIL; 00761 } 00762 00763 /* quoted-text buffer overflow */ 00764 after_dname = get_calleridname(overflow1, dname, sizeof(dname)); 00765 ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname); 00766 if (strcmp(dname, "quoted-text overflow 123456789012345678")) { 00767 ast_test_status_update(test, "overflow display-name1 test failed\n"); 00768 res = AST_TEST_FAIL; 00769 } 00770 00771 /* non-quoted-text buffer overflow */ 00772 after_dname = get_calleridname(overflow2, dname, sizeof(dname)); 00773 ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname); 00774 if (strcmp(dname, "non-quoted text overflow 12345678901234")) { 00775 ast_test_status_update(test, "overflow display-name2 test failed\n"); 00776 res = AST_TEST_FAIL; 00777 } 00778 00779 /* quoted-text buffer with no terminating end quote */ 00780 after_dname = get_calleridname(noendquote, dname, sizeof(dname)); 00781 ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname); 00782 if (*dname != '\0' && after_dname != noendquote) { 00783 ast_test_status_update(test, "no end quote for quoted-text display-name failed\n"); 00784 res = AST_TEST_FAIL; 00785 } 00786 00787 /* addr-spec rather than display-name. */ 00788 after_dname = get_calleridname(addrspec, dname, sizeof(dname)); 00789 ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname); 00790 if (*dname != '\0' && after_dname != addrspec) { 00791 ast_test_status_update(test, "detection of addr-spec failed\n"); 00792 res = AST_TEST_FAIL; 00793 } 00794 00795 /* no quotes, no brackets */ 00796 after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname)); 00797 ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname); 00798 if (*dname != '\0' && after_dname != no_quotes_no_brackets) { 00799 ast_test_status_update(test, "detection of addr-spec failed\n"); 00800 res = AST_TEST_FAIL; 00801 } 00802 00803 return res; 00804 }
AST_TEST_DEFINE | ( | sip_parse_uri_test | ) |
Definition at line 448 of file reqresp_parser.c.
References ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, name, parse_uri(), pass, TEST_EXECUTE, and TEST_INIT.
00449 { 00450 int res = AST_TEST_PASS; 00451 char *name, *pass, *hostport, *transport; 00452 char uri1[] = "sip:name@host"; 00453 char uri2[] = "sip:name@host;transport=tcp"; 00454 char uri3[] = "sip:name:secret@host;transport=tcp"; 00455 char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah"; 00456 /* test 5 is for NULL input */ 00457 char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah"; 00458 char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah"; 00459 char uri8[] = "sip:host"; 00460 char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah"; 00461 char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah"; 00462 char uri11[] = "host"; 00463 00464 switch (cmd) { 00465 case TEST_INIT: 00466 info->name = "sip_uri_parse_test"; 00467 info->category = "/channels/chan_sip/"; 00468 info->summary = "tests sip uri parsing"; 00469 info->description = 00470 "Tests parsing of various URIs " 00471 "Verifies output matches expected behavior."; 00472 return AST_TEST_NOT_RUN; 00473 case TEST_EXECUTE: 00474 break; 00475 } 00476 00477 /* Test 1, simple URI */ 00478 name = pass = hostport = transport = NULL; 00479 if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) || 00480 strcmp(name, "name") || 00481 !ast_strlen_zero(pass) || 00482 strcmp(hostport, "host") || 00483 !ast_strlen_zero(transport)) { 00484 ast_test_status_update(test, "Test 1: simple uri failed. \n"); 00485 res = AST_TEST_FAIL; 00486 } 00487 00488 /* Test 2, add tcp transport */ 00489 name = pass = hostport = transport = NULL; 00490 if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) || 00491 strcmp(name, "name") || 00492 !ast_strlen_zero(pass) || 00493 strcmp(hostport, "host") || 00494 strcmp(transport, "tcp")) { 00495 ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n"); 00496 res = AST_TEST_FAIL; 00497 } 00498 00499 /* Test 3, add secret */ 00500 name = pass = hostport = transport = NULL; 00501 if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) || 00502 strcmp(name, "name") || 00503 strcmp(pass, "secret") || 00504 strcmp(hostport, "host") || 00505 strcmp(transport, "tcp")) { 00506 ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n"); 00507 res = AST_TEST_FAIL; 00508 } 00509 00510 /* Test 4, add port and unparsed header field*/ 00511 name = pass = hostport = transport = NULL; 00512 if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) || 00513 strcmp(name, "name") || 00514 strcmp(pass, "secret") || 00515 strcmp(hostport, "host:port") || 00516 strcmp(transport, "tcp")) { 00517 ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n"); 00518 res = AST_TEST_FAIL; 00519 } 00520 00521 /* Test 5, verify parse_uri does not crash when given a NULL uri */ 00522 name = pass = hostport = transport = NULL; 00523 if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) { 00524 ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n"); 00525 res = AST_TEST_FAIL; 00526 } 00527 00528 /* Test 6, verify parse_uri does not crash when given a NULL output parameters */ 00529 name = pass = hostport = transport = NULL; 00530 if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) { 00531 ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n"); 00532 res = AST_TEST_FAIL; 00533 } 00534 00535 /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */ 00536 name = pass = hostport = transport = NULL; 00537 if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) || 00538 strcmp(name, "name:secret") || 00539 strcmp(hostport, "host:port")) { 00540 00541 ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n"); 00542 res = AST_TEST_FAIL; 00543 } 00544 00545 /* Test 8, verify parse_uri can handle a hostport only uri */ 00546 name = pass = hostport = transport = NULL; 00547 if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) || 00548 strcmp(hostport, "host") || 00549 !ast_strlen_zero(name)) { 00550 ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n"); 00551 res = AST_TEST_FAIL; 00552 } 00553 00554 /* Test 9, add port and unparsed header field with hostport only uri*/ 00555 name = pass = hostport = transport = NULL; 00556 if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) || 00557 !ast_strlen_zero(name) || 00558 !ast_strlen_zero(pass) || 00559 strcmp(hostport, "host:port") || 00560 strcmp(transport, "tcp")) { 00561 ast_test_status_update(test, "Test 9: hostport only uri failed \n"); 00562 res = AST_TEST_FAIL; 00563 } 00564 00565 /* Test 10, handle invalid/missing "sip:,sips:" scheme 00566 * we expect parse_uri to return an error, but still parse 00567 * the results correctly here */ 00568 name = pass = hostport = transport = NULL; 00569 if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) || 00570 !ast_strlen_zero(name) || 00571 !ast_strlen_zero(pass) || 00572 strcmp(hostport, "host:port") || 00573 strcmp(transport, "tcp")) { 00574 ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n"); 00575 res = AST_TEST_FAIL; 00576 } 00577 00578 /* Test 11, simple hostport only URI with missing scheme 00579 * we expect parse_uri to return an error, but still parse 00580 * the results correctly here */ 00581 name = pass = hostport = transport = NULL; 00582 if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) || 00583 !ast_strlen_zero(name) || 00584 !ast_strlen_zero(pass) || 00585 strcmp(hostport, "host") || 00586 !ast_strlen_zero(transport)) { 00587 ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n"); 00588 res = AST_TEST_FAIL; 00589 } 00590 00591 return res; 00592 }
AST_TEST_DEFINE | ( | sip_parse_uri_full_test | ) |
Definition at line 224 of file reqresp_parser.c.
References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, parse_uri_full(), pass, TEST_EXECUTE, and TEST_INIT.
00225 { 00226 int res = AST_TEST_PASS; 00227 char uri[1024]; 00228 char *user, *pass, *hostport, *headers, *residue; 00229 struct uriparams params; 00230 00231 struct testdata { 00232 char *desc; 00233 char *uri; 00234 char *user; 00235 char *pass; 00236 char *hostport; 00237 char *headers; 00238 char *residue; 00239 struct uriparams params; 00240 AST_LIST_ENTRY(testdata) list; 00241 }; 00242 00243 00244 struct testdata *testdataptr; 00245 00246 static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist; 00247 00248 struct testdata td1 = { 00249 .desc = "no headers", 00250 .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue", 00251 .user = "user", 00252 .pass = "secret", 00253 .hostport = "host:5060", 00254 .headers = "", 00255 .residue = "param2=residue", 00256 .params.transport = "tcp", 00257 .params.lr = 0, 00258 .params.user = "" 00259 }; 00260 00261 struct testdata td2 = { 00262 .desc = "with headers", 00263 .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue", 00264 .user = "user", 00265 .pass = "secret", 00266 .hostport = "host:5060", 00267 .headers = "header=blah&header2=blah2", 00268 .residue = "param3=residue", 00269 .params.transport = "tcp", 00270 .params.lr = 0, 00271 .params.user = "" 00272 }; 00273 00274 struct testdata td3 = { 00275 .desc = "difficult user", 00276 .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp", 00277 .user = "-_.!~*'()&=+$,;?/", 00278 .pass = "secret", 00279 .hostport = "host:5060", 00280 .headers = "", 00281 .residue = "", 00282 .params.transport = "tcp", 00283 .params.lr = 0, 00284 .params.user = "" 00285 }; 00286 00287 struct testdata td4 = { 00288 .desc = "difficult pass", 00289 .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp", 00290 .user = "user", 00291 .pass = "-_.!~*'()&=+$,", 00292 .hostport = "host:5060", 00293 .headers = "", 00294 .residue = "", 00295 .params.transport = "tcp", 00296 .params.lr = 0, 00297 .params.user = "" 00298 }; 00299 00300 struct testdata td5 = { 00301 .desc = "difficult host", 00302 .uri = "sip:user:secret@1-1.a-1.:5060;transport=tcp", 00303 .user = "user", 00304 .pass = "secret", 00305 .hostport = "1-1.a-1.:5060", 00306 .headers = "", 00307 .residue = "", 00308 .params.transport = "tcp", 00309 .params.lr = 0, 00310 .params.user = "" 00311 }; 00312 00313 struct testdata td6 = { 00314 .desc = "difficult params near transport", 00315 .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp", 00316 .user = "user", 00317 .pass = "secret", 00318 .hostport = "host:5060", 00319 .headers = "", 00320 .residue = "", 00321 .params.transport = "tcp", 00322 .params.lr = 0, 00323 .params.user = "" 00324 }; 00325 00326 struct testdata td7 = { 00327 .desc = "difficult params near headers", 00328 .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue", 00329 .user = "user", 00330 .pass = "secret", 00331 .hostport = "host:5060", 00332 .headers = "header=blah&header2=blah2", 00333 .residue = "-_.!~*'()[]/:&+$=residue", 00334 .params.transport = "", 00335 .params.lr = 0, 00336 .params.user = "" 00337 }; 00338 00339 struct testdata td8 = { 00340 .desc = "lr parameter", 00341 .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah", 00342 .user = "user", 00343 .pass = "secret", 00344 .hostport = "host:5060", 00345 .headers = "header=blah", 00346 .residue = "", 00347 .params.transport = "", 00348 .params.lr = 1, 00349 .params.user = "" 00350 }; 00351 00352 struct testdata td9 = { 00353 .desc = "alternative lr parameter", 00354 .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah", 00355 .user = "user", 00356 .pass = "secret", 00357 .hostport = "host:5060", 00358 .headers = "header=blah", 00359 .residue = "", 00360 .params.transport = "", 00361 .params.lr = 1, 00362 .params.user = "" 00363 }; 00364 00365 struct testdata td10 = { 00366 .desc = "no lr parameter", 00367 .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah", 00368 .user = "user", 00369 .pass = "secret", 00370 .hostport = "host:5060", 00371 .headers = "header=blah", 00372 .residue = "", 00373 .params.transport = "", 00374 .params.lr = 0, 00375 .params.user = "" 00376 }; 00377 00378 00379 AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1); 00380 AST_LIST_INSERT_TAIL(&testdatalist, &td2, list); 00381 AST_LIST_INSERT_TAIL(&testdatalist, &td3, list); 00382 AST_LIST_INSERT_TAIL(&testdatalist, &td4, list); 00383 AST_LIST_INSERT_TAIL(&testdatalist, &td5, list); 00384 AST_LIST_INSERT_TAIL(&testdatalist, &td6, list); 00385 AST_LIST_INSERT_TAIL(&testdatalist, &td7, list); 00386 AST_LIST_INSERT_TAIL(&testdatalist, &td8, list); 00387 AST_LIST_INSERT_TAIL(&testdatalist, &td9, list); 00388 AST_LIST_INSERT_TAIL(&testdatalist, &td10, list); 00389 00390 00391 switch (cmd) { 00392 case TEST_INIT: 00393 info->name = "sip_uri_full_parse_test"; 00394 info->category = "/channels/chan_sip/"; 00395 info->summary = "tests sip full uri parsing"; 00396 info->description = 00397 "Tests full parsing of various URIs " 00398 "Verifies output matches expected behavior."; 00399 return AST_TEST_NOT_RUN; 00400 case TEST_EXECUTE: 00401 break; 00402 } 00403 00404 AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) { 00405 user = pass = hostport = headers = residue = NULL; 00406 params.transport = params.user = params.method = params.ttl = params.maddr = NULL; 00407 params.lr = 0; 00408 00409 ast_copy_string(uri,testdataptr->uri,sizeof(uri)); 00410 if (parse_uri_full(uri, "sip:,sips:", &user, 00411 &pass, &hostport, 00412 ¶ms, 00413 &headers, 00414 &residue) || 00415 (user && strcmp(testdataptr->user, user)) || 00416 (pass && strcmp(testdataptr->pass, pass)) || 00417 (hostport && strcmp(testdataptr->hostport, hostport)) || 00418 (headers && strcmp(testdataptr->headers, headers)) || 00419 (residue && strcmp(testdataptr->residue, residue)) || 00420 (strcmp(testdataptr->params.transport,params.transport)) || 00421 (testdataptr->params.lr != params.lr) || 00422 (strcmp(testdataptr->params.user,params.user)) 00423 ) { 00424 ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc); 00425 res = AST_TEST_FAIL; 00426 } 00427 } 00428 00429 00430 return res; 00431 }
void free_via | ( | struct sip_via * | v | ) |
Definition at line 2269 of file reqresp_parser.c.
References ast_free.
Referenced by AST_TEST_DEFINE(), find_call(), parse_via(), process_via(), and sip_alloc().
const char* get_calleridname | ( | const char * | input, | |
char * | output, | |||
size_t | outputsize | |||
) |
Get caller id name from SIP headers, copy into output buffer.
input | string pointer placed after display-name field if possible |
Definition at line 598 of file reqresp_parser.c.
References ast_log(), ast_skip_blanks(), and LOG_WARNING.
Referenced by AST_TEST_DEFINE(), check_user_full(), get_name_and_number(), and parse_name_andor_addr().
00599 { 00600 /* From RFC3261: 00601 * 00602 * From = ( "From" / "f" ) HCOLON from-spec 00603 * from-spec = ( name-addr / addr-spec ) *( SEMI from-param ) 00604 * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT 00605 * display-name = *(token LWS)/ quoted-string 00606 * token = 1*(alphanum / "-" / "." / "!" / "%" / "*" 00607 * / "_" / "+" / "`" / "'" / "~" ) 00608 * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE 00609 * qdtext = LWS / %x21 / %x23-5B / %x5D-7E 00610 * / UTF8-NONASCII 00611 * quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) 00612 * 00613 * HCOLON = *WSP ":" SWS 00614 * SWS = [LWS] 00615 * LWS = *[*WSP CRLF] 1*WSP 00616 * WSP = (SP / HTAB) 00617 * 00618 * Deviations from it: 00619 * - following CRLF's in LWS is not done (here at least) 00620 * - ascii NUL is never legal as it terminates the C-string 00621 * - utf8-nonascii is not checked for validity 00622 */ 00623 char *orig_output = output; 00624 const char *orig_input = input; 00625 00626 if (!output || !outputsize) { 00627 /* Bad output parameters. Should never happen. */ 00628 return input; 00629 } 00630 00631 /* clear any empty characters in the beginning */ 00632 input = ast_skip_blanks(input); 00633 00634 /* make sure the output buffer is initilized */ 00635 *orig_output = '\0'; 00636 00637 /* make room for '\0' at the end of the output buffer */ 00638 --outputsize; 00639 00640 /* no data at all or no display name? */ 00641 if (!input || *input == '<') { 00642 return input; 00643 } 00644 00645 /* quoted-string rules */ 00646 if (input[0] == '"') { 00647 input++; /* skip the first " */ 00648 00649 for (; *input; ++input) { 00650 if (*input == '"') { /* end of quoted-string */ 00651 break; 00652 } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */ 00653 ++input; 00654 if (!*input) { 00655 break; 00656 } 00657 if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) { 00658 continue; /* not a valid quoted-pair, so skip it */ 00659 } 00660 } else if ((*input != 0x9 && (unsigned char) *input < 0x20) 00661 || *input == 0x7f) { 00662 continue; /* skip this invalid character. */ 00663 } 00664 00665 if (0 < outputsize) { 00666 /* We still have room for the output display-name. */ 00667 *output++ = *input; 00668 --outputsize; 00669 } 00670 } 00671 00672 /* if this is successful, input should be at the ending quote */ 00673 if (*input != '"') { 00674 ast_log(LOG_WARNING, "No ending quote for display-name was found\n"); 00675 *orig_output = '\0'; 00676 return orig_input; 00677 } 00678 00679 /* make sure input is past the last quote */ 00680 ++input; 00681 00682 /* terminate output */ 00683 *output = '\0'; 00684 } else { /* either an addr-spec or tokenLWS-combo */ 00685 for (; *input; ++input) { 00686 /* token or WSP (without LWS) */ 00687 if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z') 00688 || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.' 00689 || *input == '!' || *input == '%' || *input == '*' || *input == '_' 00690 || *input == '+' || *input == '`' || *input == '\'' || *input == '~' 00691 || *input == 0x9 || *input == ' ') { 00692 if (0 < outputsize) { 00693 /* We still have room for the output display-name. */ 00694 *output++ = *input; 00695 --outputsize; 00696 } 00697 } else if (*input == '<') { /* end of tokenLWS-combo */ 00698 /* we could assert that the previous char is LWS, but we don't care */ 00699 break; 00700 } else if (*input == ':') { 00701 /* This invalid character which indicates this is addr-spec rather than display-name. */ 00702 *orig_output = '\0'; 00703 return orig_input; 00704 } else { /* else, invalid character we can skip. */ 00705 continue; /* skip this character */ 00706 } 00707 } 00708 00709 if (*input != '<') { /* if we never found the start of addr-spec then this is invalid */ 00710 *orig_output = '\0'; 00711 return orig_input; 00712 } 00713 00714 /* terminate output while trimming any trailing whitespace */ 00715 do { 00716 *output-- = '\0'; 00717 } while (orig_output <= output && (*output == 0x9 || *output == ' ')); 00718 } 00719 00720 return input; 00721 }
int get_comma | ( | char * | in, | |
char ** | out | |||
) |
Definition at line 1334 of file reqresp_parser.c.
References ast_log(), find_closing_quote(), LOG_WARNING, and parse().
Referenced by parse_contact_header().
01335 { 01336 char *c; 01337 char *parse = in; 01338 if (out) { 01339 *out = in; 01340 } 01341 01342 /* Skip any quoted text */ 01343 while (*parse) { 01344 if ((c = strchr(parse, '"'))) { 01345 in = (char *)find_closing_quote((const char *)c + 1, NULL); 01346 if (!*in) { 01347 ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c); 01348 return -1; 01349 } else { 01350 break; 01351 } 01352 } else { 01353 break; 01354 } 01355 parse++; 01356 } 01357 parse = in; 01358 01359 /* Skip any userinfo components of a uri as they may contain commas */ 01360 if ((c = strchr(parse,'@'))) { 01361 parse = c+1; 01362 } 01363 if ((out) && (c = strchr(parse,','))) { 01364 *c++ = '\0'; 01365 *out = c; 01366 return 0; 01367 } 01368 return 1; 01369 }
char* get_in_brackets | ( | char * | tmp | ) |
Definition at line 1072 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().
01073 { 01074 char *out; 01075 01076 if ((get_in_brackets_full(tmp, &out, NULL))) { 01077 return tmp; 01078 } 01079 return out; 01080 }
int get_in_brackets_const | ( | const char * | src, | |
const char ** | start, | |||
int * | length | |||
) |
Definition at line 951 of file reqresp_parser.c.
References ast_log(), ast_strlen_zero(), find_closing_quote(), LOG_WARNING, and parse().
Referenced by build_route().
00952 { 00953 const char *parse = src; 00954 const char *first_bracket; 00955 const char *second_bracket; 00956 00957 if (start == NULL) { 00958 return -1; 00959 } 00960 if (length == NULL) { 00961 return -1; 00962 } 00963 *start = NULL; 00964 *length = -1; 00965 if (ast_strlen_zero(src)) { 00966 return 1; 00967 } 00968 00969 /* 00970 * Skip any quoted text until we find the part in brackets. 00971 * On any error give up and return -1 00972 */ 00973 while ( (first_bracket = strchr(parse, '<')) ) { 00974 const char *first_quote = strchr(parse, '"'); 00975 first_bracket++; 00976 if (!first_quote || first_quote >= first_bracket) { 00977 break; /* no need to look at quoted part */ 00978 } 00979 /* the bracket is within quotes, so ignore it */ 00980 parse = find_closing_quote(first_quote + 1, NULL); 00981 if (!*parse) { 00982 ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src); 00983 return -1; 00984 } 00985 parse++; 00986 } 00987 00988 /* Require a first bracket. Unlike get_in_brackets_full, this procedure is passed a const, 00989 * so it can expect a pointer to an original value */ 00990 if (!first_bracket) { 00991 ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src); 00992 return 1; 00993 } 00994 00995 if ((second_bracket = strchr(first_bracket, '>'))) { 00996 *start = first_bracket; 00997 *length = second_bracket - first_bracket; 00998 return 0; 00999 } 01000 ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src); 01001 return -1; 01002 }
int get_in_brackets_full | ( | char * | tmp, | |
char ** | out, | |||
char ** | residue | |||
) |
Definition at line 1004 of file reqresp_parser.c.
References ast_log(), ast_strlen_zero(), find_closing_quote(), LOG_WARNING, and parse().
Referenced by get_in_brackets(), and parse_name_andor_addr().
01005 { 01006 const char *parse = tmp; 01007 char *first_bracket; 01008 char *second_bracket; 01009 01010 if (out) { 01011 *out = ""; 01012 } 01013 if (residue) { 01014 *residue = ""; 01015 } 01016 01017 if (ast_strlen_zero(tmp)) { 01018 return 1; 01019 } 01020 01021 /* 01022 * Skip any quoted text until we find the part in brackets. 01023 * On any error give up and return -1 01024 */ 01025 while ( (first_bracket = strchr(parse, '<')) ) { 01026 char *first_quote = strchr(parse, '"'); 01027 first_bracket++; 01028 if (!first_quote || first_quote >= first_bracket) { 01029 break; /* no need to look at quoted part */ 01030 } 01031 /* the bracket is within quotes, so ignore it */ 01032 parse = find_closing_quote(first_quote + 1, NULL); 01033 if (!*parse) { 01034 ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp); 01035 return -1; 01036 } 01037 parse++; 01038 } 01039 01040 /* If no first bracket then still look for a second bracket as some other parsing functions 01041 may overwrite first bracket with NULL when terminating a token based display-name. As this 01042 only affects token based display-names there is no danger of brackets being in quotes */ 01043 if (first_bracket) { 01044 parse = first_bracket; 01045 } else { 01046 parse = tmp; 01047 } 01048 01049 if ((second_bracket = strchr(parse, '>'))) { 01050 *second_bracket++ = '\0'; 01051 if (out) { 01052 *out = (char *) parse; 01053 } 01054 if (residue) { 01055 *residue = second_bracket; 01056 } 01057 return 0; 01058 } 01059 01060 if ((first_bracket)) { 01061 ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp); 01062 return -1; 01063 } 01064 01065 if (out) { 01066 *out = tmp; 01067 } 01068 01069 return 1; 01070 }
int get_name_and_number | ( | const char * | hdr, | |
char ** | name, | |||
char ** | number | |||
) |
Definition at line 806 of file reqresp_parser.c.
References ast_copy_string(), ast_log(), ast_strdup, ast_strlen_zero(), ast_uri_decode(), dummy(), get_calleridname(), get_in_brackets(), LOG_ERROR, and parse_uri().
Referenced by AST_TEST_DEFINE(), change_redirecting_information(), and get_pai().
00807 { 00808 char header[256]; 00809 char tmp_name[256]; 00810 char *tmp_number = NULL; 00811 char *hostport = NULL; 00812 char *dummy = NULL; 00813 00814 if (!name || !number || ast_strlen_zero(hdr)) { 00815 return -1; 00816 } 00817 00818 *number = NULL; 00819 *name = NULL; 00820 ast_copy_string(header, hdr, sizeof(header)); 00821 00822 /* strip the display-name portion off the beginning of the header. */ 00823 get_calleridname(header, tmp_name, sizeof(tmp_name)); 00824 00825 /* get uri within < > brackets */ 00826 tmp_number = get_in_brackets(header); 00827 00828 /* parse out the number here */ 00829 if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) { 00830 ast_log(LOG_ERROR, "can not parse name and number from sip header.\n"); 00831 return -1; 00832 } 00833 00834 /* number is not option, and must be present at this point */ 00835 *number = ast_strdup(tmp_number); 00836 ast_uri_decode(*number); 00837 00838 /* name is optional and may not be present at this point */ 00839 if (!ast_strlen_zero(tmp_name)) { 00840 *name = ast_strdup(tmp_name); 00841 } 00842 00843 return 0; 00844 }
int parse_contact_header | ( | char * | contactheader, | |
struct contactliststruct * | contactlist | |||
) |
Definition at line 1371 of file reqresp_parser.c.
References ast_calloc, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, get_comma(), last, parse_name_andor_addr(), and value.
Referenced by AST_TEST_DEFINE().
01372 { 01373 int res; 01374 int last; 01375 char *comma; 01376 char *residue; 01377 char *param; 01378 char *value; 01379 struct contact *split_contact = NULL; 01380 01381 if (*contactheader == '*') { 01382 return 1; 01383 } 01384 01385 split_contact = ast_calloc(1, sizeof(*split_contact)); 01386 01387 AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact); 01388 while ((last = get_comma(contactheader, &comma)) != -1) { 01389 res = parse_name_andor_addr(contactheader, "sip:,sips:", 01390 &split_contact->name, &split_contact->user, 01391 &split_contact->pass, &split_contact->hostport, 01392 &split_contact->params, &split_contact->headers, 01393 &residue); 01394 if (res == -1) { 01395 return res; 01396 } 01397 01398 /* parse contact params */ 01399 split_contact->expires = split_contact->q = ""; 01400 01401 while ((value = strchr(residue,'='))) { 01402 *value++ = '\0'; 01403 01404 param = residue; 01405 if ((residue = strchr(value,';'))) { 01406 *residue++ = '\0'; 01407 } else { 01408 residue = ""; 01409 } 01410 01411 if (!strcmp(param,"expires")) { 01412 split_contact->expires = value; 01413 } else if (!strcmp(param,"q")) { 01414 split_contact->q = value; 01415 } 01416 } 01417 01418 if (last) { 01419 return 0; 01420 } 01421 contactheader = comma; 01422 01423 split_contact = ast_calloc(1, sizeof(*split_contact)); 01424 AST_LIST_INSERT_TAIL(contactlist, split_contact, list); 01425 } 01426 return last; 01427 }
int parse_name_andor_addr | ( | char * | uri, | |
const char * | scheme, | |||
char ** | name, | |||
char ** | user, | |||
char ** | pass, | |||
char ** | hostport, | |||
struct uriparams * | params, | |||
char ** | headers, | |||
char ** | residue | |||
) |
Definition at line 1160 of file reqresp_parser.c.
References get_calleridname(), get_in_brackets_full(), and parse_uri_full().
Referenced by AST_TEST_DEFINE(), and parse_contact_header().
01164 { 01165 char buf[1024]; 01166 char **residue2 = residue; 01167 char *orig_uri = uri; 01168 int ret; 01169 01170 buf[0] = '\0'; 01171 if (name) { 01172 uri = (char *) get_calleridname(uri, buf, sizeof(buf)); 01173 } 01174 ret = get_in_brackets_full(uri, &uri, residue); 01175 if (ret == 0) { 01176 /* 01177 * The uri is in brackets so do not treat unknown trailing uri 01178 * parameters as potential message header parameters. 01179 */ 01180 if (residue && **residue) { 01181 /* step over the first semicolon as per parse_uri_full residue */ 01182 *residue = *residue + 1; 01183 } 01184 residue2 = NULL; 01185 } 01186 01187 if (name) { 01188 if (buf[0]) { 01189 /* 01190 * There is always room at orig_uri for the display-name because 01191 * at least one character has always been removed. A '"' or '<' 01192 * has been removed. 01193 */ 01194 strcpy(orig_uri, buf); 01195 *name = orig_uri; 01196 } else { 01197 *name = ""; 01198 } 01199 } 01200 01201 return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2); 01202 }
unsigned int parse_sip_options | ( | const char * | options, | |
char * | unsupported, | |||
size_t | unsupported_len | |||
) |
Parse supported header in incoming packet.
This function parses through the options parameters and builds a bit field representing all the SIP options in that field. When an item is found that is not supported, it is copied to the unsupported out buffer.
option | list | |
unsupported | out buffer (optional) | |
unsupported | out buffer length (optional) |
Definition at line 1587 of file reqresp_parser.c.
References ARRAY_LEN, ast_copy_string(), ast_debug, ast_strdupa, ast_strip(), ast_strlen_zero(), FALSE, text, and TRUE.
Referenced by AST_TEST_DEFINE(), handle_request_bye(), and handle_request_invite().
01588 { 01589 char *next, *sep; 01590 char *temp; 01591 int i, found, supported; 01592 unsigned int profile = 0; 01593 01594 char *out = unsupported; 01595 size_t outlen = unsupported_len; 01596 char *cur_out = out; 01597 01598 if (ast_strlen_zero(options) ) 01599 return 0; 01600 01601 temp = ast_strdupa(options); 01602 01603 ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options); 01604 for (next = temp; next; next = sep) { 01605 found = FALSE; 01606 supported = FALSE; 01607 if ((sep = strchr(next, ',')) != NULL) { 01608 *sep++ = '\0'; 01609 } 01610 01611 /* trim leading and trailing whitespace */ 01612 next = ast_strip(next); 01613 01614 if (ast_strlen_zero(next)) { 01615 continue; /* if there is a blank argument in there just skip it */ 01616 } 01617 01618 ast_debug(3, "Found SIP option: -%s-\n", next); 01619 for (i = 0; i < ARRAY_LEN(sip_options); i++) { 01620 if (!strcasecmp(next, sip_options[i].text)) { 01621 profile |= sip_options[i].id; 01622 if (sip_options[i].supported == SUPPORTED) { 01623 supported = TRUE; 01624 } 01625 found = TRUE; 01626 ast_debug(3, "Matched SIP option: %s\n", next); 01627 break; 01628 } 01629 } 01630 01631 /* If option is not supported, add to unsupported out buffer */ 01632 if (!supported && out && outlen) { 01633 size_t copylen = strlen(next); 01634 size_t cur_outlen = strlen(out); 01635 /* Check to see if there is enough room to store this option. 01636 * Copy length is string length plus 2 for the ',' and '\0' */ 01637 if ((cur_outlen + copylen + 2) < outlen) { 01638 /* if this isn't the first item, add the ',' */ 01639 if (cur_outlen) { 01640 *cur_out = ','; 01641 cur_out++; 01642 cur_outlen++; 01643 } 01644 ast_copy_string(cur_out, next, (outlen - cur_outlen)); 01645 cur_out += copylen; 01646 } 01647 } 01648 01649 if (!found) { 01650 profile |= SIP_OPT_UNKNOWN; 01651 if (!strncasecmp(next, "x-", 2)) 01652 ast_debug(3, "Found private SIP option, not supported: %s\n", next); 01653 else 01654 ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next); 01655 } 01656 } 01657 01658 return profile; 01659 }
int parse_uri | ( | char * | uri, | |
const char * | scheme, | |||
char ** | user, | |||
char ** | pass, | |||
char ** | hostport, | |||
char ** | transport | |||
) |
Definition at line 434 of file reqresp_parser.c.
References parse_uri_full().
Referenced by AST_TEST_DEFINE(), get_name_and_number(), and parse_uri_legacy_check().
00435 { 00436 int ret; 00437 char *headers; 00438 struct uriparams params; 00439 00440 headers = NULL; 00441 ret = parse_uri_full(uri, scheme, user, pass, hostport, ¶ms, &headers, NULL); 00442 if (transport) { 00443 *transport=params.transport; 00444 } 00445 return ret; 00446 }
int parse_uri_full | ( | char * | uri, | |
const char * | scheme, | |||
char ** | user, | |||
char ** | pass, | |||
char ** | hostport, | |||
struct uriparams * | params, | |||
char ** | headers, | |||
char ** | residue | |||
) |
* parses a URI in its components.
Definition at line 39 of file reqresp_parser.c.
References ast_debug, ast_strdupa, ast_strlen_zero(), and value.
Referenced by AST_TEST_DEFINE(), parse_name_andor_addr(), and parse_uri().
00042 { 00043 char *userinfo = NULL; 00044 char *parameters = NULL; 00045 char *endparams = NULL; 00046 char *c = NULL; 00047 int error = 0; 00048 00049 /* 00050 * Initialize requested strings - some functions don't care if parse_uri fails 00051 * and will attempt to use string pointers passed into parse_uri even after a 00052 * parse_uri failure 00053 */ 00054 if (user) { 00055 *user = ""; 00056 } 00057 if (pass) { 00058 *pass = ""; 00059 } 00060 if (hostport) { 00061 *hostport = ""; 00062 } 00063 if (headers) { 00064 *headers = ""; 00065 } 00066 if (residue) { 00067 *residue = ""; 00068 } 00069 00070 /* check for valid input */ 00071 if (ast_strlen_zero(uri)) { 00072 return -1; 00073 } 00074 00075 if (scheme) { 00076 int l; 00077 char *scheme2 = ast_strdupa(scheme); 00078 char *cur = strsep(&scheme2, ","); 00079 for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) { 00080 l = strlen(cur); 00081 if (!strncasecmp(uri, cur, l)) { 00082 uri += l; 00083 break; 00084 } 00085 } 00086 if (ast_strlen_zero(cur)) { 00087 ast_debug(1, "No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme); 00088 error = -1; 00089 } 00090 } 00091 00092 if (!hostport) { 00093 /* if we don't want to split around hostport, keep everything as a 00094 * userinfo - cos thats how old parse_uri operated*/ 00095 userinfo = uri; 00096 } else { 00097 char *dom = ""; 00098 if ((c = strchr(uri, '@'))) { 00099 *c++ = '\0'; 00100 dom = c; 00101 userinfo = uri; 00102 uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */ 00103 } else { 00104 /* domain-only URI, according to the SIP RFC. */ 00105 dom = uri; 00106 userinfo = ""; 00107 } 00108 00109 *hostport = dom; 00110 } 00111 00112 if (pass && (c = strchr(userinfo, ':'))) { /* user:password */ 00113 *c++ = '\0'; 00114 *pass = c; 00115 } else if (pass) { 00116 *pass = ""; 00117 } 00118 00119 if (user) { 00120 *user = userinfo; 00121 } 00122 00123 parameters = uri; 00124 /* strip [?headers] from end of uri - even if no header pointer exists*/ 00125 if ((c = strrchr(uri, '?'))) { 00126 *c++ = '\0'; 00127 uri = c; 00128 if (headers) { 00129 *headers = c; 00130 } 00131 if ((c = strrchr(uri, ';'))) { 00132 *c++ = '\0'; 00133 } else { 00134 c = strrchr(uri, '\0'); 00135 } 00136 uri = c; /* residue */ 00137 00138 00139 } else if (headers) { 00140 *headers = ""; 00141 } 00142 00143 /* parse parameters */ 00144 endparams = strchr(parameters,'\0'); 00145 if ((c = strchr(parameters, ';'))) { 00146 *c++ = '\0'; 00147 parameters = c; 00148 } else { 00149 parameters = endparams; 00150 } 00151 00152 if (params) { 00153 char *rem = parameters; /* unparsed or unrecognised remainder */ 00154 char *label; 00155 char *value; 00156 int lr = 0; 00157 00158 params->transport = ""; 00159 params->user = ""; 00160 params->method = ""; 00161 params->ttl = ""; 00162 params->maddr = ""; 00163 params->lr = 0; 00164 00165 rem = parameters; 00166 00167 while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) { 00168 /* The while condition will not continue evaluation to set lr if it matches "lr=" */ 00169 if (lr) { 00170 value = parameters; 00171 } else { 00172 *value++ = '\0'; 00173 } 00174 label = parameters; 00175 if ((c = strchr(value, ';'))) { 00176 *c++ = '\0'; 00177 parameters = c; 00178 } else { 00179 parameters = endparams; 00180 } 00181 00182 if (!strcmp(label, "transport")) { 00183 params->transport = value; 00184 rem = parameters; 00185 } else if (!strcmp(label, "user")) { 00186 params->user = value; 00187 rem = parameters; 00188 } else if (!strcmp(label, "method")) { 00189 params->method = value; 00190 rem = parameters; 00191 } else if (!strcmp(label, "ttl")) { 00192 params->ttl = value; 00193 rem = parameters; 00194 } else if (!strcmp(label, "maddr")) { 00195 params->maddr = value; 00196 rem = parameters; 00197 /* Treat "lr", "lr=yes", "lr=on", "lr=1", "lr=almostanything" as lr enabled and "", "lr=no", "lr=off", "lr=0", "lr=" and "lranything" as lr disabled */ 00198 } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) { 00199 params->lr = 1; 00200 rem = parameters; 00201 } else { 00202 value--; 00203 *value = '='; 00204 if (c) { 00205 c--; 00206 *c = ';'; 00207 } 00208 } 00209 } 00210 if (rem > uri) { /* no headers */ 00211 uri = rem; 00212 } 00213 00214 } 00215 00216 if (residue) { 00217 *residue = uri; 00218 } 00219 00220 return error; 00221 }
struct sip_via* parse_via | ( | const char * | header | ) | [read] |
Definition at line 2279 of file reqresp_parser.c.
References ast_calloc, ast_log(), ast_skip_blanks(), ast_strdup, ast_strlen_zero(), free_via(), and LOG_ERROR.
Referenced by AST_TEST_DEFINE(), find_call(), process_via(), and sip_alloc().
02280 { 02281 struct sip_via *v = ast_calloc(1, sizeof(*v)); 02282 char *via, *parm; 02283 02284 if (!v) { 02285 return NULL; 02286 } 02287 02288 v->via = ast_strdup(header); 02289 v->ttl = 1; 02290 02291 via = v->via; 02292 02293 if (ast_strlen_zero(via)) { 02294 ast_log(LOG_ERROR, "received request without a Via header\n"); 02295 free_via(v); 02296 return NULL; 02297 } 02298 02299 /* seperate the first via-parm */ 02300 via = strsep(&via, ","); 02301 02302 /* chop off sent-protocol */ 02303 v->protocol = strsep(&via, " \t\r\n"); 02304 if (ast_strlen_zero(v->protocol)) { 02305 ast_log(LOG_ERROR, "missing sent-protocol in Via header\n"); 02306 free_via(v); 02307 return NULL; 02308 } 02309 v->protocol = ast_skip_blanks(v->protocol); 02310 02311 if (via) { 02312 via = ast_skip_blanks(via); 02313 } 02314 02315 /* chop off sent-by */ 02316 v->sent_by = strsep(&via, "; \t\r\n"); 02317 if (ast_strlen_zero(v->sent_by)) { 02318 ast_log(LOG_ERROR, "missing sent-by in Via header\n"); 02319 free_via(v); 02320 return NULL; 02321 } 02322 v->sent_by = ast_skip_blanks(v->sent_by); 02323 02324 /* store the port, we have to handle ipv6 addresses containing ':' 02325 * characters gracefully */ 02326 if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) { 02327 char *endptr; 02328 02329 v->port = strtol(++parm, &endptr, 10); 02330 } 02331 02332 /* evaluate any via-parms */ 02333 while ((parm = strsep(&via, "; \t\r\n"))) { 02334 char *c; 02335 if ((c = strstr(parm, "maddr="))) { 02336 v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1); 02337 } else if ((c = strstr(parm, "branch="))) { 02338 v->branch = ast_skip_blanks(c + sizeof("branch=") - 1); 02339 } else if ((c = strstr(parm, "ttl="))) { 02340 char *endptr; 02341 c = ast_skip_blanks(c + sizeof("ttl=") - 1); 02342 v->ttl = strtol(c, &endptr, 10); 02343 02344 /* make sure we got a valid ttl value */ 02345 if (c == endptr) { 02346 v->ttl = 1; 02347 } 02348 } 02349 } 02350 02351 return v; 02352 }
void sip_reqresp_parser_exit | ( | void | ) |
Definition at line 2570 of file reqresp_parser.c.
Referenced by unload_module().
int sip_reqresp_parser_init | ( | void | ) |
Definition at line 2559 of file reqresp_parser.c.
Referenced by load_module().
void sip_request_parser_register_tests | ( | void | ) |
Definition at line 2532 of file reqresp_parser.c.
References AST_TEST_REGISTER.
Referenced by sip_register_tests().
02533 { 02534 AST_TEST_REGISTER(get_calleridname_test); 02535 AST_TEST_REGISTER(sip_parse_uri_test); 02536 AST_TEST_REGISTER(get_in_brackets_test); 02537 AST_TEST_REGISTER(get_name_and_number_test); 02538 AST_TEST_REGISTER(sip_parse_uri_full_test); 02539 AST_TEST_REGISTER(parse_name_andor_addr_test); 02540 AST_TEST_REGISTER(parse_contact_header_test); 02541 AST_TEST_REGISTER(sip_parse_options_test); 02542 AST_TEST_REGISTER(sip_uri_cmp_test); 02543 AST_TEST_REGISTER(parse_via_test); 02544 }
void sip_request_parser_unregister_tests | ( | void | ) |
Definition at line 2545 of file reqresp_parser.c.
References AST_TEST_UNREGISTER.
Referenced by sip_unregister_tests().
02546 { 02547 AST_TEST_UNREGISTER(sip_parse_uri_test); 02548 AST_TEST_UNREGISTER(get_calleridname_test); 02549 AST_TEST_UNREGISTER(get_in_brackets_test); 02550 AST_TEST_UNREGISTER(get_name_and_number_test); 02551 AST_TEST_UNREGISTER(sip_parse_uri_full_test); 02552 AST_TEST_UNREGISTER(parse_name_andor_addr_test); 02553 AST_TEST_UNREGISTER(parse_contact_header_test); 02554 AST_TEST_UNREGISTER(sip_parse_options_test); 02555 AST_TEST_UNREGISTER(sip_uri_cmp_test); 02556 AST_TEST_UNREGISTER(parse_via_test); 02557 }
int sip_uri_cmp | ( | const char * | input1, | |
const char * | input2 | |||
) |
Definition at line 2045 of file reqresp_parser.c.
References ast_strdupa, ast_strlen_zero(), ast_uri_decode(), S_OR, sip_uri_domain_cmp(), sip_uri_headers_cmp(), and sip_uri_params_cmp().
Referenced by AST_TEST_DEFINE(), find_by_notify_uri_helper(), find_by_subscribe_uri_helper(), handle_request_invite(), and match_req_to_dialog().
02046 { 02047 char *uri1; 02048 char *uri2; 02049 char *uri_scheme1; 02050 char *uri_scheme2; 02051 char *host1; 02052 char *host2; 02053 char *params1; 02054 char *params2; 02055 char *headers1; 02056 char *headers2; 02057 02058 /* XXX It would be really nice if we could just use parse_uri_full() here 02059 * to separate the components of the URI, but unfortunately it is written 02060 * in a way that can cause URI parameters to be discarded. 02061 */ 02062 02063 if (!input1 || !input2) { 02064 return 1; 02065 } 02066 02067 uri1 = ast_strdupa(input1); 02068 uri2 = ast_strdupa(input2); 02069 02070 ast_uri_decode(uri1); 02071 ast_uri_decode(uri2); 02072 02073 uri_scheme1 = strsep(&uri1, ":"); 02074 uri_scheme2 = strsep(&uri2, ":"); 02075 02076 if (strcmp(uri_scheme1, uri_scheme2)) { 02077 return 1; 02078 } 02079 02080 /* This function is tailored for SIP and SIPS URIs. There's no 02081 * need to check uri_scheme2 since we have determined uri_scheme1 02082 * and uri_scheme2 are equivalent already. 02083 */ 02084 if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) { 02085 return 1; 02086 } 02087 02088 if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) { 02089 return 1; 02090 } 02091 02092 if ((host1 = strchr(uri1, '@'))) { 02093 *host1++ = '\0'; 02094 } 02095 if ((host2 = strchr(uri2, '@'))) { 02096 *host2++ = '\0'; 02097 } 02098 02099 /* Check for mismatched username and passwords. This is the 02100 * only case-sensitive comparison of a SIP URI 02101 */ 02102 if ((host1 && !host2) || 02103 (host2 && !host1) || 02104 (host1 && host2 && strcmp(uri1, uri2))) { 02105 return 1; 02106 } 02107 02108 if (!host1) { 02109 host1 = uri1; 02110 } 02111 if (!host2) { 02112 host2 = uri2; 02113 } 02114 02115 /* Strip off the parameters and headers so we can compare 02116 * host and port 02117 */ 02118 02119 if ((params1 = strchr(host1, ';'))) { 02120 *params1++ = '\0'; 02121 } 02122 if ((params2 = strchr(host2, ';'))) { 02123 *params2++ = '\0'; 02124 } 02125 02126 /* Headers come after parameters, but there may be headers without 02127 * parameters, thus the S_OR 02128 */ 02129 if ((headers1 = strchr(S_OR(params1, host1), '?'))) { 02130 *headers1++ = '\0'; 02131 } 02132 if ((headers2 = strchr(S_OR(params2, host2), '?'))) { 02133 *headers2++ = '\0'; 02134 } 02135 02136 if (sip_uri_domain_cmp(host1, host2)) { 02137 return 1; 02138 } 02139 02140 /* Headers have easier rules to follow, so do those first */ 02141 if (sip_uri_headers_cmp(headers1, headers2)) { 02142 return 1; 02143 } 02144 02145 /* And now the parameters. Ugh */ 02146 return sip_uri_params_cmp(params1, params2); 02147 }
static int sip_uri_domain_cmp | ( | const char * | host1, | |
const char * | host2 | |||
) | [static] |
Compare domain sections of SIP URIs.
For hostnames, a case insensitive string comparison is used. For IP addresses, a binary comparison is used. This is mainly because IPv6 addresses have many ways of writing the same address.
For specifics about IP address comparison, see the following document: http://tools.ietf.org/html/draft-ietf-sip-ipv6-abnf-fix-05
host1 | The domain from the first URI | |
host2 | THe domain from the second URI |
0 | The domains match | |
nonzero | The domains do not match |
Definition at line 2007 of file reqresp_parser.c.
References ast_sockaddr_cmp(), and ast_sockaddr_parse().
Referenced by sip_uri_cmp().
02008 { 02009 struct ast_sockaddr addr1; 02010 struct ast_sockaddr addr2; 02011 int addr1_parsed; 02012 int addr2_parsed; 02013 02014 addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0); 02015 addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0); 02016 02017 if (addr1_parsed != addr2_parsed) { 02018 /* One domain was an IP address and the other had 02019 * a host name. FAIL! 02020 */ 02021 return 1; 02022 } 02023 02024 /* Both are host names. A string comparison will work 02025 * perfectly here. Specifying the "C" locale ensures that 02026 * The LC_CTYPE conventions use those defined in ANSI C, 02027 * i.e. ASCII. 02028 */ 02029 if (!addr1_parsed) { 02030 #ifdef HAVE_XLOCALE_H 02031 if(!c_locale) { 02032 return strcasecmp(host1, host2); 02033 } else { 02034 return strcasecmp_l(host1, host2, c_locale); 02035 } 02036 #else 02037 return strcasecmp(host1, host2); 02038 #endif 02039 } 02040 02041 /* Both contain IP addresses */ 02042 return ast_sockaddr_cmp(&addr1, &addr2); 02043 }
static int sip_uri_headers_cmp | ( | const char * | input1, | |
const char * | input2 | |||
) | [static] |
helper routine for sip_uri_cmp to compare URI headers
This takes the headers from two SIP URIs and determines if the URIs match. The rules for headers is simple. If a header appears in one URI, then it must also appear in the other URI. The order in which the headers appear does not matter.
input1 | Headers from URI 1 | |
input2 | Headers from URI 2 |
0 | URI headers match | |
nonzero | URI headers do not match |
Definition at line 1942 of file reqresp_parser.c.
References ast_strdupa, and ast_strlen_zero().
Referenced by sip_uri_cmp().
01943 { 01944 char *headers1 = NULL; 01945 char *headers2 = NULL; 01946 int zerolength1 = 0; 01947 int zerolength2 = 0; 01948 int different = 0; 01949 char *header1; 01950 01951 if (ast_strlen_zero(input1)) { 01952 zerolength1 = 1; 01953 } else { 01954 headers1 = ast_strdupa(input1); 01955 } 01956 01957 if (ast_strlen_zero(input2)) { 01958 zerolength2 = 1; 01959 } else { 01960 headers2 = ast_strdupa(input2); 01961 } 01962 01963 /* If one URI contains no headers and the other 01964 * does, then they cannot possibly match 01965 */ 01966 if (zerolength1 != zerolength2) { 01967 return 1; 01968 } 01969 01970 if (zerolength1 && zerolength2) 01971 return 0; 01972 01973 /* At this point, we can definitively state that both inputs are 01974 * not zero-length. First, one more optimization. If the length 01975 * of the headers is not equal, then we definitely have no match 01976 */ 01977 if (strlen(headers1) != strlen(headers2)) { 01978 return 1; 01979 } 01980 01981 for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) { 01982 if (!strcasestr(headers2, header1)) { 01983 different = 1; 01984 break; 01985 } 01986 } 01987 01988 return different; 01989 }
static int sip_uri_params_cmp | ( | const char * | input1, | |
const char * | input2 | |||
) | [static] |
helper routine for sip_uri_cmp to compare URI parameters
This takes the parameters from two SIP URIs and determines if the URIs match. The rules for parameters *suck*. Here's a breakdown 1. If a parameter appears in both URIs, then they must have the same value in order for the URIs to match 2. If one URI has a user, maddr, ttl, or method parameter, then the other URI must also have that parameter and must have the same value in order for the URIs to match 3. All other headers appearing in only one URI are not considered when determining if URIs match
input1 | Parameters from URI 1 | |
input2 | Parameters from URI 2 |
0 | URIs' parameters match | |
nonzero | URIs' parameters do not match |
Definition at line 1816 of file reqresp_parser.c.
References ast_strdupa, and ast_strlen_zero().
Referenced by sip_uri_cmp().
01817 { 01818 char *params1 = NULL; 01819 char *params2 = NULL; 01820 char *pos1; 01821 char *pos2; 01822 int zerolength1 = 0; 01823 int zerolength2 = 0; 01824 int maddrmatch = 0; 01825 int ttlmatch = 0; 01826 int usermatch = 0; 01827 int methodmatch = 0; 01828 01829 if (ast_strlen_zero(input1)) { 01830 zerolength1 = 1; 01831 } else { 01832 params1 = ast_strdupa(input1); 01833 } 01834 if (ast_strlen_zero(input2)) { 01835 zerolength2 = 1; 01836 } else { 01837 params2 = ast_strdupa(input2); 01838 } 01839 01840 /* Quick optimization. If both params are zero-length, then 01841 * they match 01842 */ 01843 if (zerolength1 && zerolength2) { 01844 return 0; 01845 } 01846 01847 for (pos1 = strsep(¶ms1, ";"); pos1; pos1 = strsep(¶ms1, ";")) { 01848 char *value1 = pos1; 01849 char *name1 = strsep(&value1, "="); 01850 char *params2dup = NULL; 01851 int matched = 0; 01852 if (!value1) { 01853 value1 = ""; 01854 } 01855 /* Checkpoint reached. We have the name and value parsed for param1 01856 * We have to duplicate params2 each time through this loop 01857 * or else the inner loop below will not work properly. 01858 */ 01859 if (!zerolength2) { 01860 params2dup = ast_strdupa(params2); 01861 } 01862 for (pos2 = strsep(¶ms2dup, ";"); pos2; pos2 = strsep(¶ms2dup, ";")) { 01863 char *name2 = pos2; 01864 char *value2 = strchr(pos2, '='); 01865 if (!value2) { 01866 value2 = ""; 01867 } else { 01868 *value2++ = '\0'; 01869 } 01870 if (!strcasecmp(name1, name2)) { 01871 if (strcasecmp(value1, value2)) { 01872 goto fail; 01873 } else { 01874 matched = 1; 01875 break; 01876 } 01877 } 01878 } 01879 /* Check to see if the parameter is one of the 'must-match' parameters */ 01880 if (!strcasecmp(name1, "maddr")) { 01881 if (matched) { 01882 maddrmatch = 1; 01883 } else { 01884 goto fail; 01885 } 01886 } else if (!strcasecmp(name1, "ttl")) { 01887 if (matched) { 01888 ttlmatch = 1; 01889 } else { 01890 goto fail; 01891 } 01892 } else if (!strcasecmp(name1, "user")) { 01893 if (matched) { 01894 usermatch = 1; 01895 } else { 01896 goto fail; 01897 } 01898 } else if (!strcasecmp(name1, "method")) { 01899 if (matched) { 01900 methodmatch = 1; 01901 } else { 01902 goto fail; 01903 } 01904 } 01905 } 01906 01907 /* We've made it out of that horrible O(m*n) construct and there are no 01908 * failures yet. We're not done yet, though, because params2 could have 01909 * an maddr, ttl, user, or method header and params1 did not. 01910 */ 01911 for (pos2 = strsep(¶ms2, ";"); pos2; pos2 = strsep(¶ms2, ";")) { 01912 char *value2 = pos2; 01913 char *name2 = strsep(&value2, "="); 01914 if (!value2) { 01915 value2 = ""; 01916 } 01917 if ((!strcasecmp(name2, "maddr") && !maddrmatch) || 01918 (!strcasecmp(name2, "ttl") && !ttlmatch) || 01919 (!strcasecmp(name2, "user") && !usermatch) || 01920 (!strcasecmp(name2, "method") && !methodmatch)) { 01921 goto fail; 01922 } 01923 } 01924 return 0; 01925 01926 fail: 01927 return 1; 01928 }