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