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