diff --git a/contrib/src/pjproject/0001-rfc6544.patch b/contrib/src/pjproject/0001-rfc6544.patch index f4a30bd6d8ceaa581ecb3038961362b4145d2fe6..ba10ff36901bae342334d213388b0ad94cfdfb29 100644 --- a/contrib/src/pjproject/0001-rfc6544.patch +++ b/contrib/src/pjproject/0001-rfc6544.patch @@ -20,29 +20,29 @@ Rebased for pjsip 2.10 by Peymane Marandi on behalf of Savoir-faire Linux. --- - pjnath/include/pjnath/config.h | 9 + - pjnath/include/pjnath/ice_session.h | 216 ++++- - pjnath/include/pjnath/ice_strans.h | 21 + - pjnath/include/pjnath/stun_session.h | 75 +- - pjnath/include/pjnath/stun_sock.h | 67 +- - pjnath/include/pjnath/turn_sock.h | 11 + + pjnath/include/pjnath/config.h | 9 ++ + pjnath/include/pjnath/ice_session.h | 216 ++++++++++++++++++++++++++++++++++++++------- + pjnath/include/pjnath/ice_strans.h | 21 +++++ + pjnath/include/pjnath/stun_session.h | 75 +++++++++++++++- + pjnath/include/pjnath/stun_sock.h | 67 +++++++++++++- + pjnath/include/pjnath/turn_sock.h | 11 +++ pjnath/src/pjnath-test/concur_test.c | 5 +- - pjnath/src/pjnath-test/sess_auth.c | 14 +- + pjnath/src/pjnath-test/sess_auth.c | 14 ++- pjnath/src/pjnath-test/stun_sock_test.c | 7 +- - pjnath/src/pjnath/ice_session.c | 609 +++++++++++-- - pjnath/src/pjnath/ice_strans.c | 743 +++++++++++++--- + pjnath/src/pjnath/ice_session.c | 613 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- + pjnath/src/pjnath/ice_strans.c | 743 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- pjnath/src/pjnath/nat_detect.c | 7 +- - pjnath/src/pjnath/stun_session.c | 19 +- - pjnath/src/pjnath/stun_sock.c | 1081 +++++++++++++++++++---- + pjnath/src/pjnath/stun_session.c | 19 +++- + pjnath/src/pjnath/stun_sock.c | 1081 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------- pjnath/src/pjnath/stun_transaction.c | 3 + pjnath/src/pjnath/turn_session.c | 3 +- - pjnath/src/pjnath/turn_sock.c | 24 +- + pjnath/src/pjnath/turn_sock.c | 24 +++-- pjnath/src/pjturn-client/client_main.c | 2 +- pjnath/src/pjturn-srv/allocation.c | 3 +- pjnath/src/pjturn-srv/server.c | 2 +- - pjsip-apps/src/samples/icedemo.c | 116 ++- + pjsip-apps/src/samples/icedemo.c | 116 ++++++++++++++++++++++-- pjsip/src/pjsua-lib/pjsua_core.c | 2 +- - 22 files changed, 2577 insertions(+), 462 deletions(-) + 22 files changed, 2580 insertions(+), 463 deletions(-) diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h index 8a656c225..3e7c6ae3a 100644 @@ -762,7 +762,7 @@ index 18a1bbd13..577659c87 100644 if (status != PJ_SUCCESS && status != PJ_EPENDING) { app_perror(" error: server sending data", status); diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index 3fecc3def..a3869d9ca 100644 +index 3fecc3def..1fd3cfd2a 100644 --- a/pjnath/src/pjnath/ice_session.c +++ b/pjnath/src/pjnath/ice_session.c @@ -18,6 +18,7 @@ @@ -917,7 +917,7 @@ index 3fecc3def..a3869d9ca 100644 case TIMER_NONE: /* Nothing to do, just to get rid of gcc warning */ break; -@@ -1481,12 +1516,22 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) +@@ -1481,15 +1516,27 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) * See if all checks in the checklist have completed. If we do, * then mark ICE processing as failed. */ @@ -944,9 +944,15 @@ index 3fecc3def..a3869d9ca 100644 + if (!ice->is_trickling &&c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) { + break; } - no_pending_check = (i == ice->clist.count); +- no_pending_check = (i == ice->clist.count); } -@@ -1506,8 +1551,8 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) ++ if (!ice->is_trickling) { ++ no_pending_check = (i == ice->clist.count); ++ } + + if (no_pending_check) { + /* All checks have completed, but we don't have nominated pair. +@@ -1506,8 +1553,8 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) if (i < ice->comp_cnt) { /* This component ID doesn't have valid pair. @@ -957,7 +963,7 @@ index 3fecc3def..a3869d9ca 100644 on_ice_complete(ice, PJNATH_EICEFAILED); return PJ_TRUE; } else { -@@ -1541,11 +1586,48 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) +@@ -1541,11 +1588,48 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) /* Unreached */ } else if (ice->is_nominating) { @@ -1011,7 +1017,7 @@ index 3fecc3def..a3869d9ca 100644 return PJ_TRUE; } else { -@@ -1737,6 +1819,44 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, +@@ -1737,6 +1821,44 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, return check_ice_complete(ice); } @@ -1056,7 +1062,7 @@ index 3fecc3def..a3869d9ca 100644 /* Get foundation index of a check pair. This function can also be used for * adding a new foundation (combination of local & remote cands foundations) -@@ -1905,6 +2025,29 @@ static pj_status_t add_rcand_and_update_checklist( +@@ -1905,6 +2027,29 @@ static pj_status_t add_rcand_and_update_checklist( continue; } @@ -1086,7 +1092,7 @@ index 3fecc3def..a3869d9ca 100644 #if 0 /* Trickle ICE: * Make sure that pair has not been added to checklist -@@ -1925,7 +2068,6 @@ static pj_status_t add_rcand_and_update_checklist( +@@ -1925,7 +2070,6 @@ static pj_status_t add_rcand_and_update_checklist( } #endif @@ -1094,7 +1100,7 @@ index 3fecc3def..a3869d9ca 100644 /* Add the pair */ chk = &clist->checks[clist->count]; chk->lcand = lcand; -@@ -2121,6 +2263,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( +@@ -2121,6 +2265,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( td = PJ_POOL_ZALLOC_T(ice->pool, timer_data); td->ice = ice; td->clist = clist; @@ -1102,7 +1108,7 @@ index 3fecc3def..a3869d9ca 100644 clist->timer.user_data = (void*)td; clist->timer.cb = &periodic_timer; -@@ -2209,6 +2352,36 @@ PJ_DEF(pj_status_t) pj_ice_sess_update_check_list( +@@ -2209,6 +2354,36 @@ PJ_DEF(pj_status_t) pj_ice_sess_update_check_list( return status; } @@ -1139,7 +1145,7 @@ index 3fecc3def..a3869d9ca 100644 /* Perform check on the specified candidate pair. */ static pj_status_t perform_check(pj_ice_sess *ice, pj_ice_sess_checklist *clist, -@@ -2219,19 +2392,17 @@ static pj_status_t perform_check(pj_ice_sess *ice, +@@ -2219,19 +2394,17 @@ static pj_status_t perform_check(pj_ice_sess *ice, pj_ice_msg_data *msg_data; pj_ice_sess_check *check; const pj_ice_sess_cand *lcand; @@ -1160,7 +1166,7 @@ index 3fecc3def..a3869d9ca 100644 /* Create request */ status = pj_stun_session_create_req(comp->stun_sess, -@@ -2282,32 +2453,71 @@ static pj_status_t perform_check(pj_ice_sess *ice, +@@ -2282,32 +2455,71 @@ static pj_status_t perform_check(pj_ice_sess *ice, &ice->tie_breaker); } else { @@ -1249,7 +1255,7 @@ index 3fecc3def..a3869d9ca 100644 } -@@ -2344,55 +2554,108 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, +@@ -2344,55 +2556,108 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, pj_log_push_indent(); /* Send STUN Binding request for check with highest priority on @@ -1379,7 +1385,7 @@ index 3fecc3def..a3869d9ca 100644 } pj_grp_lock_release(ice->grp_lock); -@@ -2636,6 +2899,204 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, +@@ -2636,6 +2901,204 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, return status; } @@ -1584,7 +1590,7 @@ index 3fecc3def..a3869d9ca 100644 /* This callback is called when outgoing STUN request completed */ static void on_stun_request_complete(pj_stun_session *stun_sess, -@@ -2941,7 +3402,9 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, +@@ -2941,7 +3404,9 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, &check->lcand->base_addr, &check->lcand->base_addr, pj_sockaddr_get_len(&xaddr->sockaddr), @@ -1595,7 +1601,7 @@ index 3fecc3def..a3869d9ca 100644 if (status != PJ_SUCCESS) { check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -@@ -3003,11 +3466,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, +@@ -3003,11 +3468,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, /* Perform 7.1.2.2.2. Updating Pair States. * This may terminate ICE processing. */ @@ -1608,7 +1614,7 @@ index 3fecc3def..a3869d9ca 100644 pj_grp_lock_release(ice->grp_lock); } -@@ -3202,9 +3661,13 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -3202,9 +3663,13 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, msg_data->has_req_data = PJ_FALSE; /* Send the response */ @@ -1624,7 +1630,7 @@ index 3fecc3def..a3869d9ca 100644 /* * Handling early check. -@@ -3323,12 +3786,12 @@ static void handle_incoming_check(pj_ice_sess *ice, +@@ -3323,12 +3788,12 @@ static void handle_incoming_check(pj_ice_sess *ice, /* Just get candidate with the highest priority and same transport ID * for the specified component ID in the checklist. */ diff --git a/test/unitTest/ice/ice.cpp b/test/unitTest/ice/ice.cpp index 9c768ccdd8d287e0902ae658edc35d2a8b893b77..aba7691fae0bbeb52476e1ebe9e2c575b6ed2353 100644 --- a/test/unitTest/ice/ice.cpp +++ b/test/unitTest/ice/ice.cpp @@ -59,12 +59,14 @@ private: void testTurnMasterIceConnection(); void testTurnSlaveIceConnection(); void testReceiveTooManyCandidates(); + void testCompleteOnFailure(); CPPUNIT_TEST_SUITE(IceTest); CPPUNIT_TEST(testRawIceConnection); CPPUNIT_TEST(testTurnMasterIceConnection); CPPUNIT_TEST(testTurnSlaveIceConnection); CPPUNIT_TEST(testReceiveTooManyCandidates); + CPPUNIT_TEST(testCompleteOnFailure); CPPUNIT_TEST_SUITE_END(); }; @@ -506,12 +508,127 @@ IceTest::testReceiveTooManyCandidates() ice_config.compCountPerStream = 1; ice_slave = Manager::instance().getIceTransportFactory().createTransport("slave ICE", - ice_config); + ice_config); cv_create.notify_all(); CPPUNIT_ASSERT( cv.wait_for(lk, std::chrono::seconds(10), [&] { return iceMasterReady && iceSlaveReady; })); } +void +IceTest::testCompleteOnFailure() +{ + const auto& addr4 = dht_->getPublicAddress(AF_INET); + CPPUNIT_ASSERT(addr4.size() != 0); + CPPUNIT_ASSERT(turnV4_); + IceTransportOptions ice_config; + ice_config.upnpEnable = true; + ice_config.tcpEnable = true; + std::shared_ptr<IceTransport> ice_master, ice_slave; + std::mutex mtx, mtx_create, mtx_resp, mtx_init; + std::unique_lock<std::mutex> lk {mtx}, lk_create {mtx_create}, lk_resp {mtx_resp}, + lk_init {mtx_init}; + std::condition_variable cv, cv_create, cv_resp, cv_init; + std::string init = {}; + std::string response = {}; + bool iceMasterNotReady = false, iceSlaveNotReady = false; + ice_config.onInitDone = [&](bool ok) { + CPPUNIT_ASSERT(ok); + dht::ThreadPool::io().run([&] { + CPPUNIT_ASSERT(cv_create.wait_for(lk_create, std::chrono::seconds(10), [&] { + return ice_master != nullptr; + })); + auto iceAttributes = ice_master->getLocalAttributes(); + std::stringstream icemsg; + icemsg << iceAttributes.ufrag << "\n"; + icemsg << iceAttributes.pwd << "\n"; + for (const auto& addr : ice_master->getLocalCandidates(1)) { + if (addr.find("relay") != std::string::npos) { + // We only want to relayed and modify the rest (to have CONNREFUSED) + icemsg << addr << "\n"; + JAMI_DBG() << "Added local ICE candidate " << addr; + } else { + // Replace host by non existing IP (we still need host to not fail the start) + std::regex e("((?:[0-9]{1,3}\\.){3}[0-9]{1,3})"); + auto newaddr = std::regex_replace(addr, e, "100.100.100.100"); + if (newaddr != addr) + icemsg << newaddr << "\n"; + } + } + init = icemsg.str(); + cv_init.notify_one(); + CPPUNIT_ASSERT(cv_resp.wait_for(lk_resp, std::chrono::seconds(10), [&] { + return !response.empty(); + })); + auto sdp = ice_master->parseIceCandidates(response); + CPPUNIT_ASSERT( + ice_master->startIce({sdp.rem_ufrag, sdp.rem_pwd}, std::move(sdp.rem_candidates))); + }); + }; + ice_config.onNegoDone = [&](bool ok) { + iceMasterNotReady = !ok; + cv.notify_one(); + }; + ice_config.accountPublicAddr = IpAddr(*addr4[0].get()); + ice_config.accountLocalAddr = ip_utils::getLocalAddr(AF_INET); + ice_config.master = true; + ice_config.streamsCount = 1; + ice_config.compCountPerStream = 1; + ice_master = Manager::instance().getIceTransportFactory().createTransport("master ICE", + ice_config); + cv_create.notify_all(); + ice_config.onInitDone = [&](bool ok) { + CPPUNIT_ASSERT(ok); + dht::ThreadPool::io().run([&] { + CPPUNIT_ASSERT(cv_create.wait_for(lk_create, std::chrono::seconds(10), [&] { + return ice_slave != nullptr; + })); + auto iceAttributes = ice_slave->getLocalAttributes(); + std::stringstream icemsg; + icemsg << iceAttributes.ufrag << "\n"; + icemsg << iceAttributes.pwd << "\n"; + for (const auto& addr : ice_slave->getLocalCandidates(1)) { + if (addr.find("relay") != std::string::npos) { + // We only want to relayed and modify the rest (to have CONNREFUSED) + icemsg << addr << "\n"; + JAMI_DBG() << "Added local ICE candidate " << addr; + } else { + // Replace host by non existing IP (we still need host to not fail the start) + std::regex e("((?:[0-9]{1,3}\\.){3}[0-9]{1,3})"); + auto newaddr = std::regex_replace(addr, e, "100.100.100.100"); + if (newaddr != addr) + icemsg << newaddr << "\n"; + } + } + response = icemsg.str(); + cv_resp.notify_one(); + CPPUNIT_ASSERT( + cv_init.wait_for(lk_resp, std::chrono::seconds(10), [&] { return !init.empty(); })); + auto sdp = ice_slave->parseIceCandidates(init); + CPPUNIT_ASSERT( + ice_slave->startIce({sdp.rem_ufrag, sdp.rem_pwd}, std::move(sdp.rem_candidates))); + }); + }; + ice_config.onNegoDone = [&](bool ok) { + iceSlaveNotReady = !ok; + cv.notify_one(); + }; + ice_config.turnServers.emplace_back(TurnServerInfo() + .setUri(turnV4_->toString(true)) + .setUsername("ring") + .setPassword("ring") + .setRealm("ring")); + ice_config.master = false; + ice_config.streamsCount = 1; + ice_config.compCountPerStream = 1; + ice_slave = Manager::instance().getIceTransportFactory().createTransport("slave ICE", + ice_config); + cv_create.notify_all(); + // Check that nego failed and callback called + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(120), [&] { + return iceMasterNotReady && iceSlaveNotReady; + })); +} + } // namespace test } // namespace jami