- Timestamp:
- Dec 28, 2016 3:40:07 AM (8 years ago)
- Location:
- pjproject/branches/projects/uwp
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/uwp
- Property svn:mergeinfo changed
/pjproject/trunk (added) merged: 5209,5212-5234,5237-5253,5255,5257-5292,5294-5297,5299-5332,5334-5394,5396-5438,5440-5469,5471-5496,5498-5510
- Property svn:mergeinfo changed
-
pjproject/branches/projects/uwp/pjsip/src/pjsua-lib/pjsua_core.c
r5170 r5513 278 278 #if PJMEDIA_HAS_VIDEO 279 279 pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg); 280 pjmedia_vid_stream_sk_config_default(&cfg->vid_stream_sk_cfg); 280 281 #endif 281 282 pjsua_transport_config_default(&cfg->rtp_cfg); … … 303 304 cfg->register_on_acc_add = PJ_TRUE; 304 305 cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES; 306 307 cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE; 305 308 } 306 309 … … 1050 1053 1051 1054 /* Start resolving STUN server */ 1052 status = resolve_stun_server(PJ_FALSE );1055 status = resolve_stun_server(PJ_FALSE, PJ_FALSE); 1053 1056 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 1054 1057 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 1106 1109 1107 1110 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, 1109 1114 NULL, 0, 0, &pjsua_var.thread[ii]); 1110 1115 if (status != PJ_SUCCESS) … … 1155 1160 } 1156 1161 1162 1163 static 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 1157 1177 static void destroy_stun_resolve(pjsua_stun_resolve *sess) 1158 1178 { 1179 pj_time_val timeout = {0, 0}; 1180 1159 1181 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) 1161 1195 return; 1162 1163 PJSUA_LOCK();1164 1196 1165 1197 if (sess->stun_sock) { … … 1174 1206 } 1175 1207 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); 1182 1216 } 1183 1217 … … 1204 1238 result.status = sess->status; 1205 1239 result.name = sess->srv[sess->idx]; 1240 result.index = sess->idx; 1206 1241 pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr)); 1207 1242 sess->has_result = PJ_TRUE; … … 1221 1256 } 1222 1257 1223 stun_resolve_add_ref(sess);1224 1258 sess->cb(&result); 1225 stun_resolve_dec_ref(sess);1226 1259 1227 1260 on_return: … … 1252 1285 sess->srv[sess->idx].ptr, errmsg)); 1253 1286 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 1254 1295 pj_stun_sock_destroy(stun_sock); 1255 1296 sess->stun_sock = NULL; 1297 1298 stun_resolve_add_ref(sess); 1256 1299 1257 1300 ++sess->idx; … … 1261 1304 resolve_stun_entry(sess); 1262 1305 1306 stun_resolve_dec_ref(sess); 1307 1263 1308 return PJ_FALSE; 1264 1309 … … 1268 1313 pj_stun_sock_get_info(stun_sock, &ssi); 1269 1314 pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr)); 1315 1316 stun_resolve_add_ref(sess); 1270 1317 1271 1318 sess->status = PJ_SUCCESS; … … 1275 1322 stun_resolve_complete(sess); 1276 1323 1324 stun_resolve_dec_ref(sess); 1325 1277 1326 return PJ_FALSE; 1278 1327 … … 1290 1339 pj_status_t status = PJ_EUNKNOWN; 1291 1340 1292 stun_resolve_add_ref(sess);1293 1294 1341 /* Loop while we have entry to try */ 1295 1342 for (; sess->idx < sess->count; ++sess->idx) { 1296 const int af = pj_AF_INET();1343 int af; 1297 1344 char target[64]; 1298 1345 pj_str_t hostpart; … … 1307 1354 1308 1355 /* 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); 1311 1358 if (status != PJ_SUCCESS) { 1312 1359 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)); 1313 1368 continue; 1314 1369 } … … 1326 1381 pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 1327 1382 stun_sock_cb.on_status = &test_stun_on_status; 1383 sess->async_wait = PJ_FALSE; 1328 1384 status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve", 1329 1330 1385 pj_AF_INET(), &stun_sock_cb, 1386 NULL, sess, &sess->stun_sock); 1331 1387 if (status != PJ_SUCCESS) { 1332 1388 char errmsg[PJ_ERR_MSG_SIZE]; … … 1339 1395 } 1340 1396 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); 1343 1399 if (status != PJ_SUCCESS) { 1344 1400 char errmsg[PJ_ERR_MSG_SIZE]; … … 1358 1414 * stun_sock_cb() 1359 1415 */ 1360 goto on_return; 1416 sess->async_wait = PJ_TRUE; 1417 return; 1361 1418 } 1362 1419 1363 1420 if (sess->idx >= sess->count) { 1364 1421 /* No more entries to try */ 1422 stun_resolve_add_ref(sess); 1365 1423 pj_assert(status != PJ_SUCCESS || sess->status != PJ_EPENDING); 1366 1424 if (sess->status == PJ_EPENDING) 1367 1425 sess->status = status; 1368 1426 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 */ 1435 PJ_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; 1373 1459 } 1374 1460 … … 1386 1472 pjsua_stun_resolve *sess; 1387 1473 pj_status_t status; 1388 unsigned i; 1474 unsigned i, max_wait_ms; 1475 pj_timestamp start, now; 1389 1476 1390 1477 PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL); … … 1400 1487 sess->count = count; 1401 1488 sess->blocking = wait; 1489 sess->waiter = pj_thread_this(); 1402 1490 sess->status = PJ_EPENDING; 1403 1491 sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t)); … … 1414 1502 if (!wait) 1415 1503 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); 1416 1511 1417 1512 while (sess->status == PJ_EPENDING) { … … 1428 1523 pj_thread_sleep(20); 1429 1524 } 1525 1526 pj_get_timestamp(&now); 1527 if (pj_elapsed_msec(&start, &now) > max_wait_ms) 1528 sess->status = PJ_ETIMEDOUT; 1430 1529 } 1431 1530 … … 1477 1576 if ((result->status == PJ_SUCCESS) && (pjsua_var.ua_cfg.stun_srv_cnt>0)) { 1478 1577 pj_memcpy(&pjsua_var.stun_srv, &result->addr, sizeof(result->addr)); 1578 pjsua_var.stun_srv_idx = result->index; 1479 1579 1480 1580 /* Perform NAT type detection if not yet */ 1481 1581 if (pjsua_var.nat_type == PJ_STUN_NAT_TYPE_UNKNOWN && 1582 !pjsua_var.nat_in_progress && 1482 1583 pjsua_var.ua_cfg.nat_type_in_sdp) 1483 1584 { … … 1493 1594 * Resolve STUN server. 1494 1595 */ 1495 pj_status_t resolve_stun_server(pj_bool_t wait) 1496 { 1596 pj_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 1497 1606 if (pjsua_var.stun_status == PJ_EUNKNOWN) { 1498 1607 pj_status_t status; … … 1522 1631 */ 1523 1632 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) { 1525 1645 /* If there is no worker thread or 1526 1646 * the function is called from the only worker thread, … … 1535 1655 pj_thread_sleep(10); 1536 1656 } 1657 1658 pj_get_timestamp(&now); 1659 if (pj_elapsed_msec(&start, &now) > max_wait_ms) 1660 return PJ_ETIMEDOUT; 1537 1661 } 1538 1662 } … … 1545 1669 PJ_LOG(2,(THIS_FILE, 1546 1670 "Ignoring STUN resolution failure (by setting)")); 1547 pjsua_var.stun_status = PJ_SUCCESS; 1671 //pjsua_var.stun_status = PJ_SUCCESS; 1672 return PJ_SUCCESS; 1548 1673 } 1549 1674 … … 1956 2081 1957 2082 /* Make sure STUN server resolution has completed */ 1958 status = resolve_stun_server(PJ_TRUE );2083 status = resolve_stun_server(PJ_TRUE, PJ_TRUE); 1959 2084 if (status != PJ_SUCCESS) { 1960 2085 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 2015 2140 2016 2141 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); 2018 2144 stun_srv = pj_str(stun_ip_addr); 2019 2145 } else { … … 2032 2158 pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port); 2033 2159 2034 } else if (stun_srv.slen ) {2160 } else if (stun_srv.slen && af == pj_AF_INET()) { 2035 2161 pjstun_setting stun_opt; 2036 2162 2037 2163 /* 2038 2164 * STUN is specified, resolve the address with STUN. 2165 * Currently, this is available for IPv4 address only. 2039 2166 */ 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 2046 2167 pj_bzero(&stun_opt, sizeof(stun_opt)); 2047 2168 stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2; … … 2052 2173 1, &sock, &p_pub_addr->ipv4); 2053 2174 if (status != PJ_SUCCESS) { 2175 /* Failed getting mapped address via STUN */ 2054 2176 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 } 2057 2192 } 2058 2193 2059 2194 } else { 2195 2060 2196 pj_bzero(p_pub_addr, sizeof(pj_sockaddr)); 2061 2197 … … 2073 2209 p_pub_addr->addr.sa_family = (pj_uint16_t)af; 2074 2210 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 2075 2220 } 2076 2221 … … 2406 2551 PJSUA_LOCK(); 2407 2552 2408 if ( t->type== PJSIP_TRANSPORT_UDP) {2553 if ((t->type & ~PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_UDP) { 2409 2554 2410 2555 pjsip_transport *tp = t->data.tp; … … 2427 2572 status = PJ_SUCCESS; 2428 2573 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) 2431 2576 { 2432 2577 … … 2440 2585 info->id = id; 2441 2586 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); 2446 2589 info->flag = factory->flag; 2447 2590 info->addr_len = sizeof(factory->local_addr); … … 2493 2636 { 2494 2637 pj_status_t status; 2638 pjsip_transport_type_e tp_type; 2495 2639 2496 2640 /* Make sure id is in range. */ … … 2500 2644 /* Make sure that transport exists */ 2501 2645 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 2646 2647 tp_type = pjsua_var.tpdata[id].type & ~PJSIP_TRANSPORT_IPV6; 2502 2648 2503 2649 /* Note: destroy() may not work if there are objects still referencing … … 2505 2651 */ 2506 2652 if (force) { 2507 switch ( pjsua_var.tpdata[id].type) {2653 switch (tp_type) { 2508 2654 case PJSIP_TRANSPORT_UDP: 2509 2655 status = pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp); … … 2538 2684 * descriptor. 2539 2685 */ 2540 switch ( pjsua_var.tpdata[id].type) {2686 switch (tp_type) { 2541 2687 case PJSIP_TRANSPORT_UDP: 2542 2688 return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp); … … 2741 2887 2742 2888 /* Make sure STUN server resolution has completed */ 2743 status = resolve_stun_server(PJ_TRUE );2889 status = resolve_stun_server(PJ_TRUE, PJ_TRUE); 2744 2890 if (status != PJ_SUCCESS) { 2745 2891 pjsua_var.nat_status = status;
Note: See TracChangeset
for help on using the changeset viewer.