30 #include "include/sip.h"
31 #include "include/sip_utils.h"
32 #include "include/reqresp_parser.h"
40 char **hostport,
struct uriparams *params,
char **headers,
43 char *userinfo = NULL;
44 char *parameters = NULL;
45 char *endparams = NULL;
78 char *cur =
strsep(&scheme2,
",");
81 if (!strncasecmp(uri, cur, l)) {
87 ast_debug(1,
"No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme);
98 if ((c = strchr(uri,
'@'))) {
112 if (pass && (c = strchr(userinfo,
':'))) {
125 if ((c = strrchr(uri,
'?'))) {
131 if ((c = strrchr(uri,
';'))) {
134 c = strrchr(uri,
'\0');
139 }
else if (headers) {
144 endparams = strchr(parameters,
'\0');
145 if ((c = strchr(parameters,
';'))) {
149 parameters = endparams;
153 char *rem = parameters;
158 params->transport =
"";
167 while ((value = strchr(parameters,
'=')) || (lr = !strncmp(parameters,
"lr", 2))) {
175 if ((c = strchr(value,
';'))) {
179 parameters = endparams;
182 if (!strcmp(label,
"transport")) {
183 params->transport =
value;
185 }
else if (!strcmp(label,
"user")) {
186 params->user =
value;
188 }
else if (!strcmp(label,
"method")) {
189 params->method =
value;
191 }
else if (!strcmp(label,
"ttl")) {
194 }
else if (!strcmp(label,
"maddr")) {
195 params->maddr =
value;
198 }
else if ((!strcmp(label,
"lr") && strcmp(value,
"no") && strcmp(value,
"off") && strcmp(value,
"0") && strcmp(value,
"")) || ((lr) && strcmp(value,
"lr"))) {
228 char *
user, *
pass, *hostport, *headers, *residue;
229 struct uriparams params;
239 struct uriparams params;
244 struct testdata *testdataptr;
248 struct testdata td1 = {
249 .desc =
"no headers",
250 .uri =
"sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue",
253 .hostport =
"host:5060",
255 .residue =
"param2=residue",
256 .params.transport =
"tcp",
261 struct testdata td2 = {
262 .desc =
"with headers",
263 .uri =
"sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
266 .hostport =
"host:5060",
267 .headers =
"header=blah&header2=blah2",
268 .residue =
"param3=residue",
269 .params.transport =
"tcp",
274 struct testdata td3 = {
275 .desc =
"difficult user",
276 .uri =
"sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp",
277 .user =
"-_.!~*'()&=+$,;?/",
279 .hostport =
"host:5060",
282 .params.transport =
"tcp",
287 struct testdata td4 = {
288 .desc =
"difficult pass",
289 .uri =
"sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp",
291 .pass =
"-_.!~*'()&=+$,",
292 .hostport =
"host:5060",
295 .params.transport =
"tcp",
300 struct testdata td5 = {
301 .desc =
"difficult host",
302 .uri =
"sip:user:secret@1-1.a-1.:5060;transport=tcp",
305 .hostport =
"1-1.a-1.:5060",
308 .params.transport =
"tcp",
313 struct testdata td6 = {
314 .desc =
"difficult params near transport",
315 .uri =
"sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
318 .hostport =
"host:5060",
321 .params.transport =
"tcp",
326 struct testdata td7 = {
327 .desc =
"difficult params near headers",
328 .uri =
"sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
331 .hostport =
"host:5060",
332 .headers =
"header=blah&header2=blah2",
333 .residue =
"-_.!~*'()[]/:&+$=residue",
334 .params.transport =
"",
339 struct testdata td8 = {
340 .desc =
"lr parameter",
341 .uri =
"sip:user:secret@host:5060;param=discard;lr?header=blah",
344 .hostport =
"host:5060",
345 .headers =
"header=blah",
347 .params.transport =
"",
352 struct testdata td9 = {
353 .desc =
"alternative lr parameter",
354 .uri =
"sip:user:secret@host:5060;param=discard;lr=yes?header=blah",
357 .hostport =
"host:5060",
358 .headers =
"header=blah",
360 .params.transport =
"",
365 struct testdata td10 = {
366 .desc =
"no lr parameter",
367 .uri =
"sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
370 .hostport =
"host:5060",
371 .headers =
"header=blah",
373 .params.transport =
"",
393 info->name =
"sip_uri_full_parse_test";
394 info->category =
"/channels/chan_sip/";
395 info->summary =
"tests sip full uri parsing";
397 "Tests full parsing of various URIs "
398 "Verifies output matches expected behavior.";
405 user = pass = hostport = headers = residue = NULL;
406 params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
415 (user && strcmp(testdataptr->user, user)) ||
416 (pass && strcmp(testdataptr->pass, pass)) ||
417 (hostport && strcmp(testdataptr->hostport, hostport)) ||
418 (headers && strcmp(testdataptr->headers, headers)) ||
419 (residue && strcmp(testdataptr->residue, residue)) ||
420 (strcmp(testdataptr->params.transport,params.transport)) ||
421 (testdataptr->params.lr != params.lr) ||
422 (strcmp(testdataptr->params.user,params.user))
435 char **hostport,
char **transport) {
438 struct uriparams params;
441 ret =
parse_uri_full(uri, scheme, user, pass, hostport, ¶ms, &headers, NULL);
443 *transport=params.transport;
451 char *
name, *
pass, *hostport, *transport;
452 char uri1[] =
"sip:name@host";
453 char uri2[] =
"sip:name@host;transport=tcp";
454 char uri3[] =
"sip:name:secret@host;transport=tcp";
455 char uri4[] =
"sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
457 char uri6[] =
"sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
458 char uri7[] =
"sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
459 char uri8[] =
"sip:host";
460 char uri9[] =
"sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
461 char uri10[] =
"host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
462 char uri11[] =
"host";
466 info->name =
"sip_uri_parse_test";
467 info->category =
"/channels/chan_sip/";
468 info->summary =
"tests sip uri parsing";
470 "Tests parsing of various URIs "
471 "Verifies output matches expected behavior.";
478 name = pass = hostport = transport = NULL;
479 if (
parse_uri(uri1,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
480 strcmp(name,
"name") ||
482 strcmp(hostport,
"host") ||
489 name = pass = hostport = transport = NULL;
490 if (
parse_uri(uri2,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
491 strcmp(name,
"name") ||
493 strcmp(hostport,
"host") ||
494 strcmp(transport,
"tcp")) {
500 name = pass = hostport = transport = NULL;
501 if (
parse_uri(uri3,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
502 strcmp(name,
"name") ||
503 strcmp(pass,
"secret") ||
504 strcmp(hostport,
"host") ||
505 strcmp(transport,
"tcp")) {
511 name = pass = hostport = transport = NULL;
512 if (
parse_uri(uri4,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
513 strcmp(name,
"name") ||
514 strcmp(pass,
"secret") ||
515 strcmp(hostport,
"host:port") ||
516 strcmp(transport,
"tcp")) {
522 name = pass = hostport = transport = NULL;
523 if (!
parse_uri(NULL,
"sip:,sips:", &name, &pass, &hostport, &transport)) {
529 name = pass = hostport = transport = NULL;
530 if (
parse_uri(uri6,
"sip:,sips:", NULL, NULL, NULL, NULL)) {
536 name = pass = hostport = transport = NULL;
537 if (
parse_uri(uri7,
"sip:,sips:", &name, NULL, &hostport, NULL) ||
538 strcmp(name,
"name:secret") ||
539 strcmp(hostport,
"host:port")) {
546 name = pass = hostport = transport = NULL;
547 if (
parse_uri(uri8,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
548 strcmp(hostport,
"host") ||
555 name = pass = hostport = transport = NULL;
556 if (
parse_uri(uri9,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
559 strcmp(hostport,
"host:port") ||
560 strcmp(transport,
"tcp")) {
568 name = pass = hostport = transport = NULL;
569 if (!
parse_uri(uri10,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
572 strcmp(hostport,
"host:port") ||
573 strcmp(transport,
"tcp")) {
581 name = pass = hostport = transport = NULL;
582 if (!
parse_uri(uri11,
"sip:,sips:", &name, &pass, &hostport, &transport) ||
585 strcmp(hostport,
"host") ||
623 char *orig_output = output;
624 const char *orig_input =
input;
626 if (!output || !outputsize) {
641 if (!input || *input ==
'<') {
646 if (input[0] ==
'"') {
652 }
else if (*input == 0x5c) {
657 if ((
unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
660 }
else if ((*input != 0x9 && (
unsigned char) *input < 0x20)
665 if (0 < outputsize) {
687 if ((*input >=
'0' && *input <=
'9') || (*input >=
'A' && *input <=
'Z')
688 || (*input >=
'a' && *input <=
'z') || *input ==
'-' || *input ==
'.'
689 || *input ==
'!' || *input ==
'%' || *input ==
'*' || *input ==
'_'
690 || *input ==
'+' || *input ==
'`' || *input ==
'\'' || *input ==
'~'
691 || *input == 0x9 || *input ==
' ') {
692 if (0 < outputsize) {
697 }
else if (*input ==
'<') {
700 }
else if (*input ==
':') {
717 }
while (orig_output <= output && (*output == 0x9 || *output ==
' '));
726 const char *in1 =
" \" quoted-text internal \\\" quote \"<stuff>";
727 const char *in2 =
" token text with no quotes <stuff>";
728 const char *overflow1 =
" \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
729 const char *overflow2 =
" non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
730 const char *noendquote =
" \"quoted-text no end <stuff>";
731 const char *addrspec =
" sip:blah@blah";
732 const char *no_quotes_no_brackets =
"blah@blah";
733 const char *after_dname;
738 info->name =
"sip_get_calleridname_test";
739 info->category =
"/channels/chan_sip/";
740 info->summary =
"decodes callerid name from sip header";
741 info->description =
"Decodes display-name field of sip header. Checks for valid output and expected failure cases.";
750 if (strcmp(dname,
" quoted-text internal \" quote ")) {
758 if (strcmp(dname,
"token text with no quotes")) {
766 if (strcmp(dname,
"quoted-text overflow 123456789012345678")) {
774 if (strcmp(dname,
"non-quoted text overflow 12345678901234")) {
782 if (*dname !=
'\0' && after_dname != noendquote) {
790 if (*dname !=
'\0' && after_dname != addrspec) {
796 after_dname =
get_calleridname(no_quotes_no_brackets, dname,
sizeof(dname));
798 if (*dname !=
'\0' && after_dname != no_quotes_no_brackets) {
810 char *tmp_number = NULL;
811 char *hostport = NULL;
851 const char *in1 =
"NAME <sip:NUMBER@place>";
852 const char *in2 =
"\"NA><ME\" <sip:NUMBER@place>";
853 const char *in3 =
"NAME";
854 const char *in4 =
"<sip:NUMBER@place>";
855 const char *in5 =
"This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
859 info->name =
"sip_get_name_and_number_test";
860 info->category =
"/channels/chan_sip/";
861 info->summary =
"Tests getting name and number from sip header";
863 "Runs through various test situations in which a name and "
864 "and number can be retrieved from a sip header.";
871 number = name = NULL;
873 strcmp(name,
"NAME") ||
874 strcmp(number,
"NUMBER")) {
883 number = name = NULL;
885 strcmp(name,
"NA><ME") ||
886 strcmp(number,
"NUMBER")) {
895 number = name = NULL;
905 number = name = NULL;
908 strcmp(number,
"NUMBER")) {
917 number = name = NULL;
929 number = name = NULL;
937 number = name = NULL;
953 const char *
parse = src;
954 const char *first_bracket;
955 const char *second_bracket;
960 if (length == NULL) {
973 while ( (first_bracket = strchr(parse,
'<')) ) {
974 const char *first_quote = strchr(parse,
'"');
976 if (!first_quote || first_quote >= first_bracket) {
990 if (!first_bracket) {
995 if ((second_bracket = strchr(first_bracket,
'>'))) {
996 *start = first_bracket;
997 *length = second_bracket - first_bracket;
1006 const char *
parse = tmp;
1007 char *first_bracket;
1008 char *second_bracket;
1025 while ( (first_bracket = strchr(parse,
'<')) ) {
1026 char *first_quote = strchr(parse,
'"');
1028 if (!first_quote || first_quote >= first_bracket) {
1043 if (first_bracket) {
1044 parse = first_bracket;
1049 if ((second_bracket = strchr(parse,
'>'))) {
1050 *second_bracket++ =
'\0';
1052 *out = (
char *) parse;
1055 *residue = second_bracket;
1060 if ((first_bracket)) {
1085 char in_brackets[] =
"sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1086 char no_name[] =
"<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1087 char quoted_string[] =
"\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1088 char missing_end_quote[] =
"\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1089 char name_no_quotes[] =
"name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1090 char no_end_bracket[] =
"name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1091 char no_name_no_brackets[] =
"sip:name@host";
1092 char missing_start_bracket[] =
"sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1097 info->name =
"sip_get_in_brackets_test";
1098 info->category =
"/channels/chan_sip/";
1099 info->summary =
"Tests getting a sip uri in <> brackets within a sip header.";
1101 "Runs through various test situations in which a sip uri "
1102 "in angle brackets needs to be retrieved";
1115 if (!(uri =
get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
1121 if (!(uri =
get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
1127 if (!(uri =
get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
1133 if (!(uri =
get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
1145 if (!(uri =
get_in_brackets(no_name_no_brackets)) || strcmp(uri,
"sip:name@host")) {
1151 if (!(uri =
get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
1161 char **
user,
char **
pass,
char **hostport,
1162 struct uriparams *params,
char **headers,
1166 char **residue2 = residue;
1167 char *orig_uri = uri;
1180 if (residue && **residue) {
1182 *residue = *residue + 1;
1194 strcpy(orig_uri, buf);
1201 return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1208 char *
name, *
user, *
pass, *hostport, *headers, *residue;
1209 struct uriparams params;
1220 struct uriparams params;
1224 struct testdata *testdataptr;
1228 struct testdata td1 = {
1229 .desc =
"quotes and brackets",
1230 .uri =
"\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
1234 .hostport =
"host:5060",
1236 .residue =
"tag=tag",
1237 .params.transport =
"tcp",
1242 struct testdata td2 = {
1243 .desc =
"no quotes",
1244 .uri =
"givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
1245 .name =
"givenname familyname",
1248 .hostport =
"host:5060",
1250 .residue =
"expires=3600",
1251 .params.transport =
"tcp",
1256 struct testdata td3 = {
1257 .desc =
"no brackets",
1258 .uri =
"sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
1262 .hostport =
"host:5060",
1265 .params.transport =
"tcp",
1270 struct testdata td4 = {
1271 .desc =
"just host",
1279 .params.transport =
"",
1293 info->name =
"parse_name_andor_addr_test";
1294 info->category =
"/channels/chan_sip/";
1295 info->summary =
"tests parsing of name_andor_addr abnf structure";
1297 "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
1298 "Verifies output matches expected behavior.";
1305 name = user = pass = hostport = headers = residue = NULL;
1306 params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
1317 (name && strcmp(testdataptr->name, name)) ||
1318 (user && strcmp(testdataptr->user, user)) ||
1319 (pass && strcmp(testdataptr->pass, pass)) ||
1320 (hostport && strcmp(testdataptr->hostport, hostport)) ||
1321 (headers && strcmp(testdataptr->headers, headers)) ||
1322 (residue && strcmp(testdataptr->residue, residue)) ||
1323 (strcmp(testdataptr->params.transport,params.transport)) ||
1324 (strcmp(testdataptr->params.user,params.user))
1344 if ((c = strchr(parse,
'"'))) {
1360 if ((c = strchr(parse,
'@'))) {
1363 if ((out) && (c = strchr(parse,
','))) {
1379 struct contact *split_contact = NULL;
1381 if (*contactheader ==
'*') {
1385 split_contact =
ast_calloc(1,
sizeof(*split_contact));
1388 while ((last =
get_comma(contactheader, &comma)) != -1) {
1390 &split_contact->name, &split_contact->user,
1391 &split_contact->pass, &split_contact->hostport,
1392 &split_contact->params, &split_contact->headers,
1399 split_contact->expires = split_contact->q =
"";
1401 while ((value = strchr(residue,
'='))) {
1405 if ((residue = strchr(value,
';'))) {
1411 if (!strcmp(param,
"expires")) {
1412 split_contact->expires =
value;
1413 }
else if (!strcmp(param,
"q")) {
1414 split_contact->q =
value;
1421 contactheader = comma;
1423 split_contact =
ast_calloc(1,
sizeof(*split_contact));
1432 char contactheader[1024];
1434 struct contactliststruct contactlist;
1435 struct contactliststruct *contactlistptr=&contactlist;
1439 char *contactheader;
1441 struct contactliststruct *contactlist;
1446 struct testdata *testdataptr;
1447 struct contact *tdcontactptr;
1448 struct contact *contactptr;
1451 struct contactliststruct contactlist1, contactlist2;
1453 struct testdata td1 = {
1454 .desc =
"single contact",
1455 .contactheader =
"\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
1456 .contactlist = &contactlist1,
1459 struct contact contact11 = {
1460 .name =
"name :@;?&,",
1463 .hostport =
"host:5082",
1464 .params.transport =
"tcp",
1472 struct testdata td2 = {
1473 .desc =
"multiple contacts",
1474 .contactheader =
"sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
1475 .contactlist = &contactlist2,
1478 struct contact contact21 = {
1481 .pass =
",secret1,",
1482 .hostport =
"host1",
1483 .params.transport =
"",
1490 struct contact contact22 = {
1494 .hostport =
"host2",
1495 .params.transport =
"",
1503 struct testdata td3 = {
1504 .desc =
"star - all contacts",
1505 .contactheader =
"*",
1522 info->name =
"parse_contact_header_test";
1523 info->category =
"/channels/chan_sip/";
1524 info->summary =
"tests parsing of sip contact header";
1526 "Tests parsing of a contact header including those with multiple contacts "
1527 "Verifies output matches expected behavior.";
1534 ast_copy_string(contactheader,testdataptr->contactheader,
sizeof(contactheader));
1536 if (testdataptr->star) {
1547 strcmp(tdcontactptr->name, contactptr->name) ||
1548 strcmp(tdcontactptr->user, contactptr->user) ||
1549 strcmp(tdcontactptr->pass, contactptr->pass) ||
1550 strcmp(tdcontactptr->hostport, contactptr->hostport) ||
1551 strcmp(tdcontactptr->headers, contactptr->headers) ||
1552 strcmp(tdcontactptr->expires, contactptr->expires) ||
1553 strcmp(tdcontactptr->q, contactptr->q) ||
1554 strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
1555 strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
1556 (tdcontactptr->params.lr != contactptr->params.lr)
1591 int i, found, supported;
1592 unsigned int profile = 0;
1594 char *out = unsupported;
1595 size_t outlen = unsupported_len;
1596 char *cur_out = out;
1603 ast_debug(3,
"Begin: parsing SIP \"Supported: %s\"\n", options);
1604 for (next = temp; next; next = sep) {
1607 if ((sep = strchr(next,
',')) != NULL) {
1618 ast_debug(3,
"Found SIP option: -%s-\n", next);
1619 for (i = 0; i <
ARRAY_LEN(sip_options); i++) {
1620 if (!strcasecmp(next, sip_options[i].
text)) {
1621 profile |= sip_options[i].id;
1622 if (sip_options[i].supported == SUPPORTED) {
1626 ast_debug(3,
"Matched SIP option: %s\n", next);
1632 if (!supported && out && outlen) {
1633 size_t copylen = strlen(next);
1634 size_t cur_outlen = strlen(out);
1637 if ((cur_outlen + copylen + 2) < outlen) {
1650 profile |= SIP_OPT_UNKNOWN;
1651 if (!strncasecmp(next,
"x-", 2))
1652 ast_debug(3,
"Found private SIP option, not supported: %s\n", next);
1654 ast_debug(3,
"Found no match for SIP option: %s (Please file bug report!)\n", next);
1664 char unsupported[64];
1665 unsigned int option_profile = 0;
1668 char *input_options;
1669 char *expected_unsupported;
1670 unsigned int expected_profile;
1674 struct testdata *testdataptr;
1677 struct testdata test1 = {
1678 .name =
"test_all_unsupported",
1679 .input_options =
"unsupported1,,, ,unsupported2,unsupported3,unsupported4",
1680 .expected_unsupported =
"unsupported1,unsupported2,unsupported3,unsupported4",
1681 .expected_profile = SIP_OPT_UNKNOWN,
1683 struct testdata test2 = {
1684 .name =
"test_all_unsupported_one_supported",
1685 .input_options =
" unsupported1, replaces, unsupported3 , , , ,unsupported4",
1686 .expected_unsupported =
"unsupported1,unsupported3,unsupported4",
1687 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
1689 struct testdata test3 = {
1690 .name =
"test_two_supported_two_unsupported",
1691 .input_options =
",, timer ,replaces ,unsupported3,unsupported4",
1692 .expected_unsupported =
"unsupported3,unsupported4",
1693 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1696 struct testdata test4 = {
1697 .name =
"test_all_supported",
1698 .input_options =
"timer,replaces",
1699 .expected_unsupported =
"",
1700 .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1703 struct testdata test5 = {
1704 .name =
"test_all_supported_redundant",
1705 .input_options =
"timer,replaces,timer,replace,timer,replaces",
1706 .expected_unsupported =
"",
1707 .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1709 struct testdata test6 = {
1710 .name =
"test_buffer_overflow",
1711 .input_options =
"unsupported1,replaces,timer,unsupported4,unsupported_huge____"
1712 "____________________________________,__________________________________________"
1713 "________________________________________________",
1714 .expected_unsupported =
"unsupported1,unsupported4",
1715 .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1717 struct testdata test7 = {
1718 .name =
"test_null_input",
1719 .input_options = NULL,
1720 .expected_unsupported =
"",
1721 .expected_profile = 0,
1723 struct testdata test8 = {
1724 .name =
"test_whitespace_input",
1725 .input_options =
" ",
1726 .expected_unsupported =
"",
1727 .expected_profile = 0,
1729 struct testdata test9 = {
1730 .name =
"test_whitespace_plus_option_input",
1731 .input_options =
" , , ,timer , , , , , ",
1732 .expected_unsupported =
"",
1733 .expected_profile = SIP_OPT_TIMER,
1738 info->name =
"sip_parse_options_test";
1739 info->category =
"/channels/chan_sip/";
1740 info->summary =
"Tests parsing of sip options";
1742 "Tests parsing of SIP options from supported and required "
1743 "header fields. Verifies when unsupported options are encountered "
1744 "that they are appended to the unsupported out buffer and that the "
1745 "correct bit field representnig the option profile is returned.";
1763 memset(unsupported, 0,
sizeof(unsupported));
1765 if (option_profile != testdataptr->expected_profile ||
1766 strcmp(unsupported, testdataptr->expected_unsupported)) {
1767 ast_test_status_update(test,
"Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
1768 "%s expected bit profile: %x actual bit profile: %x\n",
1770 testdataptr->expected_unsupported,
1772 testdataptr->expected_profile,
1783 if (option_profile != testdataptr->expected_profile) {
1784 ast_test_status_update(test,
"NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
1786 testdataptr->expected_profile,
1818 char *params1 = NULL;
1819 char *params2 = NULL;
1822 int zerolength1 = 0;
1823 int zerolength2 = 0;
1827 int methodmatch = 0;
1843 if (zerolength1 && zerolength2) {
1847 for (pos1 =
strsep(¶ms1,
";"); pos1; pos1 =
strsep(¶ms1,
";")) {
1848 char *value1 = pos1;
1849 char *name1 =
strsep(&value1,
"=");
1850 char *params2dup = NULL;
1862 for (pos2 =
strsep(¶ms2dup,
";"); pos2; pos2 =
strsep(¶ms2dup,
";")) {
1864 char *value2 = strchr(pos2,
'=');
1870 if (!strcasecmp(name1, name2)) {
1871 if (strcasecmp(value1, value2)) {
1880 if (!strcasecmp(name1,
"maddr")) {
1886 }
else if (!strcasecmp(name1,
"ttl")) {
1892 }
else if (!strcasecmp(name1,
"user")) {
1898 }
else if (!strcasecmp(name1,
"method")) {
1911 for (pos2 =
strsep(¶ms2,
";"); pos2; pos2 =
strsep(¶ms2,
";")) {
1912 char *value2 = pos2;
1913 char *name2 =
strsep(&value2,
"=");
1917 if ((!strcasecmp(name2,
"maddr") && !maddrmatch) ||
1918 (!strcasecmp(name2,
"ttl") && !ttlmatch) ||
1919 (!strcasecmp(name2,
"user") && !usermatch) ||
1920 (!strcasecmp(name2,
"method") && !methodmatch)) {
1944 char *headers1 = NULL;
1945 char *headers2 = NULL;
1946 int zerolength1 = 0;
1947 int zerolength2 = 0;
1966 if (zerolength1 != zerolength2) {
1970 if (zerolength1 && zerolength2)
1977 if (strlen(headers1) != strlen(headers2)) {
1981 for (header1 =
strsep(&headers1,
"&"); header1; header1 =
strsep(&headers1,
"&")) {
2017 if (addr1_parsed != addr2_parsed) {
2029 if (!addr1_parsed) {
2030 #ifdef HAVE_XLOCALE_H
2032 return strcasecmp(host1, host2);
2034 return strcasecmp_l(host1, host2, c_locale);
2037 return strcasecmp(host1, host2);
2063 if (!input1 || !input2) {
2073 uri_scheme1 =
strsep(&uri1,
":");
2074 uri_scheme2 =
strsep(&uri2,
":");
2076 if (strcmp(uri_scheme1, uri_scheme2)) {
2084 if (strcmp(uri_scheme1,
"sip") && strcmp(uri_scheme1,
"sips")) {
2092 if ((host1 = strchr(uri1,
'@'))) {
2095 if ((host2 = strchr(uri2,
'@'))) {
2102 if ((host1 && !host2) ||
2103 (host2 && !host1) ||
2104 (host1 && host2 && strcmp(uri1, uri2))) {
2119 if ((params1 = strchr(host1,
';'))) {
2122 if ((params2 = strchr(host2,
';'))) {
2129 if ((headers1 = strchr(
S_OR(params1, host1),
'?'))) {
2132 if ((headers2 = strchr(
S_OR(params2, host2),
'?'))) {
2149 #define URI_CMP_MATCH 0
2150 #define URI_CMP_NOMATCH 1
2154 static const struct {
2157 int expected_result;
2158 } uri_cmp_tests [] = {
2160 {
"sip:bob@example.com",
"sip:bob@example.com",
URI_CMP_MATCH },
2168 {
"sip:bob@1.2.3.4",
"sip:bob@001.002.003.004",
URI_CMP_MATCH },
2174 {
"sip:bob@[2001:db8::1234]",
"sip:bob@[2001:db8::1234]",
URI_CMP_MATCH },
2176 {
"sip:bob@[2001:db8::1234]",
"sip:bob@[2001:0db8::1234]",
URI_CMP_MATCH },
2182 {
"sip:bob@[2001:db8:1234]:5060",
"sip:bob@[2001:db8:1234]",
URI_CMP_NOMATCH },
2186 {
"sip:bob@example.com",
"sip:bob@EXAMPLE.COM",
URI_CMP_MATCH },
2188 {
"sip:bob@example.com?header1=value1&header2=value2",
"sip:bob@example.com?header1=value1&header2=value2",
URI_CMP_MATCH },
2190 {
"sip:bob@example.com?header1=value1&header2=value2",
"sip:bob@example.com",
URI_CMP_NOMATCH },
2192 {
"sip:bob@example.com?header1=value1&header2=value2",
"sip:bob@example.com?header1=value1&header2=value3",
URI_CMP_NOMATCH },
2194 {
"sip:bob@example.com;param1=value1;param2=value2",
"sip:bob@example.com;param1=value1;param2=value2",
URI_CMP_MATCH },
2196 {
"sip:bob@example.com;param2=value2;param1=value1",
"sip:bob@example.com;param1=value1;param2=value2",
URI_CMP_MATCH },
2198 {
"sip:bob@example.com;param1=value1;param2=value2",
"sip:bob@example.com",
URI_CMP_MATCH },
2200 {
"sip:bob@example.com;param1=value1;param2=value2",
"sip:bob@example.com;param1=value1;param2=value3",
URI_CMP_NOMATCH },
2202 {
"sip:bob@example.com;param1=value1;maddr=192.168.0.1",
"sip:bob@example.com;param1=value1",
URI_CMP_NOMATCH },
2204 {
"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 },
2222 info->name =
"sip_uri_cmp_test";
2223 info->category =
"/channels/chan_sip/";
2224 info->summary =
"Tests comparison of SIP URIs";
2225 info->description =
"Several would-be tricky URI comparisons are performed";
2231 for (i = 0; i <
ARRAY_LEN(uri_cmp_tests); ++i) {
2234 if ((cmp_res1 =
sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
2240 if (cmp_res1 != uri_cmp_tests[i].expected_result) {
2242 "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
2243 uri_cmp_tests[i].expected_result ==
URI_CMP_MATCH ?
"Match" :
"No Match",
2251 if ((cmp_res2 =
sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
2257 if (cmp_res2 != uri_cmp_tests[i].expected_result) {
2259 "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
2260 uri_cmp_tests[i].expected_result ==
URI_CMP_MATCH ?
"Match" :
"No Match",
2281 struct sip_via *v =
ast_calloc(1,
sizeof(*v));
2303 v->protocol =
strsep(&via,
" \t\r\n");
2316 v->sent_by =
strsep(&via,
"; \t\r\n");
2326 if (((parm = strchr(v->sent_by,
']')) && *(++parm) ==
':') || (parm = strchr(v->sent_by,
':'))) {
2329 v->port = strtol(++parm, &endptr, 10);
2333 while ((parm =
strsep(&via,
"; \t\r\n"))) {
2335 if ((c = strstr(parm,
"maddr="))) {
2337 }
else if ((c = strstr(parm,
"branch="))) {
2339 }
else if ((c = strstr(parm,
"ttl="))) {
2342 v->ttl = strtol(c, &endptr, 10);
2358 struct sip_via *via;
2361 char *expected_protocol;
2362 char *expected_branch;
2363 char *expected_sent_by;
2364 char *expected_maddr;
2365 unsigned int expected_port;
2366 unsigned char expected_ttl;
2370 struct testdata *testdataptr;
2372 struct testdata t1 = {
2373 .in =
"SIP/2.0/UDP host:port;branch=thebranch",
2374 .expected_protocol =
"SIP/2.0/UDP",
2375 .expected_sent_by =
"host:port",
2376 .expected_branch =
"thebranch",
2378 struct testdata t2 = {
2379 .in =
"SIP/2.0/UDP host:port",
2380 .expected_protocol =
"SIP/2.0/UDP",
2381 .expected_sent_by =
"host:port",
2382 .expected_branch =
"",
2384 struct testdata t3 = {
2385 .in =
"SIP/2.0/UDP",
2388 struct testdata t4 = {
2389 .in =
"BLAH/BLAH/BLAH host:port;branch=",
2390 .expected_protocol =
"BLAH/BLAH/BLAH",
2391 .expected_sent_by =
"host:port",
2392 .expected_branch =
"",
2394 struct testdata t5 = {
2395 .in =
"SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
2396 .expected_protocol =
"SIP/2.0/UDP",
2397 .expected_sent_by =
"host:5060",
2398 .expected_port = 5060,
2399 .expected_branch =
"thebranch",
2400 .expected_maddr =
"224.0.0.1",
2403 struct testdata t6 = {
2404 .in =
"SIP/2.0/UDP host:5060;\n branch=thebranch;\r\n maddr=224.0.0.1; ttl=1",
2405 .expected_protocol =
"SIP/2.0/UDP",
2406 .expected_sent_by =
"host:5060",
2407 .expected_port = 5060,
2408 .expected_branch =
"thebranch",
2409 .expected_maddr =
"224.0.0.1",
2412 struct testdata t7 = {
2413 .in =
"SIP/2.0/UDP [::1]:5060",
2414 .expected_protocol =
"SIP/2.0/UDP",
2415 .expected_sent_by =
"[::1]:5060",
2416 .expected_port = 5060,
2417 .expected_branch =
"",
2421 info->name =
"parse_via_test";
2422 info->category =
"/channels/chan_sip/";
2423 info->summary =
"Tests parsing the Via header";
2425 "Runs through various test situations in which various "
2426 " parameters parameter must be extracted from a VIA header";
2444 if (!testdataptr->expected_null) {
2446 "failed to parse header\n",
2447 i, testdataptr->in);
2454 if (testdataptr->expected_null) {
2456 "successfully parased invalid via header\n",
2457 i, testdataptr->in);
2465 || (!
ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
2468 "parsed protocol = \"%s\"\n"
2469 "expected = \"%s\"\n"
2470 "failed to parse protocol\n",
2471 i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
2476 || (!
ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
2479 "parsed sent_by = \"%s\"\n"
2480 "expected = \"%s\"\n"
2481 "failed to parse sent-by\n",
2482 i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
2486 if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
2488 "parsed port = \"%u\"\n"
2489 "expected = \"%u\"\n"
2490 "failed to parse port\n",
2491 i, testdataptr->in, via->port, testdataptr->expected_port);
2496 || (!
ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
2499 "parsed branch = \"%s\"\n"
2500 "expected = \"%s\"\n"
2501 "failed to parse branch\n",
2502 i, testdataptr->in, via->branch, testdataptr->expected_branch);
2507 || (!
ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
2510 "parsed maddr = \"%s\"\n"
2511 "expected = \"%s\"\n"
2512 "failed to parse maddr\n",
2513 i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
2517 if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
2519 "parsed ttl = \"%d\"\n"
2520 "expected = \"%d\"\n"
2521 "failed to parse ttl\n",
2522 i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
2561 #ifdef HAVE_XLOCALE_H
2562 c_locale = newlocale(LC_CTYPE_MASK,
"C", NULL);
2572 #ifdef HAVE_XLOCALE_H
2574 freelocale(c_locale);
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
char * strsep(char **str, const char *delims)
unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
Parse supported header in incoming packet.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
int get_in_brackets_const(const char *src, const char **start, int *length)
void ast_uri_decode(char *s)
Decode URI, URN, URL (overwrite string)
static void dummy(char *unused,...)
int get_in_brackets_full(char *tmp, char **out, char **residue)
static int sip_uri_domain_cmp(const char *host1, const char *host2)
Compare domain sections of SIP URIs.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
#define AST_TEST_REGISTER(cb)
int sip_uri_cmp(const char *input1, const char *input2)
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
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.
static int input(yyscan_t yyscanner)
Socket address structure.
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
#define ast_debug(level,...)
Log a DEBUG message.
int get_name_and_number(const char *hdr, char **name, char **number)
void sip_request_parser_register_tests(void)
#define ast_test_status_update(a, b, c...)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
struct sla_ringing_trunk * last
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
char * get_in_brackets(char *tmp)
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
void free_via(struct sip_via *v)
void sip_reqresp_parser_exit(void)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
static int sip_uri_headers_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI headers
#define AST_TEST_UNREGISTER(cb)
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)
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
int get_comma(char *in, char **out)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
static void parse(struct mgcp_request *req)
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
structure to hold users read from users.conf
void sip_request_parser_unregister_tests(void)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
int sip_reqresp_parser_init(void)
#define AST_TEST_DEFINE(hdr)
struct sip_via * parse_via(const char *header)
static int sip_uri_params_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI parameters
char * strcasestr(const char *, const char *)
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.