Changeset 2864


Ignore:
Timestamp:
Aug 12, 2009 11:03:23 AM (10 years ago)
Author:
bennylp
Message:

Ticket #866: Allow application to specify more than one STUN servers for more robustness, and continue application startup if STUN resolution fails

PJSUA-LIB:

  • New fields in pjsua_config to specify more than one STUN servers (the stun_srv_cnt and stun_srv array)
  • The existing stun_host and stun_domain fields are deprecated, but backward compatibility is maintained. If stun_srv_cnt is zero, the library will import the entries from stun_host and stun_domain
  • The library will now resolve the STUN server entries one by one and test it before using it
  • New auxiliary API pjsua_resolve_stun_servers() to perform resolution and test against array of STUN servers

pjsua application:

  • The "stun-srv" command line options can now be specified more than once
Location:
pjproject/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r2862 r2864  
    191191    puts  ("  --publish           Send presence PUBLISH for this account"); 
    192192    puts  ("  --use-100rel        Require reliable provisional response (100rel)"); 
    193     puts  ("  --use-timer         Require session timers"); 
     193    puts  ("  --use-timer         Require SIP session timers"); 
    194194    puts  ("  --timer-se          Session timers expiration period, in secs (def:1800)"); 
    195195    puts  ("  --timer-min-se      Session timers minimum expiration period, in secs (def:90)"); 
     
    217217    puts  ("  --outbound=url      Set the URL of global outbound proxy server"); 
    218218    puts  ("                      May be specified multiple times"); 
    219     puts  ("  --stun-srv=name     Set STUN server host or domain"); 
     219    puts  ("  --stun-srv=FORMAT   Set STUN server host or domain. This option may be"); 
     220    puts  ("                      specified more than once. FORMAT is hostdom[:PORT]"); 
    220221    puts  (""); 
    221222    puts  ("TLS Options:"); 
     
    478479           OPT_BOUND_ADDR, OPT_CONTACT_PARAMS, OPT_CONTACT_URI_PARAMS, 
    479480           OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD, 
    480            OPT_NAMESERVER, OPT_STUN_DOMAIN, OPT_STUN_SRV, 
     481           OPT_NAMESERVER, OPT_STUN_SRV, 
    481482           OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, 
    482483           OPT_AUTO_ANSWER, OPT_AUTO_PLAY, OPT_AUTO_PLAY_HANGUP, OPT_AUTO_LOOP, 
     
    544545        { "password",   1, 0, OPT_PASSWORD}, 
    545546        { "nameserver", 1, 0, OPT_NAMESERVER}, 
    546         { "stun-domain",1, 0, OPT_STUN_DOMAIN}, 
    547547        { "stun-srv",   1, 0, OPT_STUN_SRV}, 
    548548        { "add-buddy",  1, 0, OPT_ADD_BUDDY}, 
     
    960960            break; 
    961961 
    962         case OPT_STUN_DOMAIN:   /* STUN domain */ 
    963             cfg->cfg.stun_domain = pj_str(pj_optarg); 
    964             break; 
    965  
    966962        case OPT_STUN_SRV:   /* STUN server */ 
    967963            cfg->cfg.stun_host = pj_str(pj_optarg); 
     964            if (cfg->cfg.stun_srv_cnt==PJ_ARRAY_SIZE(cfg->cfg.stun_srv)) { 
     965                PJ_LOG(1,(THIS_FILE, "Error: too many STUN servers")); 
     966                return PJ_ETOOMANY; 
     967            } 
     968            cfg->cfg.stun_srv[cfg->cfg.stun_srv_cnt++] = pj_str(pj_optarg); 
    968969            break; 
    969970 
     
    16161617 
    16171618    /* STUN */ 
    1618     if (config->cfg.stun_domain.slen) { 
    1619         pj_ansi_sprintf(line, "--stun-domain %.*s\n", 
    1620                         (int)config->cfg.stun_domain.slen,  
    1621                         config->cfg.stun_domain.ptr); 
    1622         pj_strcat2(&cfg, line); 
    1623     } 
    1624     if (config->cfg.stun_host.slen) { 
     1619    for (i=0; i<config->cfg.stun_srv_cnt; ++i) { 
    16251620        pj_ansi_sprintf(line, "--stun-srv %.*s\n", 
    1626                         (int)config->cfg.stun_host.slen,  
    1627                         config->cfg.stun_host.ptr); 
     1621                        (int)config->cfg.stun_srv[i].slen,  
     1622                        config->cfg.stun_srv[i].ptr); 
    16281623        pj_strcat2(&cfg, line); 
    16291624    } 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r2859 r2864  
    892892 
    893893    /** 
     894     * Warning: deprecated, please use \a stun_srv field instead. To maintain 
     895     * backward compatibility, if \a stun_srv_cnt is zero then the value of 
     896     * this field will be copied to \a stun_srv field, if present. 
     897     * 
    894898     * Specify domain name to be resolved with DNS SRV resolution to get the 
    895899     * address of the STUN server. Alternatively application may specify 
     
    902906 
    903907    /** 
     908     * Warning: deprecated, please use \a stun_srv field instead. To maintain 
     909     * backward compatibility, if \a stun_srv_cnt is zero then the value of 
     910     * this field will be copied to \a stun_srv field, if present. 
     911     * 
    904912     * Specify STUN server to be used, in "HOST[:PORT]" format. If port is 
    905913     * not specified, default port 3478 will be used. 
    906914     */ 
    907915    pj_str_t        stun_host; 
     916 
     917    /** 
     918     * Number of STUN server entries in \a stun_srv array. 
     919     */ 
     920    unsigned        stun_srv_cnt; 
     921 
     922    /** 
     923     * Array of STUN servers to try. The library will try to resolve and 
     924     * contact each of the STUN server entry until it finds one that is 
     925     * usable. Each entry may be a domain name, host name, IP address, and 
     926     * it may contain an optional port number. For example: 
     927     *  - "pjsip.org" (domain name) 
     928     *  - "sip.pjsip.org" (host name) 
     929     *  - "pjsip.org:33478" (domain name and a non-standard port number) 
     930     *  - "10.0.0.1:3478" (IP address and port number) 
     931     * 
     932     * When nameserver is configured in the \a pjsua_config.nameserver field, 
     933     * if entry is not an IP address, it will be resolved with DNS SRV  
     934     * resolution first, and it will fallback to use DNS A resolution if this 
     935     * fails. Port number may be specified even if the entry is a domain name, 
     936     * in case the DNS SRV resolution should fallback to a non-standard port. 
     937     * 
     938     * When nameserver is not configured, entries will be resolved with 
     939     * #pj_gethostbyname() if it's not an IP address. Port number may be 
     940     * specified if the server is not listening in standard STUN port. 
     941     */ 
     942    pj_str_t        stun_srv[8]; 
     943 
     944    /** 
     945     * This specifies if the library startup should ignore failure with the 
     946     * STUN servers. If this is set to PJ_FALSE, the library will refuse to 
     947     * start if it fails to resolve or contact any of the STUN servers. 
     948     * 
     949     * Default: PJ_TRUE 
     950     */ 
     951    pj_bool_t       stun_ignore_failure; 
    908952 
    909953    /** 
     
    12141258 * 
    12151259 */ 
     1260 
     1261/** 
     1262 * This structure is used to represent the result of the STUN server  
     1263 * resolution and testing, the #pjsua_resolve_stun_servers() function. 
     1264 * This structure will be passed in #pj_stun_resolve_cb callback. 
     1265 */ 
     1266typedef struct pj_stun_resolve_result 
     1267{ 
     1268    /** 
     1269     * Arbitrary data that was passed to #pjsua_resolve_stun_servers() 
     1270     * function. 
     1271     */ 
     1272    void            *token; 
     1273 
     1274    /** 
     1275     * This will contain PJ_SUCCESS if at least one usable STUN server 
     1276     * is found, otherwise it will contain the last error code during 
     1277     * the operation. 
     1278     */ 
     1279    pj_status_t      status; 
     1280 
     1281    /** 
     1282     * The server name that yields successful result. This will only 
     1283     * contain value if status is successful. 
     1284     */ 
     1285    pj_str_t         name; 
     1286 
     1287    /** 
     1288     * The server IP address. This will only contain value if status  
     1289     * is successful. 
     1290     */ 
     1291    pj_sockaddr      addr; 
     1292 
     1293} pj_stun_resolve_result; 
     1294 
     1295 
     1296/** 
     1297 * Typedef of callback to be registered to #pjsua_resolve_stun_servers(). 
     1298 */ 
     1299typedef void (*pj_stun_resolve_cb)(const pj_stun_resolve_result *result); 
    12161300 
    12171301/** 
     
    12511335 */ 
    12521336PJ_DECL(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type); 
     1337 
     1338 
     1339/** 
     1340 * Auxiliary function to resolve and contact each of the STUN server 
     1341 * entries (sequentially) to find which is usable. The #pjsua_init() must 
     1342 * have been called before calling this function. 
     1343 * 
     1344 * @param count         Number of STUN server entries to try. 
     1345 * @param srv           Array of STUN server entries to try. Please see 
     1346 *                      the \a stun_srv field in the #pjsua_config  
     1347 *                      documentation about the format of this entry. 
     1348 * @param wait          Specify non-zero to make the function block until 
     1349 *                      it gets the result. In this case, the function 
     1350 *                      will block while the resolution is being done, 
     1351 *                      and the callback will be called before this function 
     1352 *                      returns. 
     1353 * @param token         Arbitrary token to be passed back to application 
     1354 *                      in the callback. 
     1355 * @param cb            Callback to be called to notify the result of 
     1356 *                      the function. 
     1357 * 
     1358 * @return              If \a wait parameter is non-zero, this will return 
     1359 *                      PJ_SUCCESS if one usable STUN server is found. 
     1360 *                      Otherwise it will always return PJ_SUCCESS, and 
     1361 *                      application will be notified about the result in 
     1362 *                      the callback. 
     1363 */ 
     1364PJ_DECL(pj_status_t) pjsua_resolve_stun_servers(unsigned count, 
     1365                                                pj_str_t srv[], 
     1366                                                pj_bool_t wait, 
     1367                                                void *token, 
     1368                                                pj_stun_resolve_cb cb); 
     1369 
     1370/** 
     1371 * Cancel pending STUN resolution which match the specified token.  
     1372 * 
     1373 * @param token         The token to match. This token was given to  
     1374 *                      #pjsua_resolve_stun_servers() 
     1375 * @param notify_cb     Boolean to control whether the callback should 
     1376 *                      be called for cancelled resolutions. When the 
     1377 *                      callback is called, the status in the result 
     1378 *                      will be set as PJ_ECANCELLED. 
     1379 * 
     1380 * @return              PJ_SUCCESS if there is at least one pending STUN 
     1381 *                      resolution cancelled, or PJ_ENOTFOUND if there is 
     1382 *                      no matching one, or other error. 
     1383 */ 
     1384PJ_DECL(pj_status_t) pjsua_cancel_stun_resolution(void *token, 
     1385                                                  pj_bool_t notify_cb); 
    12531386 
    12541387 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r2855 r2864  
    213213} pjsua_conf_setting; 
    214214 
     215typedef struct pjsua_stun_resolve 
     216{ 
     217    PJ_DECL_LIST_MEMBER(struct pjsua_stun_resolve); 
     218 
     219    pj_pool_t           *pool;      /**< Pool               */ 
     220    unsigned             count;     /**< # of entries       */ 
     221    pj_str_t            *srv;       /**< Array of entries   */ 
     222    unsigned             idx;       /**< Current index      */ 
     223    void                *token;     /**< App token          */ 
     224    pj_stun_resolve_cb   cb;        /**< App callback       */ 
     225    pj_bool_t            blocking;  /**< Blocking?          */ 
     226    pj_status_t          status;    /**< Session status     */ 
     227    pj_sockaddr          addr;      /**< Result             */ 
     228    pj_stun_sock        *stun_sock; /**< Testing STUN sock  */ 
     229} pjsua_stun_resolve; 
     230 
    215231 
    216232/** 
     
    242258    pj_sockaddr          stun_srv;  /**< Resolved STUN server address   */ 
    243259    pj_status_t          stun_status; /**< STUN server status.          */ 
     260    pjsua_stun_resolve   stun_res;  /**< List of pending STUN resolution*/ 
    244261    pj_dns_resolver     *resolver;  /**< DNS resolver.                  */ 
    245262 
     
    351368#endif 
    352369 
     370/****** 
     371 * STUN resolution 
     372 */ 
     373/* Resolve the STUN server */ 
     374pj_status_t resolve_stun_server(pj_bool_t wait); 
     375 
    353376/**  
    354377 * Normalize route URI (check for ";lr" and append one if it doesn't 
     
    356379 */ 
    357380pj_status_t normalize_route_uri(pj_pool_t *pool, pj_str_t *uri); 
    358  
    359 /** 
    360  * Resolve STUN server. 
    361  */ 
    362 pj_status_t pjsua_resolve_stun_server(pj_bool_t wait); 
    363381 
    364382/** 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r2859 r2864  
    2525 
    2626 
     27/* Internal prototypes */ 
     28static void resolve_stun_entry(pjsua_stun_resolve *sess); 
     29 
     30 
    2731/* PJSUA application instance. */ 
    2832struct pjsua_data pjsua_var; 
     
    6064    pjsua_var.stun_status = PJ_EUNKNOWN; 
    6165    pjsua_var.nat_status = PJ_EPENDING; 
     66    pj_list_init(&pjsua_var.stun_res); 
    6267} 
    6368 
     
    9398    cfg->thread_cnt = 1; 
    9499    cfg->nat_type_in_sdp = 1; 
     100    cfg->stun_ignore_failure = PJ_TRUE; 
    95101    cfg->force_lr = PJ_TRUE; 
    96102#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     
    123129    pj_strdup_with_null(pool, &dst->stun_domain, &src->stun_domain); 
    124130    pj_strdup_with_null(pool, &dst->stun_host, &src->stun_host); 
     131 
     132    for (i=0; i<src->stun_srv_cnt; ++i) { 
     133        pj_strdup_with_null(pool, &dst->stun_srv[i], &src->stun_srv[i]); 
     134    } 
    125135} 
    126136 
     
    762772        goto on_error; 
    763773 
     774    /* Convert deprecated STUN settings */ 
     775    if (pjsua_var.ua_cfg.stun_srv_cnt==0) { 
     776        if (pjsua_var.ua_cfg.stun_domain.slen) { 
     777            pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] =  
     778                pjsua_var.ua_cfg.stun_domain; 
     779        } 
     780        if (pjsua_var.ua_cfg.stun_host.slen) { 
     781            pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] =  
     782                pjsua_var.ua_cfg.stun_host; 
     783        } 
     784    } 
    764785 
    765786    /* Start resolving STUN server */ 
    766  
    767     status = pjsua_resolve_stun_server(PJ_FALSE); 
     787    status = resolve_stun_server(PJ_FALSE); 
    768788    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    769789        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     
    860880} 
    861881 
    862  
    863 /* 
    864  * Callback function to receive notification from the resolver 
    865  * when the resolution process completes. 
    866  */ 
    867 static void stun_dns_srv_resolver_cb(void *user_data, 
    868                                      pj_status_t status, 
    869                                      const pj_dns_srv_record *rec) 
    870 { 
     882/* Internal function to destroy STUN resolution session 
     883 * (pj_stun_resolve). 
     884 */ 
     885static void destroy_stun_resolve(pjsua_stun_resolve *sess) 
     886{ 
     887    PJSUA_LOCK(); 
     888    pj_list_erase(sess); 
     889    PJSUA_UNLOCK(); 
     890 
     891    pj_assert(sess->stun_sock==NULL); 
     892    pj_pool_release(sess->pool); 
     893} 
     894 
     895/* This is the internal function to be called when STUN resolution 
     896 * session (pj_stun_resolve) has completed. 
     897 */ 
     898static void stun_resolve_complete(pjsua_stun_resolve *sess) 
     899{ 
     900    pj_stun_resolve_result result; 
     901 
     902    pj_bzero(&result, sizeof(result)); 
     903    result.token = sess->token; 
     904    result.status = sess->status; 
     905    result.name = sess->srv[sess->idx]; 
     906    pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr)); 
     907 
     908    if (result.status == PJ_SUCCESS) { 
     909        char addr[PJ_INET6_ADDRSTRLEN+10]; 
     910        pj_sockaddr_print(&result.addr, addr, sizeof(addr), 3); 
     911        PJ_LOG(4,(THIS_FILE,  
     912                  "STUN resolution success, using %.*s, address is %s", 
     913                  (int)sess->srv[sess->idx].slen, 
     914                  sess->srv[sess->idx].ptr, 
     915                  addr)); 
     916    } else { 
     917        char errmsg[PJ_ERR_MSG_SIZE]; 
     918        pj_strerror(result.status, errmsg, sizeof(errmsg)); 
     919        PJ_LOG(1,(THIS_FILE, "STUN resolution failed: %s", errmsg)); 
     920    } 
     921 
     922    sess->cb(&result); 
     923 
     924    if (!sess->blocking) { 
     925        destroy_stun_resolve(sess); 
     926    } 
     927} 
     928 
     929/* This is the callback called by the STUN socket (pj_stun_sock) 
     930 * to report it's state. We use this as part of testing the 
     931 * STUN server. 
     932 */ 
     933static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock,  
     934                                     pj_stun_sock_op op, 
     935                                     pj_status_t status) 
     936{ 
     937    pjsua_stun_resolve *sess; 
     938 
     939    sess = pj_stun_sock_get_user_data(stun_sock); 
     940    pj_assert(stun_sock == sess->stun_sock); 
     941 
     942    if (status != PJ_SUCCESS) { 
     943        char errmsg[PJ_ERR_MSG_SIZE]; 
     944        pj_strerror(status, errmsg, sizeof(errmsg)); 
     945 
     946        PJ_LOG(4,(THIS_FILE, "STUN resolution for %.*s failed: %s", 
     947                  (int)sess->srv[sess->idx].slen, 
     948                  sess->srv[sess->idx].ptr, errmsg)); 
     949 
     950        sess->status = status; 
     951 
     952        pj_stun_sock_destroy(stun_sock); 
     953        sess->stun_sock = NULL; 
     954 
     955        ++sess->idx; 
     956        resolve_stun_entry(sess); 
     957 
     958        return PJ_FALSE; 
     959 
     960    } else if (op == PJ_STUN_SOCK_BINDING_OP) { 
     961        pj_stun_sock_info ssi; 
     962 
     963        pj_stun_sock_get_info(stun_sock, &ssi); 
     964        pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr)); 
     965 
     966        sess->status = PJ_SUCCESS; 
     967        pj_stun_sock_destroy(stun_sock); 
     968        sess->stun_sock = NULL; 
     969 
     970        stun_resolve_complete(sess); 
     971 
     972        return PJ_FALSE; 
     973 
     974    } else 
     975        return PJ_TRUE; 
     976     
     977} 
     978 
     979/* This is an internal function to resolve and test current 
     980 * server entry in pj_stun_resolve session. It is called by 
     981 * pjsua_resolve_stun_servers() and test_stun_on_status() above 
     982 */ 
     983static void resolve_stun_entry(pjsua_stun_resolve *sess) 
     984{ 
     985    /* Loop while we have entry to try */ 
     986    for (; sess->idx < sess->count; ++sess->idx) { 
     987        const int af = pj_AF_INET(); 
     988        pj_str_t hostpart; 
     989        pj_uint16_t port; 
     990        pj_stun_sock_cb stun_sock_cb; 
     991         
     992        pj_assert(sess->idx < sess->count); 
     993 
     994        /* Parse the server entry into host:port */ 
     995        sess->status = pj_sockaddr_parse2(af, 0, &sess->srv[sess->idx], 
     996                                          &hostpart, &port, NULL); 
     997        if (sess->status != PJ_SUCCESS) { 
     998            PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %.*s",  
     999                      (int)sess->srv[sess->idx].slen,  
     1000                      sess->srv[sess->idx].ptr)); 
     1001            continue; 
     1002        } 
     1003         
     1004        /* Use default port if not specified */ 
     1005        if (port == 0) 
     1006            port = PJ_STUN_PORT; 
     1007 
     1008        pj_assert(sess->stun_sock == NULL); 
     1009 
     1010        PJ_LOG(4,(THIS_FILE, "Trying STUN server %.*s (%d of %d)..", 
     1011                  (int)sess->srv[sess->idx].slen, 
     1012                  sess->srv[sess->idx].ptr, 
     1013                  sess->idx+1, sess->count)); 
     1014 
     1015        /* Use STUN_sock to test this entry */ 
     1016        pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 
     1017        stun_sock_cb.on_status = &test_stun_on_status; 
     1018        sess->status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve", 
     1019                                           pj_AF_INET(), &stun_sock_cb, 
     1020                                           NULL, sess, &sess->stun_sock); 
     1021        if (sess->status != PJ_SUCCESS) { 
     1022            char errmsg[PJ_ERR_MSG_SIZE]; 
     1023            pj_strerror(sess->status, errmsg, sizeof(errmsg)); 
     1024            PJ_LOG(4,(THIS_FILE,  
     1025                     "Error creating STUN socket for %.*s: %s", 
     1026                      (int)sess->srv[sess->idx].slen, 
     1027                      sess->srv[sess->idx].ptr, errmsg)); 
     1028 
     1029            continue; 
     1030        } 
     1031 
     1032        sess->status = pj_stun_sock_start(sess->stun_sock, &hostpart, 
     1033                                          port, pjsua_var.resolver); 
     1034        if (sess->status != PJ_SUCCESS) { 
     1035            char errmsg[PJ_ERR_MSG_SIZE]; 
     1036            pj_strerror(sess->status, errmsg, sizeof(errmsg)); 
     1037            PJ_LOG(4,(THIS_FILE,  
     1038                     "Error starting STUN socket for %.*s: %s", 
     1039                      (int)sess->srv[sess->idx].slen, 
     1040                      sess->srv[sess->idx].ptr, errmsg)); 
     1041 
     1042            pj_stun_sock_destroy(sess->stun_sock); 
     1043            sess->stun_sock = NULL; 
     1044            continue; 
     1045        } 
     1046 
     1047        /* Done for now, testing will resume/complete asynchronously in 
     1048         * stun_sock_cb() 
     1049         */ 
     1050        return; 
     1051    } 
     1052 
     1053    if (sess->idx >= sess->count) { 
     1054        /* No more entries to try */ 
     1055        PJ_ASSERT_ON_FAIL(sess->status != PJ_SUCCESS,  
     1056                          sess->status = PJ_EUNKNOWN); 
     1057        stun_resolve_complete(sess); 
     1058    } 
     1059} 
     1060 
     1061 
     1062/* 
     1063 * Resolve STUN server. 
     1064 */ 
     1065PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count, 
     1066                                                pj_str_t srv[], 
     1067                                                pj_bool_t wait, 
     1068                                                void *token, 
     1069                                                pj_stun_resolve_cb cb) 
     1070{ 
     1071    pj_pool_t *pool; 
     1072    pjsua_stun_resolve *sess; 
     1073    pj_status_t status; 
    8711074    unsigned i; 
    8721075 
    873     PJ_UNUSED_ARG(user_data); 
    874  
    875     pjsua_var.stun_status = status; 
    876      
    877     if (status != PJ_SUCCESS) { 
    878         /* DNS SRV resolution failed. If stun_host is specified, resolve 
    879          * it with gethostbyname() 
    880          */ 
    881         if (pjsua_var.ua_cfg.stun_host.slen) { 
    882             pjsua_var.stun_status =  
    883                 pj_sockaddr_parse(pj_AF_INET(), 0, 
    884                                   &pjsua_var.ua_cfg.stun_host, 
    885                                   &pjsua_var.stun_srv); 
    886             if (pjsua_var.stun_status != PJ_SUCCESS) { 
    887                 pjsua_perror(THIS_FILE, "Invalid STUN server",  
    888                              pjsua_var.stun_status); 
    889             } else { 
    890                 if (pj_sockaddr_get_port(&pjsua_var.stun_srv)==0) 
    891                     pj_sockaddr_set_port(&pjsua_var.stun_srv, 3478); 
    892  
    893                 PJ_LOG(3,(THIS_FILE,  
    894                           "STUN server %.*s resolved, address is %s:%d", 
    895                           (int)pjsua_var.ua_cfg.stun_host.slen, 
    896                           pjsua_var.ua_cfg.stun_host.ptr, 
    897                           pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr), 
    898                           (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port))); 
     1076    PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL); 
     1077 
     1078    pool = pjsua_pool_create("stunres", 256, 256); 
     1079    if (!pool) 
     1080        return PJ_ENOMEM; 
     1081 
     1082    sess = PJ_POOL_ZALLOC_T(pool, pjsua_stun_resolve); 
     1083    sess->pool = pool; 
     1084    sess->token = token; 
     1085    sess->cb = cb; 
     1086    sess->count = count; 
     1087    sess->blocking = wait; 
     1088    sess->status = PJ_EPENDING; 
     1089    sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t)); 
     1090    for (i=0; i<count; ++i) { 
     1091        pj_strdup(pool, &sess->srv[i], &srv[i]); 
     1092    } 
     1093 
     1094    PJSUA_LOCK(); 
     1095    pj_list_push_back(&pjsua_var.stun_res, sess); 
     1096    PJSUA_UNLOCK(); 
     1097 
     1098    resolve_stun_entry(sess); 
     1099 
     1100    if (!wait) 
     1101        return PJ_SUCCESS; 
     1102 
     1103    while (sess->status == PJ_EPENDING) { 
     1104        pjsua_handle_events(50); 
     1105    } 
     1106 
     1107    status = sess->status; 
     1108    destroy_stun_resolve(sess); 
     1109 
     1110    return status; 
     1111} 
     1112 
     1113/* 
     1114 * Cancel pending STUN resolution. 
     1115 */ 
     1116PJ_DEF(pj_status_t) pjsua_cancel_stun_resolution( void *token, 
     1117                                                  pj_bool_t notify_cb) 
     1118{ 
     1119    pjsua_stun_resolve *sess; 
     1120    unsigned cancelled_count = 0; 
     1121 
     1122    PJSUA_LOCK(); 
     1123    sess = pjsua_var.stun_res.next; 
     1124    while (sess != &pjsua_var.stun_res) { 
     1125        pjsua_stun_resolve *next = sess->next; 
     1126 
     1127        if (sess->token == token) { 
     1128            if (notify_cb) { 
     1129                pj_stun_resolve_result result; 
     1130 
     1131                pj_bzero(&result, sizeof(result)); 
     1132                result.token = token; 
     1133                result.status = PJ_ECANCELLED; 
     1134 
     1135                sess->cb(&result); 
    8991136            } 
    900         } else { 
    901             char errmsg[PJ_ERR_MSG_SIZE]; 
    902  
    903             pj_strerror(status, errmsg, sizeof(errmsg)); 
    904             PJ_LOG(1,(THIS_FILE,  
    905                      "DNS SRV resolution failed for STUN server %.*s: %s", 
    906                      (int)pjsua_var.ua_cfg.stun_domain.slen, 
    907                      pjsua_var.ua_cfg.stun_domain.ptr, 
    908                      errmsg)); 
    909         } 
    910         return; 
    911     } 
    912  
    913     pj_assert(rec->count != 0 && rec->entry[0].server.addr_count != 0); 
    914     pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 
    915                         rec->entry[0].port); 
    916     pjsua_var.stun_srv.ipv4.sin_addr.s_addr =  
    917         rec->entry[0].server.addr[0].s_addr; 
    918  
    919     PJ_LOG(3,(THIS_FILE, "_stun._udp.%.*s resolved, found %d entry(s):", 
    920               (int)pjsua_var.ua_cfg.stun_domain.slen, 
    921               pjsua_var.ua_cfg.stun_domain.ptr, 
    922               rec->count)); 
    923  
    924     for (i=0; i<rec->count; ++i) { 
    925         PJ_LOG(3,(THIS_FILE,  
    926                   " %d: prio=%d, weight=%d  %s:%d",  
    927                   i, rec->entry[i].priority, rec->entry[i].weight, 
    928                   pj_inet_ntoa(rec->entry[i].server.addr[0]), 
    929                   (int)rec->entry[i].port)); 
    930     } 
    931  
     1137 
     1138            destroy_stun_resolve(sess); 
     1139            ++cancelled_count; 
     1140        } 
     1141 
     1142        sess = next; 
     1143    } 
     1144    PJSUA_UNLOCK(); 
     1145 
     1146    return cancelled_count ? PJ_SUCCESS : PJ_ENOTFOUND; 
     1147} 
     1148 
     1149static void internal_stun_resolve_cb(const pj_stun_resolve_result *result) 
     1150{ 
     1151    pjsua_var.stun_status = result->status; 
     1152    if (result->status == PJ_SUCCESS) { 
     1153        pj_memcpy(&pjsua_var.stun_srv, &result->addr, sizeof(result->addr)); 
     1154    } 
    9321155} 
    9331156 
     
    9351158 * Resolve STUN server. 
    9361159 */ 
    937 pj_status_t pjsua_resolve_stun_server(pj_bool_t wait) 
     1160pj_status_t resolve_stun_server(pj_bool_t wait) 
    9381161{ 
    9391162    if (pjsua_var.stun_status == PJ_EUNKNOWN) { 
     1163        pj_status_t status; 
     1164 
    9401165        /* Initialize STUN configuration */ 
    9411166        pj_stun_config_init(&pjsua_var.stun_cfg, &pjsua_var.cp.factory, 0, 
     
    9441169 
    9451170        /* Start STUN server resolution */ 
    946          
    947         pjsua_var.stun_status = PJ_EPENDING; 
    948  
    949         /* If stun_domain is specified, resolve STUN servers with DNS 
    950          * SRV resolution. 
    951          */ 
    952         if (pjsua_var.ua_cfg.stun_domain.slen) { 
    953             pj_str_t res_type; 
    954             pj_status_t status; 
    955  
    956             /* Fail if resolver is not configured */ 
    957             if (pjsua_var.resolver == NULL) { 
    958                 PJ_LOG(1,(THIS_FILE, "Nameserver must be configured when " 
    959                                      "stun_domain is specified")); 
    960                 pjsua_var.stun_status = PJLIB_UTIL_EDNSNONS; 
    961                 return PJLIB_UTIL_EDNSNONS; 
     1171        if (pjsua_var.ua_cfg.stun_srv_cnt) { 
     1172            pjsua_var.stun_status = PJ_EPENDING; 
     1173            status = pjsua_resolve_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt, 
     1174                                                pjsua_var.ua_cfg.stun_srv, 
     1175                                                wait, NULL, 
     1176                                                &internal_stun_resolve_cb); 
     1177            if (wait || status != PJ_SUCCESS) { 
     1178                pjsua_var.stun_status = status; 
    9621179            } 
    963             res_type = pj_str("_stun._udp"); 
    964             status =  
    965                 pj_dns_srv_resolve(&pjsua_var.ua_cfg.stun_domain, &res_type, 
    966                                    3478, pjsua_var.pool, pjsua_var.resolver, 
    967                                    0, NULL, &stun_dns_srv_resolver_cb, NULL); 
    968             if (status != PJ_SUCCESS) { 
    969                 pjsua_perror(THIS_FILE, "Error starting DNS SRV resolution",  
    970                              pjsua_var.stun_status); 
    971                 pjsua_var.stun_status = status; 
    972                 return pjsua_var.stun_status; 
    973             } else { 
    974                 pjsua_var.stun_status = PJ_EPENDING; 
    975             } 
    976         } 
    977         /* Otherwise if stun_host is specified, resolve STUN server with 
    978          * gethostbyname(). 
    979          */ 
    980         else if (pjsua_var.ua_cfg.stun_host.slen) { 
    981             pjsua_var.stun_status =  
    982                 pj_sockaddr_parse(pj_AF_INET(), 0, 
    983                                   &pjsua_var.ua_cfg.stun_host, 
    984                                   &pjsua_var.stun_srv); 
    985             if (pjsua_var.stun_status != PJ_SUCCESS) { 
    986                 pjsua_perror(THIS_FILE, "Invalid STUN server",  
    987                                         pjsua_var.stun_status); 
    988                 return pjsua_var.stun_status; 
    989             } 
    990  
    991             if (pj_sockaddr_get_port(&pjsua_var.stun_srv)==0) 
    992                 pj_sockaddr_set_port(&pjsua_var.stun_srv, 3478); 
    993  
    994             PJ_LOG(3,(THIS_FILE,  
    995                       "STUN server %.*s resolved, address is %s:%d", 
    996                       (int)pjsua_var.ua_cfg.stun_host.slen, 
    997                       pjsua_var.ua_cfg.stun_host.ptr, 
    998                       pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr), 
    999                       (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port))); 
    1000  
    1001         } 
    1002         /* Otherwise disable STUN. */ 
    1003         else { 
     1180        } else { 
    10041181            pjsua_var.stun_status = PJ_SUCCESS; 
    10051182        } 
    1006  
    1007  
    1008         return pjsua_var.stun_status; 
    10091183 
    10101184    } else if (pjsua_var.stun_status == PJ_EPENDING) { 
     
    10161190                pjsua_handle_events(10); 
    10171191        } 
    1018  
    1019         return pjsua_var.stun_status; 
    1020  
    1021     } else { 
    1022         /* STUN server has been resolved, return the status */ 
    1023         return pjsua_var.stun_status; 
    1024     } 
     1192    } 
     1193 
     1194    if (pjsua_var.stun_status != PJ_EPENDING && 
     1195        pjsua_var.stun_status != PJ_SUCCESS && 
     1196        pjsua_var.ua_cfg.stun_ignore_failure) 
     1197    { 
     1198        PJ_LOG(2,(THIS_FILE,  
     1199                  "Ignoring STUN resolution failure (by setting)")); 
     1200        pjsua_var.stun_status = PJ_SUCCESS; 
     1201    } 
     1202 
     1203    return pjsua_var.stun_status; 
    10251204} 
    10261205 
     
    10751254    /* Destroy endpoint. */ 
    10761255    if (pjsua_var.endpt) { 
     1256 
     1257        /* Terminate any pending STUN resolution */ 
     1258        if (!pj_list_empty(&pjsua_var.stun_res)) { 
     1259            pjsua_stun_resolve *sess = pjsua_var.stun_res.next; 
     1260            while (sess != &pjsua_var.stun_res) { 
     1261                pjsua_stun_resolve *next = sess->next; 
     1262                destroy_stun_resolve(sess); 
     1263                sess = next; 
     1264            } 
     1265        } 
     1266 
    10771267        /* Wait for some time to allow unregistration and ICE/TURN 
    10781268         * transports shutdown to complete:  
     
    12711461 
    12721462    /* Make sure STUN server resolution has completed */ 
    1273     status = pjsua_resolve_stun_server(PJ_TRUE); 
     1463    status = resolve_stun_server(PJ_TRUE); 
    12741464    if (status != PJ_SUCCESS) { 
    12751465        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     
    19832173 
    19842174    /* Make sure STUN server resolution has completed */ 
    1985     status = pjsua_resolve_stun_server(PJ_TRUE); 
     2175    status = resolve_stun_server(PJ_TRUE); 
    19862176    if (status != PJ_SUCCESS) { 
    19872177        pjsua_var.nat_status = status; 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r2837 r2864  
    360360 
    361361    /* Make sure STUN server resolution has completed */ 
    362     status = pjsua_resolve_stun_server(PJ_TRUE); 
     362    status = resolve_stun_server(PJ_TRUE); 
    363363    if (status != PJ_SUCCESS) { 
    364364        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     
    861861 
    862862    /* Make sure STUN server resolution has completed */ 
    863     status = pjsua_resolve_stun_server(PJ_TRUE); 
     863    status = resolve_stun_server(PJ_TRUE); 
    864864    if (status != PJ_SUCCESS) { 
    865865        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
Note: See TracChangeset for help on using the changeset viewer.