Changeset 5326
- Timestamp:
- May 31, 2016 4:28:00 AM (8 years ago)
- Location:
- pjproject/trunk/pjsip
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
r5307 r5326 3326 3326 * Control the use of STUN for the media transports. 3327 3327 * 3328 * Default: PJSUA_STUN_ USE_DEFAULT3328 * Default: PJSUA_STUN_RETRY_ON_FAILURE 3329 3329 */ 3330 3330 pjsua_stun_use media_stun_use; -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
r5323 r5326 368 368 pj_stun_resolve_cb cb; /**< App callback */ 369 369 pj_bool_t blocking; /**< Blocking? */ 370 pj_thread_t *waiter; /**< Waiting thread */ 371 pj_timer_entry timer; /**< Destroy timer */ 370 372 pj_status_t status; /**< Session status */ 371 373 pj_sockaddr addr; /**< Result */ … … 609 611 */ 610 612 /* Resolve the STUN server */ 611 pj_status_t resolve_stun_server(pj_bool_t wait );613 pj_status_t resolve_stun_server(pj_bool_t wait, pj_bool_t retry_if_cur_error); 612 614 613 615 /** -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
r5322 r5326 303 303 cfg->register_on_acc_add = PJ_TRUE; 304 304 cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES; 305 306 cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE; 305 307 } 306 308 … … 1050 1052 1051 1053 /* Start resolving STUN server */ 1052 status = resolve_stun_server(PJ_FALSE );1054 status = resolve_stun_server(PJ_FALSE, PJ_FALSE); 1053 1055 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 1054 1056 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 1157 1159 } 1158 1160 1161 1162 static void destroy_stun_resolve_cb(pj_timer_heap_t *t, pj_timer_entry *e) 1163 { 1164 pjsua_stun_resolve *sess = (pjsua_stun_resolve*)e->user_data; 1165 PJ_UNUSED_ARG(t); 1166 1167 PJSUA_LOCK(); 1168 pj_list_erase(sess); 1169 PJSUA_UNLOCK(); 1170 1171 pj_assert(sess->stun_sock==NULL); 1172 pj_pool_release(sess->pool); 1173 } 1174 1175 1159 1176 static void destroy_stun_resolve(pjsua_stun_resolve *sess) 1160 1177 { 1178 pj_time_val timeout = {0, 0}; 1179 1161 1180 sess->destroy_flag = PJ_TRUE; 1162 if (sess->ref_cnt > 0) 1181 1182 /* If the STUN resolution session is blocking, only the waiting thread 1183 * is allowed to destroy the session, otherwise it may cause deadlock. 1184 */ 1185 if (sess->blocking) { 1186 if (sess->waiter != pj_thread_this()) 1187 return; 1188 1189 /* Before destroying, make sure ref count is zero. */ 1190 while (sess->ref_cnt > 0) 1191 pj_thread_sleep(10); 1192 1193 } else if (sess->ref_cnt > 0) 1163 1194 return; 1164 1165 PJSUA_LOCK();1166 1195 1167 1196 if (sess->stun_sock) { … … 1176 1205 } 1177 1206 1178 pj_list_erase(sess); 1179 1180 PJSUA_UNLOCK(); 1181 1182 pj_assert(sess->stun_sock==NULL); 1183 pj_pool_release(sess->pool); 1207 /* Schedule session clean up, it needs PJSUA lock and locking it here 1208 * may cause deadlock as this function may be called by STUN socket 1209 * while holding STUN socket lock, while application may wait for STUN 1210 * resolution while holding PJSUA lock. 1211 */ 1212 pj_timer_entry_init(&sess->timer, 0, (void*)sess, 1213 &destroy_stun_resolve_cb); 1214 pjsua_schedule_timer(&sess->timer, &timeout); 1184 1215 } 1185 1216 … … 1224 1255 } 1225 1256 1226 stun_resolve_add_ref(sess);1227 1257 sess->cb(&result); 1228 stun_resolve_dec_ref(sess);1229 1258 1230 1259 on_return: … … 1258 1287 sess->stun_sock = NULL; 1259 1288 1289 stun_resolve_add_ref(sess); 1290 1260 1291 ++sess->idx; 1261 1292 if (sess->idx >= sess->count) … … 1264 1295 resolve_stun_entry(sess); 1265 1296 1297 stun_resolve_dec_ref(sess); 1298 1266 1299 return PJ_FALSE; 1267 1300 … … 1271 1304 pj_stun_sock_get_info(stun_sock, &ssi); 1272 1305 pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr)); 1306 1307 stun_resolve_add_ref(sess); 1273 1308 1274 1309 sess->status = PJ_SUCCESS; … … 1278 1313 stun_resolve_complete(sess); 1279 1314 1315 stun_resolve_dec_ref(sess); 1316 1280 1317 return PJ_FALSE; 1281 1318 … … 1292 1329 { 1293 1330 pj_status_t status = PJ_EUNKNOWN; 1294 1295 stun_resolve_add_ref(sess);1296 1331 1297 1332 /* Loop while we have entry to try */ … … 1361 1396 * stun_sock_cb() 1362 1397 */ 1363 goto on_return;1398 return; 1364 1399 } 1365 1400 1366 1401 if (sess->idx >= sess->count) { 1367 1402 /* No more entries to try */ 1403 stun_resolve_add_ref(sess); 1368 1404 pj_assert(status != PJ_SUCCESS || sess->status != PJ_EPENDING); 1369 1405 if (sess->status == PJ_EPENDING) 1370 1406 sess->status = status; 1371 1407 stun_resolve_complete(sess); 1372 } 1373 1374 on_return: 1375 stun_resolve_dec_ref(sess); 1408 stun_resolve_dec_ref(sess); 1409 } 1376 1410 } 1377 1411 … … 1397 1431 pjsua_var.stun_status = PJ_EUNKNOWN; 1398 1432 1399 status = resolve_stun_server(wait); 1433 PJSUA_UNLOCK(); 1434 1435 status = resolve_stun_server(wait, PJ_FALSE); 1400 1436 if (wait == PJ_FALSE && status == PJ_EPENDING) 1401 1437 status = PJ_SUCCESS; 1402 1438 1403 PJSUA_UNLOCK();1404 1405 1439 return status; 1406 1440 } … … 1419 1453 pjsua_stun_resolve *sess; 1420 1454 pj_status_t status; 1421 unsigned i; 1455 unsigned i, max_wait_ms; 1456 pj_timestamp start, now; 1422 1457 1423 1458 PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL); … … 1433 1468 sess->count = count; 1434 1469 sess->blocking = wait; 1470 sess->waiter = pj_thread_this(); 1435 1471 sess->status = PJ_EPENDING; 1436 1472 sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t)); … … 1447 1483 if (!wait) 1448 1484 return PJ_SUCCESS; 1485 1486 /* Should limit the wait time to avoid deadlock. For example, 1487 * if app holds dlg/tsx lock, pjsua worker thread will block on 1488 * any dlg/tsx state change. 1489 */ 1490 max_wait_ms = count * pjsua_var.stun_cfg.rto_msec * (1 << 7); 1491 pj_get_timestamp(&start); 1449 1492 1450 1493 while (sess->status == PJ_EPENDING) { … … 1461 1504 pj_thread_sleep(20); 1462 1505 } 1506 1507 pj_get_timestamp(&now); 1508 if (pj_elapsed_msec(&start, &now) > max_wait_ms) 1509 sess->status = PJ_ETIMEDOUT; 1463 1510 } 1464 1511 … … 1528 1575 * Resolve STUN server. 1529 1576 */ 1530 pj_status_t resolve_stun_server(pj_bool_t wait) 1531 { 1577 pj_status_t resolve_stun_server(pj_bool_t wait, pj_bool_t retry_if_cur_error) 1578 { 1579 /* Retry resolving if currently the STUN status is error */ 1580 if (pjsua_var.stun_status != PJ_EPENDING && 1581 pjsua_var.stun_status != PJ_SUCCESS && 1582 retry_if_cur_error) 1583 { 1584 pjsua_var.stun_status = PJ_EUNKNOWN; 1585 } 1586 1532 1587 if (pjsua_var.stun_status == PJ_EUNKNOWN) { 1533 1588 pj_status_t status; … … 1557 1612 */ 1558 1613 if (wait) { 1559 pj_bool_t has_pjsua_lock = PJSUA_LOCK_IS_LOCKED(); 1560 1561 if (has_pjsua_lock) 1562 PJSUA_UNLOCK(); 1614 unsigned max_wait_ms; 1615 pj_timestamp start, now; 1616 1617 /* Should limit the wait time to avoid deadlock. For example, 1618 * if app holds dlg/tsx lock, pjsua worker thread will block on 1619 * any dlg/tsx state change. 1620 */ 1621 max_wait_ms = pjsua_var.ua_cfg.stun_srv_cnt * 1622 pjsua_var.stun_cfg.rto_msec * (1 << 7); 1623 pj_get_timestamp(&start); 1563 1624 1564 1625 while (pjsua_var.stun_status == PJ_EPENDING) { … … 1575 1636 pj_thread_sleep(10); 1576 1637 } 1638 1639 pj_get_timestamp(&now); 1640 if (pj_elapsed_msec(&start, &now) > max_wait_ms) 1641 return PJ_ETIMEDOUT; 1577 1642 } 1578 if (has_pjsua_lock)1579 PJSUA_LOCK();1580 1643 } 1581 1644 } … … 1998 2061 1999 2062 /* Make sure STUN server resolution has completed */ 2000 status = resolve_stun_server(PJ_TRUE );2063 status = resolve_stun_server(PJ_TRUE, PJ_TRUE); 2001 2064 if (status != PJ_SUCCESS) { 2002 2065 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 2785 2848 2786 2849 /* Make sure STUN server resolution has completed */ 2787 status = resolve_stun_server(PJ_TRUE );2850 status = resolve_stun_server(PJ_TRUE, PJ_TRUE); 2788 2851 if (status != PJ_SUCCESS) { 2789 2852 pjsua_var.nat_status = status; -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r5311 r5326 255 255 /* Make sure STUN server resolution has completed */ 256 256 if (!use_ipv6 && pjsua_media_acc_is_using_stun(call_med->call->acc_id)) { 257 status = resolve_stun_server(PJ_TRUE); 257 pj_bool_t retry_stun = (acc->cfg.media_stun_use & 258 PJSUA_STUN_RETRY_ON_FAILURE) == 259 PJSUA_STUN_RETRY_ON_FAILURE; 260 status = resolve_stun_server(PJ_TRUE, retry_stun); 258 261 if (status != PJ_SUCCESS) { 259 262 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 391 394 392 395 if (status != PJ_SUCCESS && pjsua_var.ua_cfg.stun_srv_cnt > 1 && 393 ((acc->cfg.media_stun_use & PJSUA_STUN_RETRY_ON_FAILURE)!=0)) 396 ((acc->cfg.media_stun_use & PJSUA_STUN_RETRY_ON_FAILURE)== 397 PJSUA_STUN_RETRY_ON_FAILURE)) 394 398 { 395 399 pj_str_t srv = … … 419 423 status=pjsua_update_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt, 420 424 pjsua_var.ua_cfg.stun_srv, 421 PJ_FALSE); 422 423 if (status == PJ_SUCCESS) 424 status = resolve_stun_server(PJ_TRUE); 425 425 PJ_TRUE); 426 426 if (status == PJ_SUCCESS) { 427 427 if (pjsua_var.stun_srv.addr.sa_family != 0) { … … 829 829 /* Make sure STUN server resolution has completed */ 830 830 if (pjsua_media_acc_is_using_stun(call_med->call->acc_id)) { 831 status = resolve_stun_server(PJ_TRUE); 831 pj_bool_t retry_stun = (acc_cfg->media_stun_use & 832 PJSUA_STUN_RETRY_ON_FAILURE) == 833 PJSUA_STUN_RETRY_ON_FAILURE; 834 status = resolve_stun_server(PJ_TRUE, retry_stun); 832 835 if (status != PJ_SUCCESS) { 833 836 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
Note: See TracChangeset
for help on using the changeset viewer.