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: 365400 $")
00025
00026 #include "include/sip.h"
00027 #include "include/config_parser.h"
00028 #include "include/sip_utils.h"
00029
00030
00031
00032
00033
00034
00035 int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno)
00036 {
00037 int portnum = 0;
00038 int domainport = 0;
00039 enum sip_transport transport = SIP_TRANSPORT_UDP;
00040 char buf[256] = "";
00041 char *userpart = NULL, *hostpart = NULL;
00042
00043 AST_DECLARE_APP_ARGS(pre1,
00044 AST_APP_ARG(peer);
00045 AST_APP_ARG(userpart);
00046 );
00047 AST_DECLARE_APP_ARGS(pre2,
00048 AST_APP_ARG(transport);
00049 AST_APP_ARG(blank);
00050 AST_APP_ARG(userpart);
00051 );
00052 AST_DECLARE_APP_ARGS(user1,
00053 AST_APP_ARG(userpart);
00054 AST_APP_ARG(secret);
00055 AST_APP_ARG(authuser);
00056 );
00057 AST_DECLARE_APP_ARGS(user2,
00058 AST_APP_ARG(user);
00059 AST_APP_ARG(domain);
00060 );
00061 AST_DECLARE_APP_ARGS(user3,
00062 AST_APP_ARG(authuser);
00063 AST_APP_ARG(domainport);
00064 );
00065 AST_DECLARE_APP_ARGS(host1,
00066 AST_APP_ARG(hostpart);
00067 AST_APP_ARG(expiry);
00068 );
00069 AST_DECLARE_APP_ARGS(host2,
00070 AST_APP_ARG(hostpart);
00071 AST_APP_ARG(extension);
00072 );
00073 AST_DECLARE_APP_ARGS(host3,
00074 AST_APP_ARG(host);
00075 AST_APP_ARG(port);
00076 );
00077
00078 if (!value) {
00079 return -1;
00080 }
00081
00082 if (!reg) {
00083 return -1;
00084 }
00085 ast_copy_string(buf, value, sizeof(buf));
00086
00087
00088
00089
00090
00091
00092 if ((hostpart = strrchr(buf, '@'))) {
00093 *hostpart++ = '\0';
00094 userpart = buf;
00095 }
00096
00097 if (ast_strlen_zero(userpart) || ast_strlen_zero(hostpart)) {
00098 ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
00099 return -1;
00100 }
00101
00102
00103
00104
00105
00106
00107 AST_NONSTANDARD_RAW_ARGS(pre1, userpart, '?');
00108 if (ast_strlen_zero(pre1.userpart)) {
00109 pre1.userpart = pre1.peer;
00110 pre1.peer = NULL;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119 AST_NONSTANDARD_RAW_ARGS(pre2, pre1.userpart, '/');
00120 if (ast_strlen_zero(pre2.userpart)) {
00121 pre2.userpart = pre2.transport;
00122 pre2.transport = NULL;
00123 } else {
00124 pre2.transport[strlen(pre2.transport) - 1] = '\0';
00125 }
00126
00127 if (!ast_strlen_zero(pre2.blank)) {
00128 ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
00129 return -1;
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 AST_NONSTANDARD_RAW_ARGS(user1, pre2.userpart, ':');
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 AST_NONSTANDARD_RAW_ARGS(host1, hostpart, '~');
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 AST_NONSTANDARD_RAW_ARGS(host2, host1.hostpart, '/');
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':');
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 AST_NONSTANDARD_RAW_ARGS(user3, user1.authuser, ':');
00206
00207
00208
00209 if (user3.argc == 2) {
00210 char *reorder = user3.domainport;
00211 user3.domainport = user1.secret;
00212 user1.secret = user3.authuser;
00213 user3.authuser = reorder;
00214 }
00215
00216 if (host3.port) {
00217 if (!(portnum = port_str2int(host3.port, 0))) {
00218 ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno);
00219 }
00220 }
00221 if (user3.domainport) {
00222 if (!(domainport = port_str2int(user3.domainport, 0))) {
00223 ast_log(LOG_NOTICE, "'%s' is not a valid domain port number on line %d of sip.conf. using default.\n", user3.domainport, lineno);
00224 }
00225 }
00226
00227
00228 if (!pre2.transport) {
00229 transport = SIP_TRANSPORT_UDP;
00230 } else if (!strncasecmp(pre2.transport, "tcp", 3)) {
00231 transport = SIP_TRANSPORT_TCP;
00232 } else if (!strncasecmp(pre2.transport, "tls", 3)) {
00233 transport = SIP_TRANSPORT_TLS;
00234 } else if (!strncasecmp(pre2.transport, "udp", 3)) {
00235 transport = SIP_TRANSPORT_UDP;
00236 } else {
00237 transport = SIP_TRANSPORT_UDP;
00238 ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", pre2.transport, lineno);
00239 }
00240
00241
00242 if (!portnum) {
00243 if (transport == SIP_TRANSPORT_TLS) {
00244 portnum = STANDARD_TLS_PORT;
00245 } else {
00246 portnum = STANDARD_SIP_PORT;
00247 }
00248 }
00249
00250
00251 ast_string_field_set(reg, callback, ast_strip_quoted(S_OR(host2.extension, "s"), "\"", "\""));
00252 ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user2.user, ""), "\"", "\""));
00253 ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\""));
00254 ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user3.authuser, ""), "\"", "\""));
00255 ast_string_field_set(reg, secret, ast_strip_quoted(S_OR(user1.secret, ""), "\"", "\""));
00256 ast_string_field_set(reg, peername, ast_strip_quoted(S_OR(pre1.peer, ""), "\"", "\""));
00257 ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user2.domain, ""), "\"", "\""));
00258
00259 reg->transport = transport;
00260 reg->timeout = reg->expire = -1;
00261 reg->portno = portnum;
00262 reg->regdomainport = domainport;
00263 reg->callid_valid = FALSE;
00264 reg->ocseq = INITIAL_CSEQ;
00265 reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry);
00266
00267 return 0;
00268 }
00269
00270 AST_TEST_DEFINE(sip_parse_register_line_test)
00271 {
00272 int res = AST_TEST_PASS;
00273 struct sip_registry *reg;
00274 int default_expiry = 120;
00275 const char *reg1 = "name@domain";
00276 const char *reg2 = "name:pass@domain";
00277 const char *reg3 = "name@namedomain:pass:authuser@domain";
00278 const char *reg4 = "name@namedomain:pass:authuser@domain/extension";
00279 const char *reg5 = "tcp://name@namedomain:pass:authuser@domain/extension";
00280 const char *reg6 = "tls://name@namedomain:pass:authuser@domain/extension~111";
00281 const char *reg7 = "peer?tcp://name@namedomain:pass:authuser@domain:1234/extension~111";
00282 const char *reg8 = "peer?name@namedomain:pass:authuser@domain:1234/extension~111";
00283 const char *reg9 = "peer?name:pass:authuser:1234/extension~111";
00284 const char *reg10 = "@domin:1234";
00285 const char *reg12 = "name@namedomain:4321:pass:authuser@domain";
00286 const char *reg13 = "name@namedomain:4321::@domain";
00287
00288 switch (cmd) {
00289 case TEST_INIT:
00290 info->name = "sip_parse_register_line_test";
00291 info->category = "/channels/chan_sip/";
00292 info->summary = "tests sip register line parsing";
00293 info->description =
00294 "Tests parsing of various register line configurations. "
00295 "Verifies output matches expected behavior.";
00296 return AST_TEST_NOT_RUN;
00297 case TEST_EXECUTE:
00298 break;
00299 }
00300
00301
00302 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00303 goto alloc_fail;
00304 } else if (
00305 sip_parse_register_line(reg, default_expiry, reg1, 1) ||
00306 strcmp(reg->callback, "s") ||
00307 strcmp(reg->username, "name") ||
00308 strcmp(reg->regdomain, "") ||
00309 strcmp(reg->hostname, "domain") ||
00310 strcmp(reg->authuser, "") ||
00311 strcmp(reg->secret, "") ||
00312 strcmp(reg->peername, "") ||
00313 reg->transport != SIP_TRANSPORT_UDP ||
00314 reg->timeout != -1 ||
00315 reg->expire != -1 ||
00316 reg->refresh != default_expiry ||
00317 reg->expiry != default_expiry ||
00318 reg->configured_expiry != default_expiry ||
00319 reg->portno != STANDARD_SIP_PORT ||
00320 (reg->regdomainport) ||
00321 reg->callid_valid != FALSE ||
00322 reg->ocseq != INITIAL_CSEQ) {
00323
00324 ast_test_status_update(test, "Test 1: simple config failed\n");
00325 res = AST_TEST_FAIL;
00326 }
00327 ast_string_field_free_memory(reg);
00328 ast_free(reg);
00329
00330
00331 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00332 goto alloc_fail;
00333 } else if (
00334 sip_parse_register_line(reg, default_expiry, reg2, 1) ||
00335 strcmp(reg->callback, "s") ||
00336 strcmp(reg->username, "name") ||
00337 strcmp(reg->regdomain, "") ||
00338 strcmp(reg->hostname, "domain") ||
00339 strcmp(reg->authuser, "") ||
00340 strcmp(reg->secret, "pass") ||
00341 strcmp(reg->peername, "") ||
00342 reg->transport != SIP_TRANSPORT_UDP ||
00343 reg->timeout != -1 ||
00344 reg->expire != -1 ||
00345 reg->refresh != default_expiry ||
00346 reg->expiry != default_expiry ||
00347 reg->configured_expiry != default_expiry ||
00348 reg->portno != STANDARD_SIP_PORT ||
00349 (reg->regdomainport) ||
00350 reg->callid_valid != FALSE ||
00351 reg->ocseq != INITIAL_CSEQ) {
00352
00353 ast_test_status_update(test, "Test 2: add secret failed\n");
00354 res = AST_TEST_FAIL;
00355 }
00356 ast_string_field_free_memory(reg);
00357 ast_free(reg);
00358
00359
00360 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00361 goto alloc_fail;
00362 } else if (
00363 sip_parse_register_line(reg, default_expiry, reg3, 1) ||
00364 strcmp(reg->callback, "s") ||
00365 strcmp(reg->username, "name") ||
00366 strcmp(reg->regdomain, "namedomain") ||
00367 strcmp(reg->hostname, "domain") ||
00368 strcmp(reg->authuser, "authuser") ||
00369 strcmp(reg->secret, "pass") ||
00370 strcmp(reg->peername, "") ||
00371 reg->transport != SIP_TRANSPORT_UDP ||
00372 reg->timeout != -1 ||
00373 reg->expire != -1 ||
00374 reg->refresh != default_expiry ||
00375 reg->expiry != default_expiry ||
00376 reg->configured_expiry != default_expiry ||
00377 reg->portno != STANDARD_SIP_PORT ||
00378 (reg->regdomainport) ||
00379 reg->callid_valid != FALSE ||
00380 reg->ocseq != INITIAL_CSEQ) {
00381
00382 ast_test_status_update(test, "Test 3: add userdomain and authuser failed\n");
00383 res = AST_TEST_FAIL;
00384 }
00385 ast_string_field_free_memory(reg);
00386 ast_free(reg);
00387
00388
00389 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00390 goto alloc_fail;
00391 } else if (
00392 sip_parse_register_line(reg, default_expiry, reg4, 1) ||
00393 strcmp(reg->callback, "extension") ||
00394 strcmp(reg->username, "name") ||
00395 strcmp(reg->regdomain, "namedomain") ||
00396 strcmp(reg->hostname, "domain") ||
00397 strcmp(reg->authuser, "authuser") ||
00398 strcmp(reg->secret, "pass") ||
00399 strcmp(reg->peername, "") ||
00400 reg->transport != SIP_TRANSPORT_UDP ||
00401 reg->timeout != -1 ||
00402 reg->expire != -1 ||
00403 reg->refresh != default_expiry ||
00404 reg->expiry != default_expiry ||
00405 reg->configured_expiry != default_expiry ||
00406 reg->portno != STANDARD_SIP_PORT ||
00407 (reg->regdomainport) ||
00408 reg->callid_valid != FALSE ||
00409 reg->ocseq != INITIAL_CSEQ) {
00410
00411 ast_test_status_update(test, "Test 4: add callback extension failed\n");
00412 res = AST_TEST_FAIL;
00413 }
00414 ast_string_field_free_memory(reg);
00415 ast_free(reg);
00416
00417
00418 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00419 goto alloc_fail;
00420 } else if (
00421 sip_parse_register_line(reg, default_expiry, reg5, 1) ||
00422 strcmp(reg->callback, "extension") ||
00423 strcmp(reg->username, "name") ||
00424 strcmp(reg->regdomain, "namedomain") ||
00425 strcmp(reg->hostname, "domain") ||
00426 strcmp(reg->authuser, "authuser") ||
00427 strcmp(reg->secret, "pass") ||
00428 strcmp(reg->peername, "") ||
00429 reg->transport != SIP_TRANSPORT_TCP ||
00430 reg->timeout != -1 ||
00431 reg->expire != -1 ||
00432 reg->refresh != default_expiry ||
00433 reg->expiry != default_expiry ||
00434 reg->configured_expiry != default_expiry ||
00435 reg->portno != STANDARD_SIP_PORT ||
00436 (reg->regdomainport) ||
00437 reg->callid_valid != FALSE ||
00438 reg->ocseq != INITIAL_CSEQ) {
00439
00440 ast_test_status_update(test, "Test 5: add transport failed\n");
00441 res = AST_TEST_FAIL;
00442 }
00443 ast_string_field_free_memory(reg);
00444 ast_free(reg);
00445
00446
00447 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00448 goto alloc_fail;
00449 } else if (
00450 sip_parse_register_line(reg, default_expiry, reg6, 1) ||
00451 strcmp(reg->callback, "extension") ||
00452 strcmp(reg->username, "name") ||
00453 strcmp(reg->regdomain, "namedomain") ||
00454 strcmp(reg->hostname, "domain") ||
00455 strcmp(reg->authuser, "authuser") ||
00456 strcmp(reg->secret, "pass") ||
00457 strcmp(reg->peername, "") ||
00458 reg->transport != SIP_TRANSPORT_TLS ||
00459 reg->timeout != -1 ||
00460 reg->expire != -1 ||
00461 reg->refresh != 111 ||
00462 reg->expiry != 111 ||
00463 reg->configured_expiry != 111 ||
00464 reg->portno != STANDARD_TLS_PORT ||
00465 (reg->regdomainport) ||
00466 reg->callid_valid != FALSE ||
00467 reg->ocseq != INITIAL_CSEQ) {
00468
00469 ast_test_status_update(test, "Test 6: change to tls transport and add expiry failed\n");
00470 res = AST_TEST_FAIL;
00471 }
00472 ast_string_field_free_memory(reg);
00473 ast_free(reg);
00474
00475
00476 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00477 goto alloc_fail;
00478 } else if (
00479 sip_parse_register_line(reg, default_expiry, reg7, 1) ||
00480 strcmp(reg->callback, "extension") ||
00481 strcmp(reg->username, "name") ||
00482 strcmp(reg->regdomain, "namedomain") ||
00483 strcmp(reg->hostname, "domain") ||
00484 strcmp(reg->authuser, "authuser") ||
00485 strcmp(reg->secret, "pass") ||
00486 strcmp(reg->peername, "peer") ||
00487 reg->transport != SIP_TRANSPORT_TCP ||
00488 reg->timeout != -1 ||
00489 reg->expire != -1 ||
00490 reg->refresh != 111 ||
00491 reg->expiry != 111 ||
00492 reg->configured_expiry != 111 ||
00493 reg->portno != 1234 ||
00494 (reg->regdomainport) ||
00495 reg->callid_valid != FALSE ||
00496 reg->ocseq != INITIAL_CSEQ) {
00497
00498 ast_test_status_update(test, "Test 7, change transport to tcp, add custom port, and add peer failed.\n");
00499 res = AST_TEST_FAIL;
00500 }
00501 ast_string_field_free_memory(reg);
00502 ast_free(reg);
00503
00504
00505 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00506 goto alloc_fail;
00507 } else if (
00508 sip_parse_register_line(reg, default_expiry, reg8, 1) ||
00509 strcmp(reg->callback, "extension") ||
00510 strcmp(reg->username, "name") ||
00511 strcmp(reg->regdomain, "namedomain") ||
00512 strcmp(reg->hostname, "domain") ||
00513 strcmp(reg->authuser, "authuser") ||
00514 strcmp(reg->secret, "pass") ||
00515 strcmp(reg->peername, "peer") ||
00516 reg->transport != SIP_TRANSPORT_UDP ||
00517 reg->timeout != -1 ||
00518 reg->expire != -1 ||
00519 reg->refresh != 111 ||
00520 reg->expiry != 111 ||
00521 reg->configured_expiry != 111 ||
00522 reg->portno != 1234 ||
00523 (reg->regdomainport) ||
00524 reg->callid_valid != FALSE ||
00525 reg->ocseq != INITIAL_CSEQ) {
00526
00527 ast_test_status_update(test, "Test 8, remove transport failed.\n");
00528 res = AST_TEST_FAIL;
00529 }
00530 ast_string_field_free_memory(reg);
00531 ast_free(reg);
00532
00533
00534 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00535 goto alloc_fail;
00536 } else if (
00537 sip_parse_register_line(reg, default_expiry, reg12, 1) ||
00538 strcmp(reg->callback, "s") ||
00539 strcmp(reg->username, "name") ||
00540 strcmp(reg->regdomain, "namedomain") ||
00541 strcmp(reg->hostname, "domain") ||
00542 strcmp(reg->authuser, "authuser") ||
00543 strcmp(reg->secret, "pass") ||
00544 strcmp(reg->peername, "") ||
00545 reg->transport != SIP_TRANSPORT_UDP ||
00546 reg->timeout != -1 ||
00547 reg->expire != -1 ||
00548 reg->refresh != default_expiry ||
00549 reg->expiry != default_expiry ||
00550 reg->configured_expiry != default_expiry ||
00551 reg->portno != STANDARD_SIP_PORT ||
00552 reg->regdomainport != 4321 ||
00553 reg->callid_valid != FALSE ||
00554 reg->ocseq != INITIAL_CSEQ) {
00555
00556 ast_test_status_update(test, "Test 12, add domain port failed.\n");
00557 res = AST_TEST_FAIL;
00558 }
00559
00560
00561 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00562 goto alloc_fail;
00563 } else if (
00564 sip_parse_register_line(reg, default_expiry, reg13, 1) ||
00565 strcmp(reg->callback, "s") ||
00566 strcmp(reg->username, "name") ||
00567 strcmp(reg->regdomain, "namedomain") ||
00568 strcmp(reg->hostname, "domain") ||
00569 strcmp(reg->authuser, "") ||
00570 strcmp(reg->secret, "") ||
00571 strcmp(reg->peername, "") ||
00572 reg->transport != SIP_TRANSPORT_UDP ||
00573 reg->timeout != -1 ||
00574 reg->expire != -1 ||
00575 reg->refresh != default_expiry ||
00576 reg->expiry != default_expiry ||
00577 reg->configured_expiry != default_expiry ||
00578 reg->portno != STANDARD_SIP_PORT ||
00579 reg->regdomainport != 4321 ||
00580 reg->callid_valid != FALSE ||
00581 reg->ocseq != INITIAL_CSEQ) {
00582
00583 ast_test_status_update(test, "Test 13, domain port without secret failed.\n");
00584 res = AST_TEST_FAIL;
00585 }
00586
00587
00588 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00589 goto alloc_fail;
00590 } else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) {
00591 ast_test_status_update(test,
00592 "Test 9, missing domain, expected to fail but did not.\n");
00593 res = AST_TEST_FAIL;
00594 }
00595 ast_string_field_free_memory(reg);
00596 ast_free(reg);
00597
00598
00599 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00600 goto alloc_fail;
00601 } else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) {
00602 ast_test_status_update(test,
00603 "Test 10, missing user expected to fail but did not\n");
00604 res = AST_TEST_FAIL;
00605 }
00606 ast_string_field_free_memory(reg);
00607 ast_free(reg);
00608
00609
00610 if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) {
00611 ast_test_status_update(test,
00612 "Test 11, no registry object, expected to fail but did not.\n");
00613 res = AST_TEST_FAIL;
00614 }
00615
00616
00617 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
00618 goto alloc_fail;
00619 } else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) {
00620
00621 ast_test_status_update(test,
00622 "Test 11, NULL register line expected to fail but did not.\n");
00623 res = AST_TEST_FAIL;
00624 }
00625 ast_string_field_free_memory(reg);
00626 ast_free(reg);
00627
00628
00629 return res;
00630
00631 alloc_fail:
00632 ast_test_status_update(test, "Out of memory. \n");
00633 return res;
00634 }
00635
00636 int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport)
00637 {
00638 char *port;
00639
00640 if (ast_strlen_zero(line)) {
00641 *hostname = NULL;
00642 return -1;
00643 }
00644 if ((*hostname = strstr(line, "://"))) {
00645 *hostname += 3;
00646
00647 if (!strncasecmp(line, "tcp", 3))
00648 *transport = SIP_TRANSPORT_TCP;
00649 else if (!strncasecmp(line, "tls", 3))
00650 *transport = SIP_TRANSPORT_TLS;
00651 else if (!strncasecmp(line, "udp", 3))
00652 *transport = SIP_TRANSPORT_UDP;
00653 else
00654 ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", line, lineno);
00655 } else {
00656 *hostname = line;
00657 *transport = SIP_TRANSPORT_UDP;
00658 }
00659
00660 if ((line = strrchr(*hostname, '@')))
00661 line++;
00662 else
00663 line = *hostname;
00664
00665 if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
00666 ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
00667 line, lineno);
00668 return -1;
00669 }
00670
00671 if (port) {
00672 if (!sscanf(port, "%5u", portnum)) {
00673 ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
00674 port = NULL;
00675 }
00676 }
00677
00678 if (!port) {
00679 if (*transport & SIP_TRANSPORT_TLS) {
00680 *portnum = STANDARD_TLS_PORT;
00681 } else {
00682 *portnum = STANDARD_SIP_PORT;
00683 }
00684 }
00685
00686 return 0;
00687 }
00688
00689 AST_TEST_DEFINE(sip_parse_host_line_test)
00690 {
00691 int res = AST_TEST_PASS;
00692 char *host;
00693 int port;
00694 enum sip_transport transport;
00695 char host1[] = "www.blah.com";
00696 char host2[] = "tcp://www.blah.com";
00697 char host3[] = "tls://10.10.10.10";
00698 char host4[] = "tls://10.10.10.10:1234";
00699 char host5[] = "10.10.10.10:1234";
00700
00701 switch (cmd) {
00702 case TEST_INIT:
00703 info->name = "sip_parse_host_line_test";
00704 info->category = "/channels/chan_sip/";
00705 info->summary = "tests sip.conf host line parsing";
00706 info->description =
00707 "Tests parsing of various host line configurations. "
00708 "Verifies output matches expected behavior.";
00709 return AST_TEST_NOT_RUN;
00710 case TEST_EXECUTE:
00711 break;
00712 }
00713
00714
00715 sip_parse_host(host1, 1, &host, &port, &transport);
00716 if (port != STANDARD_SIP_PORT ||
00717 ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
00718 transport != SIP_TRANSPORT_UDP) {
00719 ast_test_status_update(test, "Test 1: simple host failed.\n");
00720 res = AST_TEST_FAIL;
00721 }
00722
00723
00724 sip_parse_host(host2, 1, &host, &port, &transport);
00725 if (port != STANDARD_SIP_PORT ||
00726 ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
00727 transport != SIP_TRANSPORT_TCP) {
00728 ast_test_status_update(test, "Test 2: tcp host failed.\n");
00729 res = AST_TEST_FAIL;
00730 }
00731
00732
00733 sip_parse_host(host3, 1, &host, &port, &transport);
00734 if (port != STANDARD_TLS_PORT ||
00735 ast_strlen_zero(host) || strcmp(host, "10.10.10.10") ||
00736 transport != SIP_TRANSPORT_TLS) {
00737 ast_test_status_update(test, "Test 3: tls host failed. \n");
00738 res = AST_TEST_FAIL;
00739 }
00740
00741
00742 sip_parse_host(host4, 1, &host, &port, &transport);
00743 if (port != 1234 || ast_strlen_zero(host) ||
00744 strcmp(host, "10.10.10.10") ||
00745 transport != SIP_TRANSPORT_TLS) {
00746 ast_test_status_update(test, "Test 4: tls host with custom port failed.\n");
00747 res = AST_TEST_FAIL;
00748 }
00749
00750
00751 sip_parse_host(host5, 1, &host, &port, &transport);
00752 if (port != 1234 || ast_strlen_zero(host) ||
00753 strcmp(host, "10.10.10.10") ||
00754 transport != SIP_TRANSPORT_UDP) {
00755 ast_test_status_update(test, "Test 5: simple host with custom port failed.\n");
00756 res = AST_TEST_FAIL;
00757 }
00758
00759
00760 if (!sip_parse_host(NULL, 1, &host, &port, &transport)) {
00761 ast_test_status_update(test, "Test 6: expected error on NULL input did not occur.\n");
00762 res = AST_TEST_FAIL;
00763 }
00764
00765 return res;
00766
00767 }
00768
00769
00770 void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags)
00771 {
00772 char *parse, *this;
00773
00774 if (!(parse = ast_strdupa(value))) {
00775 return;
00776 }
00777
00778
00779
00780 ast_set_flag(&mask[0], SIP_NAT_FORCE_RPORT);
00781 ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP);
00782 ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_RPORT);
00783 ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
00784
00785 while ((this = strsep(&parse, ","))) {
00786 if (ast_false(this)) {
00787 ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
00788 ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
00789 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
00790 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
00791 break;
00792 } else if (!strcasecmp(this, "yes")) {
00793 ast_log(LOG_WARNING, "nat=yes is deprecated, use nat=force_rport,comedia instead\n");
00794 ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
00795 ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
00796 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
00797 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
00798 break;
00799 } else if (!strcasecmp(this, "force_rport") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
00800 ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
00801 } else if (!strcasecmp(this, "comedia") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
00802 ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
00803 } else if (!strcasecmp(this, "auto_force_rport")) {
00804 ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
00805
00806 ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
00807 } else if (!strcasecmp(this, "auto_comedia")) {
00808 ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
00809
00810 ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
00811 }
00812 }
00813 }
00814
00815 #define TEST_FORCE_RPORT 1 << 0
00816 #define TEST_COMEDIA 1 << 1
00817 #define TEST_AUTO_FORCE_RPORT 1 << 2
00818 #define TEST_AUTO_COMEDIA 1 << 3
00819 static int match_nat_options(int val, struct ast_flags *flags)
00820 {
00821 if ((!ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)) != !(val & TEST_FORCE_RPORT)) {
00822 return 0;
00823 }
00824 if (!ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) != !(val & TEST_COMEDIA)) {
00825 return 0;
00826 }
00827 if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT) != !(val & TEST_AUTO_FORCE_RPORT)) {
00828 return 0;
00829 }
00830 if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) != !(val & TEST_AUTO_COMEDIA)) {
00831 return 0;
00832 }
00833 return 1;
00834 }
00835
00836 AST_TEST_DEFINE(sip_parse_nat_test)
00837 {
00838 int i, res = AST_TEST_PASS;
00839 struct ast_flags mask[3] = {{0}}, flags[3] = {{0}};
00840 struct {
00841 const char *str;
00842 int i;
00843 } options[] = {
00844 { "yes", TEST_FORCE_RPORT | TEST_COMEDIA },
00845 { "no", 0 },
00846 { "force_rport", TEST_FORCE_RPORT },
00847 { "comedia", TEST_COMEDIA },
00848 { "auto_force_rport", TEST_AUTO_FORCE_RPORT },
00849 { "auto_comedia", TEST_AUTO_COMEDIA },
00850 { "force_rport,auto_force_rport", TEST_AUTO_FORCE_RPORT },
00851 { "auto_force_rport,force_rport", TEST_AUTO_FORCE_RPORT },
00852 { "comedia,auto_comedia", TEST_AUTO_COMEDIA },
00853 { "auto_comedia,comedia", TEST_AUTO_COMEDIA },
00854 { "force_rport,comedia", TEST_FORCE_RPORT | TEST_COMEDIA },
00855 { "force_rport,auto_comedia", TEST_FORCE_RPORT | TEST_AUTO_COMEDIA },
00856 { "force_rport,yes,no", TEST_FORCE_RPORT | TEST_COMEDIA },
00857 { "auto_comedia,no,yes", 0 },
00858 };
00859
00860 switch (cmd) {
00861 case TEST_INIT:
00862 info->name = "sip_parse_nat_test";
00863 info->category = "/channels/chan_sip/";
00864 info->summary = "tests sip.conf nat line parsing";
00865 info->description =
00866 "Tests parsing of various nat line configurations. "
00867 "Verifies output matches expected behavior.";
00868 return AST_TEST_NOT_RUN;
00869 case TEST_EXECUTE:
00870 break;
00871 }
00872
00873 for (i = 0; i < ARRAY_LEN(options); i++) {
00874 sip_parse_nat_option(options[i].str, mask, flags);
00875 if (!match_nat_options(options[i].i, flags)) {
00876 ast_test_status_update(test, "Failed nat=%s\n", options[i].str);
00877 res = AST_TEST_FAIL;
00878 }
00879 memset(flags, 0, sizeof(flags));
00880 memset(mask, 0, sizeof(mask));
00881 }
00882
00883 return res;
00884 }
00885
00886 void sip_config_parser_register_tests(void)
00887 {
00888 AST_TEST_REGISTER(sip_parse_register_line_test);
00889 AST_TEST_REGISTER(sip_parse_host_line_test);
00890 AST_TEST_REGISTER(sip_parse_nat_test);
00891 }
00892
00893
00894 void sip_config_parser_unregister_tests(void)
00895 {
00896 AST_TEST_UNREGISTER(sip_parse_register_line_test);
00897 AST_TEST_UNREGISTER(sip_parse_host_line_test);
00898 AST_TEST_UNREGISTER(sip_parse_nat_test);
00899 }
00900