Ignore:
Timestamp:
Dec 28, 2016 3:40:07 AM (8 years ago)
Author:
nanang
Message:

Re #1900: More merged from trunk (r5512 mistakenly contains merged changes in third-party dir only).

Location:
pjproject/branches/projects/uwp
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/uwp

  • pjproject/branches/projects/uwp/pjsip/src/pjsua-lib/pjsua_core.c

    r5170 r5513  
    278278#if PJMEDIA_HAS_VIDEO 
    279279    pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg); 
     280    pjmedia_vid_stream_sk_config_default(&cfg->vid_stream_sk_cfg); 
    280281#endif 
    281282    pjsua_transport_config_default(&cfg->rtp_cfg); 
     
    303304    cfg->register_on_acc_add = PJ_TRUE; 
    304305    cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES; 
     306 
     307    cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE; 
    305308} 
    306309 
     
    10501053 
    10511054    /* Start resolving STUN server */ 
    1052     status = resolve_stun_server(PJ_FALSE); 
     1055    status = resolve_stun_server(PJ_FALSE, PJ_FALSE); 
    10531056    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    10541057        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     
    11061109 
    11071110        for (ii=0; ii<pjsua_var.ua_cfg.thread_cnt; ++ii) { 
    1108             status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread, 
     1111            char thread_name[16]; 
     1112            pj_ansi_snprintf(thread_name, 16, "pjsua_%d", ii); 
     1113            status = pj_thread_create(pjsua_var.pool, thread_name, &worker_thread, 
    11091114                                      NULL, 0, 0, &pjsua_var.thread[ii]); 
    11101115            if (status != PJ_SUCCESS) 
     
    11551160} 
    11561161 
     1162 
     1163static void destroy_stun_resolve_cb(pj_timer_heap_t *t, pj_timer_entry *e) 
     1164{ 
     1165    pjsua_stun_resolve *sess = (pjsua_stun_resolve*)e->user_data; 
     1166    PJ_UNUSED_ARG(t); 
     1167 
     1168    PJSUA_LOCK(); 
     1169    pj_list_erase(sess); 
     1170    PJSUA_UNLOCK(); 
     1171 
     1172    pj_assert(sess->stun_sock==NULL); 
     1173    pj_pool_release(sess->pool); 
     1174} 
     1175 
     1176 
    11571177static void destroy_stun_resolve(pjsua_stun_resolve *sess) 
    11581178{ 
     1179    pj_time_val timeout = {0, 0}; 
     1180 
    11591181    sess->destroy_flag = PJ_TRUE; 
    1160     if (sess->ref_cnt > 0) 
     1182 
     1183    /* If the STUN resolution session is blocking, only the waiting thread 
     1184     * is allowed to destroy the session, otherwise it may cause deadlock. 
     1185     */ 
     1186    if (sess->blocking) { 
     1187        if (sess->waiter != pj_thread_this()) 
     1188            return; 
     1189 
     1190        /* Before destroying, make sure ref count is zero. */ 
     1191        while (sess->ref_cnt > 0) 
     1192            pj_thread_sleep(10); 
     1193 
     1194    } else if (sess->ref_cnt > 0) 
    11611195        return; 
    1162  
    1163     PJSUA_LOCK(); 
    11641196 
    11651197    if (sess->stun_sock) { 
     
    11741206    } 
    11751207     
    1176     pj_list_erase(sess); 
    1177  
    1178     PJSUA_UNLOCK(); 
    1179  
    1180     pj_assert(sess->stun_sock==NULL); 
    1181     pj_pool_release(sess->pool); 
     1208    /* Schedule session clean up, it needs PJSUA lock and locking it here 
     1209     * may cause deadlock as this function may be called by STUN socket 
     1210     * while holding STUN socket lock, while application may wait for STUN 
     1211     * resolution while holding PJSUA lock. 
     1212     */ 
     1213    pj_timer_entry_init(&sess->timer, 0, (void*)sess, 
     1214                        &destroy_stun_resolve_cb); 
     1215    pjsua_schedule_timer(&sess->timer, &timeout); 
    11821216} 
    11831217 
     
    12041238    result.status = sess->status; 
    12051239    result.name = sess->srv[sess->idx]; 
     1240    result.index = sess->idx; 
    12061241    pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr)); 
    12071242    sess->has_result = PJ_TRUE; 
     
    12211256    } 
    12221257 
    1223     stun_resolve_add_ref(sess); 
    12241258    sess->cb(&result); 
    1225     stun_resolve_dec_ref(sess); 
    12261259 
    12271260on_return: 
     
    12521285                  sess->srv[sess->idx].ptr, errmsg)); 
    12531286 
     1287        if (op == PJ_STUN_SOCK_BINDING_OP && !sess->async_wait) { 
     1288            /* Just return here, we will destroy the STUN socket and 
     1289             * continue the STUN resolution later in resolve_stun_entry(). 
     1290             * For more details, please refer to ticket #1962. 
     1291             */ 
     1292            return PJ_FALSE; 
     1293        } 
     1294 
    12541295        pj_stun_sock_destroy(stun_sock); 
    12551296        sess->stun_sock = NULL; 
     1297 
     1298        stun_resolve_add_ref(sess); 
    12561299 
    12571300        ++sess->idx; 
     
    12611304        resolve_stun_entry(sess); 
    12621305 
     1306        stun_resolve_dec_ref(sess); 
     1307 
    12631308        return PJ_FALSE; 
    12641309 
     
    12681313        pj_stun_sock_get_info(stun_sock, &ssi); 
    12691314        pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr)); 
     1315 
     1316        stun_resolve_add_ref(sess); 
    12701317 
    12711318        sess->status = PJ_SUCCESS; 
     
    12751322        stun_resolve_complete(sess); 
    12761323 
     1324        stun_resolve_dec_ref(sess); 
     1325 
    12771326        return PJ_FALSE; 
    12781327 
     
    12901339    pj_status_t status = PJ_EUNKNOWN; 
    12911340 
    1292     stun_resolve_add_ref(sess); 
    1293  
    12941341    /* Loop while we have entry to try */ 
    12951342    for (; sess->idx < sess->count; ++sess->idx) { 
    1296         const int af = pj_AF_INET(); 
     1343        int af; 
    12971344        char target[64]; 
    12981345        pj_str_t hostpart; 
     
    13071354 
    13081355        /* Parse the server entry into host:port */ 
    1309         status = pj_sockaddr_parse2(af, 0, &sess->srv[sess->idx], 
    1310                                           &hostpart, &port, NULL); 
     1356        status = pj_sockaddr_parse2(pj_AF_UNSPEC(), 0, &sess->srv[sess->idx], 
     1357                                    &hostpart, &port, &af); 
    13111358        if (status != PJ_SUCCESS) { 
    13121359            PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %s", target)); 
     1360            continue; 
     1361        } else if (af != pj_AF_INET()) { 
     1362            /* Ignore IPv6 STUN server for now */ 
     1363            status = PJ_EAFNOTSUP; 
     1364            PJ_LOG(3,(THIS_FILE, "Ignored STUN server entry %s, currently " 
     1365                                 "only IPv4 STUN server is supported (does " 
     1366                                 "IPv6 still need a mapped address?)", 
     1367                      target)); 
    13131368            continue; 
    13141369        } 
     
    13261381        pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 
    13271382        stun_sock_cb.on_status = &test_stun_on_status; 
     1383        sess->async_wait = PJ_FALSE; 
    13281384        status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve", 
    1329                                            pj_AF_INET(), &stun_sock_cb, 
    1330                                            NULL, sess, &sess->stun_sock); 
     1385                                     pj_AF_INET(), &stun_sock_cb, 
     1386                                     NULL, sess, &sess->stun_sock); 
    13311387        if (status != PJ_SUCCESS) { 
    13321388            char errmsg[PJ_ERR_MSG_SIZE]; 
     
    13391395        } 
    13401396 
    1341         status = pj_stun_sock_start(sess->stun_sock, &hostpart, 
    1342                                           port, pjsua_var.resolver); 
     1397        status = pj_stun_sock_start(sess->stun_sock, &hostpart, port, 
     1398                                    pjsua_var.resolver); 
    13431399        if (status != PJ_SUCCESS) { 
    13441400            char errmsg[PJ_ERR_MSG_SIZE]; 
     
    13581414         * stun_sock_cb() 
    13591415         */ 
    1360         goto on_return; 
     1416        sess->async_wait = PJ_TRUE; 
     1417        return; 
    13611418    } 
    13621419 
    13631420    if (sess->idx >= sess->count) { 
    13641421        /* No more entries to try */ 
     1422        stun_resolve_add_ref(sess); 
    13651423        pj_assert(status != PJ_SUCCESS || sess->status != PJ_EPENDING); 
    13661424        if (sess->status == PJ_EPENDING) 
    13671425            sess->status = status; 
    13681426        stun_resolve_complete(sess); 
    1369     } 
    1370  
    1371 on_return: 
    1372     stun_resolve_dec_ref(sess); 
     1427        stun_resolve_dec_ref(sess); 
     1428    } 
     1429} 
     1430 
     1431 
     1432/* 
     1433 * Update STUN servers. 
     1434 */ 
     1435PJ_DEF(pj_status_t) pjsua_update_stun_servers(unsigned count, pj_str_t srv[], 
     1436                                              pj_bool_t wait) 
     1437{ 
     1438    unsigned i; 
     1439    pj_status_t status; 
     1440 
     1441    PJ_ASSERT_RETURN(count && srv, PJ_EINVAL); 
     1442     
     1443    PJSUA_LOCK(); 
     1444 
     1445    pjsua_var.ua_cfg.stun_srv_cnt = count; 
     1446    for (i = 0; i < count; i++) { 
     1447        if (pj_strcmp(&pjsua_var.ua_cfg.stun_srv[i], &srv[i])) 
     1448            pj_strdup(pjsua_var.pool, &pjsua_var.ua_cfg.stun_srv[i], &srv[i]); 
     1449    } 
     1450    pjsua_var.stun_status = PJ_EUNKNOWN; 
     1451 
     1452    PJSUA_UNLOCK(); 
     1453     
     1454    status = resolve_stun_server(wait, PJ_FALSE); 
     1455    if (wait == PJ_FALSE && status == PJ_EPENDING) 
     1456        status = PJ_SUCCESS; 
     1457 
     1458    return status; 
    13731459} 
    13741460 
     
    13861472    pjsua_stun_resolve *sess; 
    13871473    pj_status_t status; 
    1388     unsigned i; 
     1474    unsigned i, max_wait_ms; 
     1475    pj_timestamp start, now; 
    13891476 
    13901477    PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL); 
     
    14001487    sess->count = count; 
    14011488    sess->blocking = wait; 
     1489    sess->waiter = pj_thread_this(); 
    14021490    sess->status = PJ_EPENDING; 
    14031491    sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t)); 
     
    14141502    if (!wait) 
    14151503        return PJ_SUCCESS; 
     1504 
     1505    /* Should limit the wait time to avoid deadlock. For example, 
     1506     * if app holds dlg/tsx lock, pjsua worker thread will block on 
     1507     * any dlg/tsx state change. 
     1508     */ 
     1509    max_wait_ms = count * pjsua_var.stun_cfg.rto_msec * (1 << 7); 
     1510    pj_get_timestamp(&start); 
    14161511 
    14171512    while (sess->status == PJ_EPENDING) { 
     
    14281523            pj_thread_sleep(20); 
    14291524        } 
     1525 
     1526        pj_get_timestamp(&now); 
     1527        if (pj_elapsed_msec(&start, &now) > max_wait_ms) 
     1528            sess->status = PJ_ETIMEDOUT; 
    14301529    } 
    14311530 
     
    14771576    if ((result->status == PJ_SUCCESS) && (pjsua_var.ua_cfg.stun_srv_cnt>0)) { 
    14781577        pj_memcpy(&pjsua_var.stun_srv, &result->addr, sizeof(result->addr)); 
     1578        pjsua_var.stun_srv_idx = result->index; 
    14791579 
    14801580        /* Perform NAT type detection if not yet */ 
    14811581        if (pjsua_var.nat_type == PJ_STUN_NAT_TYPE_UNKNOWN && 
     1582            !pjsua_var.nat_in_progress && 
    14821583            pjsua_var.ua_cfg.nat_type_in_sdp) 
    14831584        { 
     
    14931594 * Resolve STUN server. 
    14941595 */ 
    1495 pj_status_t resolve_stun_server(pj_bool_t wait) 
    1496 { 
     1596pj_status_t resolve_stun_server(pj_bool_t wait, pj_bool_t retry_if_cur_error) 
     1597{ 
     1598    /* Retry resolving if currently the STUN status is error */ 
     1599    if (pjsua_var.stun_status != PJ_EPENDING && 
     1600        pjsua_var.stun_status != PJ_SUCCESS && 
     1601        retry_if_cur_error) 
     1602    { 
     1603        pjsua_var.stun_status = PJ_EUNKNOWN; 
     1604    } 
     1605 
    14971606    if (pjsua_var.stun_status == PJ_EUNKNOWN) { 
    14981607        pj_status_t status; 
     
    15221631         */ 
    15231632        if (wait) { 
    1524             while (pjsua_var.stun_status == PJ_EPENDING) { 
     1633            unsigned max_wait_ms; 
     1634            pj_timestamp start, now; 
     1635 
     1636            /* Should limit the wait time to avoid deadlock. For example, 
     1637             * if app holds dlg/tsx lock, pjsua worker thread will block on 
     1638             * any dlg/tsx state change. 
     1639             */ 
     1640            max_wait_ms = pjsua_var.ua_cfg.stun_srv_cnt * 
     1641                          pjsua_var.stun_cfg.rto_msec * (1 << 7); 
     1642            pj_get_timestamp(&start); 
     1643 
     1644            while (pjsua_var.stun_status == PJ_EPENDING) {               
    15251645                /* If there is no worker thread or 
    15261646                 * the function is called from the only worker thread, 
     
    15351655                    pj_thread_sleep(10); 
    15361656                } 
     1657 
     1658                pj_get_timestamp(&now); 
     1659                if (pj_elapsed_msec(&start, &now) > max_wait_ms) 
     1660                    return PJ_ETIMEDOUT; 
    15371661            } 
    15381662        } 
     
    15451669        PJ_LOG(2,(THIS_FILE,  
    15461670                  "Ignoring STUN resolution failure (by setting)")); 
    1547         pjsua_var.stun_status = PJ_SUCCESS; 
     1671        //pjsua_var.stun_status = PJ_SUCCESS; 
     1672        return PJ_SUCCESS; 
    15481673    } 
    15491674 
     
    19562081 
    19572082    /* Make sure STUN server resolution has completed */ 
    1958     status = resolve_stun_server(PJ_TRUE); 
     2083    status = resolve_stun_server(PJ_TRUE, PJ_TRUE); 
    19592084    if (status != PJ_SUCCESS) { 
    19602085        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     
    20152140 
    20162141    if (pjsua_var.stun_srv.addr.sa_family != 0) { 
    2017         pj_ansi_strcpy(stun_ip_addr,pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
     2142        pj_sockaddr_print(&pjsua_var.stun_srv, 
     2143                          stun_ip_addr, sizeof(stun_ip_addr), 0); 
    20182144        stun_srv = pj_str(stun_ip_addr); 
    20192145    } else { 
     
    20322158            pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port); 
    20332159 
    2034     } else if (stun_srv.slen) { 
     2160    } else if (stun_srv.slen && af == pj_AF_INET()) { 
    20352161        pjstun_setting stun_opt; 
    20362162 
    20372163        /* 
    20382164         * STUN is specified, resolve the address with STUN. 
     2165         * Currently, this is available for IPv4 address only. 
    20392166         */ 
    2040         if (af != pj_AF_INET()) { 
    2041             pjsua_perror(THIS_FILE, "Cannot use STUN", PJ_EAFNOTSUP); 
    2042             pj_sock_close(sock); 
    2043             return PJ_EAFNOTSUP; 
    2044         } 
    2045  
    20462167        pj_bzero(&stun_opt, sizeof(stun_opt)); 
    20472168        stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2; 
     
    20522173                                         1, &sock, &p_pub_addr->ipv4); 
    20532174        if (status != PJ_SUCCESS) { 
     2175            /* Failed getting mapped address via STUN */ 
    20542176            pjsua_perror(THIS_FILE, "Error contacting STUN server", status); 
    2055             pj_sock_close(sock); 
    2056             return status; 
     2177             
     2178            /* Return error if configured to not ignore STUN failure */ 
     2179            if (!pjsua_var.ua_cfg.stun_ignore_failure) { 
     2180                pj_sock_close(sock); 
     2181                return status; 
     2182            } 
     2183 
     2184            /* Otherwise, just use host IP */ 
     2185            pj_sockaddr_init(af, p_pub_addr, NULL, (pj_uint16_t)port); 
     2186            status = pj_gethostip(af, p_pub_addr); 
     2187            if (status != PJ_SUCCESS) { 
     2188                pjsua_perror(THIS_FILE, "Unable to get local host IP", status); 
     2189                pj_sock_close(sock); 
     2190                return status; 
     2191            } 
    20572192        } 
    20582193 
    20592194    } else { 
     2195 
    20602196        pj_bzero(p_pub_addr, sizeof(pj_sockaddr)); 
    20612197 
     
    20732209        p_pub_addr->addr.sa_family = (pj_uint16_t)af; 
    20742210        pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port); 
     2211 
     2212        if (stun_srv.slen && af != pj_AF_INET()) { 
     2213            /* STUN is specified, but it is not IPv4, just print warning */ 
     2214            PJ_PERROR(2, (THIS_FILE, PJ_EAFNOTSUP, 
     2215                          "Cannot use STUN for SIP UDP socket %s:%d", 
     2216                          addr_string(p_pub_addr), 
     2217                          (int)pj_sockaddr_get_port(p_pub_addr))); 
     2218        } 
     2219 
    20752220    } 
    20762221 
     
    24062551    PJSUA_LOCK(); 
    24072552 
    2408     if (t->type == PJSIP_TRANSPORT_UDP) { 
     2553    if ((t->type & ~PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_UDP) { 
    24092554 
    24102555        pjsip_transport *tp = t->data.tp; 
     
    24272572        status = PJ_SUCCESS; 
    24282573 
    2429     } else if (t->type == PJSIP_TRANSPORT_TCP || 
    2430                t->type == PJSIP_TRANSPORT_TLS) 
     2574    } else if ((t->type & ~PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_TCP || 
     2575               (t->type & ~PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_TLS) 
    24312576    { 
    24322577 
     
    24402585        info->id = id; 
    24412586        info->type = t->type; 
    2442         info->type_name = (t->type==PJSIP_TRANSPORT_TCP)? pj_str("TCP"): 
    2443                                                           pj_str("TLS"); 
    2444         info->info = (t->type==PJSIP_TRANSPORT_TCP)? pj_str("TCP transport"): 
    2445                                                      pj_str("TLS transport"); 
     2587        info->type_name = pj_str(factory->type_name); 
     2588        info->info = pj_str(factory->info); 
    24462589        info->flag = factory->flag; 
    24472590        info->addr_len = sizeof(factory->local_addr); 
     
    24932636{ 
    24942637    pj_status_t status; 
     2638    pjsip_transport_type_e tp_type; 
    24952639 
    24962640    /* Make sure id is in range. */ 
     
    25002644    /* Make sure that transport exists */ 
    25012645    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 
     2646 
     2647    tp_type = pjsua_var.tpdata[id].type & ~PJSIP_TRANSPORT_IPV6; 
    25022648 
    25032649    /* Note: destroy() may not work if there are objects still referencing 
     
    25052651     */ 
    25062652    if (force) { 
    2507         switch (pjsua_var.tpdata[id].type) { 
     2653        switch (tp_type) { 
    25082654        case PJSIP_TRANSPORT_UDP: 
    25092655            status = pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp); 
     
    25382684         * descriptor. 
    25392685         */ 
    2540         switch (pjsua_var.tpdata[id].type) { 
     2686        switch (tp_type) { 
    25412687        case PJSIP_TRANSPORT_UDP: 
    25422688            return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp); 
     
    27412887 
    27422888    /* Make sure STUN server resolution has completed */ 
    2743     status = resolve_stun_server(PJ_TRUE); 
     2889    status = resolve_stun_server(PJ_TRUE, PJ_TRUE); 
    27442890    if (status != PJ_SUCCESS) { 
    27452891        pjsua_var.nat_status = status; 
Note: See TracChangeset for help on using the changeset viewer.