Wed May 16 06:33:31 2012

Asterisk developer's documentation


config_parser.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2010, Digium, Inc.
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*!
00018  * \file
00019  * \brief sip config parsing functions and unit tests
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 /*! \brief Parse register=> line in sip.conf
00031  *
00032  * \retval 0 on success
00033  * \retval -1 on failure
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    /* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] */
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    /*! register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
00088     * becomes
00089     *   userpart => [peer?][transport://]user[@domain][:secret[:authuser]]
00090     *   hostpart => host[:port][/extension][~expiry]
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     * pre1.peer => peer
00104     * pre1.userpart => [transport://]user[@domain][:secret[:authuser]]
00105     * hostpart => host[:port][/extension][~expiry]
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     * pre1.peer => peer
00115     * pre2.transport = transport
00116     * pre2.userpart => user[@domain][:secret[:authuser]]
00117     * hostpart => host[:port][/extension][~expiry]
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'; /* Remove trailing : */
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     * pre1.peer => peer
00134     * pre2.transport = transport
00135     * user1.userpart => user[@domain]
00136     * user1.secret => secret
00137     * user1.authuser => authuser
00138     * hostpart => host[:port][/extension][~expiry]
00139     */
00140    AST_NONSTANDARD_RAW_ARGS(user1, pre2.userpart, ':');
00141 
00142    /*!
00143     * pre1.peer => peer
00144     * pre2.transport = transport
00145     * user1.userpart => user[@domain]
00146     * user1.secret => secret
00147     * user1.authuser => authuser
00148     * host1.hostpart => host[:port][/extension]
00149     * host1.expiry => [expiry]
00150     */
00151    AST_NONSTANDARD_RAW_ARGS(host1, hostpart, '~');
00152 
00153    /*!
00154     * pre1.peer => peer
00155     * pre2.transport = transport
00156     * user1.userpart => user[@domain]
00157     * user1.secret => secret
00158     * user1.authuser => authuser
00159     * host2.hostpart => host[:port]
00160     * host2.extension => [extension]
00161     * host1.expiry => [expiry]
00162     */
00163    AST_NONSTANDARD_RAW_ARGS(host2, host1.hostpart, '/');
00164 
00165    /*!
00166     * pre1.peer => peer
00167     * pre2.transport = transport
00168     * user1.userpart => user[@domain]
00169     * user1.secret => secret
00170     * user1.authuser => authuser
00171     * host3.host => host
00172     * host3.port => port
00173     * host2.extension => extension
00174     * host1.expiry => expiry
00175     */
00176    AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':');
00177 
00178    /*!
00179      * pre1.peer => peer
00180      * pre2.transport = transport
00181      * user2.user => user
00182      * user2.domain => domain
00183      * user1.secret => secret
00184      * user1.authuser => authuser
00185      * host3.host => host
00186      * host3.port => port
00187      * host2.extension => extension
00188      * host1.expiry => expiry
00189     */
00190    AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
00191 
00192    /*!
00193      * pre1.peer => peer
00194      * pre2.transport = transport
00195      * user2.user => user
00196      * user2.domain => domain
00197      * user1.secret => secret
00198      * user3.authuser => authuser
00199      * user3.domainport => domainport
00200      * host3.host => host
00201      * host3.port => port
00202      * host2.extension => extension
00203      * host1.expiry => expiry
00204     */
00205    AST_NONSTANDARD_RAW_ARGS(user3, user1.authuser, ':');
00206 
00207    /* Reordering needed due to fields being [(:secret[:username])|(:regdomainport:secret:username)]
00208       but parsing being [secret[:username[:regdomainport]]] */
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    /* set transport type */
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    /* if no portnum specified, set default for transport */
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    /* copy into sip_registry object */
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    /* ---Test reg 1, simple config --- */
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    /* ---Test reg 2, add secret --- */
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    /* ---Test reg 3, add userdomain and authuser --- */
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    /* ---Test reg 4, add callback extension --- */
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    /* ---Test reg 5, add transport --- */
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    /* ---Test reg 6, change to tls transport, add expiry  --- */
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    /* ---Test reg 7, change transport to tcp, add custom port, and add peer --- */
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    /* ---Test reg 8, remove transport --- */
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    /* ---Test reg12, add domain port --- */
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    /* ---Test reg13, domain port without secret --- */
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    /* ---Test reg 9, missing domain, expected to fail --- */
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    /* ---Test reg 10,  missing user, expected to fail --- */
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    /* ---Test reg 11, no registry object, expected to fail--- */
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    /* ---Test reg 11,  no registry line, expected to fail --- */
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    /* test 1, simple host */
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    /* test 2, add tcp transport */
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    /* test 3, add tls transport */
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    /* test 4, add custom port with tls */
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    /* test 5, simple host with custom port */
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    /* test 6, expected failure with NULL input */
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 /*! \brief Parse the comma-separated nat= option values */
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    /* Since we need to completely override the general settings if we are being called
00779     * later for a peer, always set the flags for all options on the mask */
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; /* It doesn't make sense to have no + something else */
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; /* It doesn't make sense to have yes + something else */
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          /* In case someone did something dumb like nat=force_rport,auto_force_rport */
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          /* In case someone did something dumb like nat=comedia,auto_comedia*/
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 /*! \brief SIP test registration */
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 /*! \brief SIP test registration */
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 

Generated on Wed May 16 06:33:31 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6