2
0

icetransport.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /**
  2. * Copyright (c) 2019-2020 Paul-Louis Ageneau
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "icetransport.hpp"
  19. #include "configuration.hpp"
  20. #include "internals.hpp"
  21. #include "transport.hpp"
  22. #include <iostream>
  23. #include <random>
  24. #include <sstream>
  25. #ifdef _WIN32
  26. #include <winsock2.h>
  27. #include <ws2tcpip.h>
  28. #else
  29. #include <arpa/inet.h>
  30. #include <netdb.h>
  31. #include <netinet/in.h>
  32. #include <sys/socket.h>
  33. #endif
  34. #include <sys/types.h>
  35. using namespace std::chrono_literals;
  36. using std::chrono::system_clock;
  37. namespace rtc::impl {
  38. #if !USE_NICE // libjuice
  39. const int MAX_TURN_SERVERS_COUNT = 2;
  40. IceTransport::IceTransport(const Configuration &config, candidate_callback candidateCallback,
  41. state_callback stateChangeCallback,
  42. gathering_state_callback gatheringStateChangeCallback)
  43. : Transport(nullptr, std::move(stateChangeCallback)), mRole(Description::Role::ActPass),
  44. mMid("0"), mGatheringState(GatheringState::New),
  45. mCandidateCallback(std::move(candidateCallback)),
  46. mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)),
  47. mAgent(nullptr, nullptr) {
  48. PLOG_DEBUG << "Initializing ICE transport (libjuice)";
  49. juice_log_level_t level;
  50. auto logger = plog::get();
  51. switch (logger ? logger->getMaxSeverity() : plog::none) {
  52. case plog::none:
  53. level = JUICE_LOG_LEVEL_NONE;
  54. break;
  55. case plog::fatal:
  56. level = JUICE_LOG_LEVEL_VERBOSE;
  57. break;
  58. case plog::error:
  59. level = JUICE_LOG_LEVEL_ERROR;
  60. break;
  61. case plog::warning:
  62. level = JUICE_LOG_LEVEL_WARN;
  63. break;
  64. case plog::info:
  65. case plog::debug: // juice debug is output as verbose
  66. level = JUICE_LOG_LEVEL_INFO;
  67. break;
  68. default:
  69. level = JUICE_LOG_LEVEL_VERBOSE;
  70. break;
  71. }
  72. juice_set_log_handler(IceTransport::LogCallback);
  73. juice_set_log_level(level);
  74. juice_config_t jconfig = {};
  75. jconfig.cb_state_changed = IceTransport::StateChangeCallback;
  76. jconfig.cb_candidate = IceTransport::CandidateCallback;
  77. jconfig.cb_gathering_done = IceTransport::GatheringDoneCallback;
  78. jconfig.cb_recv = IceTransport::RecvCallback;
  79. jconfig.user_ptr = this;
  80. if (config.enableIceTcp) {
  81. PLOG_WARNING << "ICE-TCP is not supported with libjuice";
  82. }
  83. if (config.enableIceUdpMux) {
  84. PLOG_DEBUG << "Enabling ICE UDP mux";
  85. jconfig.concurrency_mode = JUICE_CONCURRENCY_MODE_MUX;
  86. } else {
  87. jconfig.concurrency_mode = JUICE_CONCURRENCY_MODE_POLL;
  88. }
  89. // Randomize servers order
  90. std::vector<IceServer> servers = config.iceServers;
  91. auto seed = static_cast<unsigned int>(system_clock::now().time_since_epoch().count());
  92. std::shuffle(servers.begin(), servers.end(), std::default_random_engine(seed));
  93. // Pick a STUN server
  94. for (auto &server : servers) {
  95. if (!server.hostname.empty() && server.type == IceServer::Type::Stun) {
  96. if (server.port == 0)
  97. server.port = 3478; // STUN UDP port
  98. PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port << "\"";
  99. jconfig.stun_server_host = server.hostname.c_str();
  100. jconfig.stun_server_port = server.port;
  101. break;
  102. }
  103. }
  104. juice_turn_server_t turn_servers[MAX_TURN_SERVERS_COUNT];
  105. std::memset(turn_servers, 0, sizeof(turn_servers));
  106. // Add TURN servers
  107. int k = 0;
  108. for (auto &server : servers) {
  109. if (!server.hostname.empty() && server.type == IceServer::Type::Turn) {
  110. if (server.port == 0)
  111. server.port = 3478; // TURN UDP port
  112. PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\"";
  113. turn_servers[k].host = server.hostname.c_str();
  114. turn_servers[k].username = server.username.c_str();
  115. turn_servers[k].password = server.password.c_str();
  116. turn_servers[k].port = server.port;
  117. if (++k >= MAX_TURN_SERVERS_COUNT)
  118. break;
  119. }
  120. }
  121. jconfig.turn_servers = k > 0 ? turn_servers : nullptr;
  122. jconfig.turn_servers_count = k;
  123. // Bind address
  124. if (config.bindAddress) {
  125. jconfig.bind_address = config.bindAddress->c_str();
  126. }
  127. // Port range
  128. if (config.portRangeBegin > 1024 ||
  129. (config.portRangeEnd != 0 && config.portRangeEnd != 65535)) {
  130. jconfig.local_port_range_begin = config.portRangeBegin;
  131. jconfig.local_port_range_end = config.portRangeEnd;
  132. }
  133. // Create agent
  134. mAgent = decltype(mAgent)(juice_create(&jconfig), juice_destroy);
  135. if (!mAgent)
  136. throw std::runtime_error("Failed to create the ICE agent");
  137. }
  138. IceTransport::~IceTransport() {
  139. stop();
  140. mAgent.reset();
  141. }
  142. bool IceTransport::stop() { return Transport::stop(); }
  143. Description::Role IceTransport::role() const { return mRole; }
  144. Description IceTransport::getLocalDescription(Description::Type type) const {
  145. char sdp[JUICE_MAX_SDP_STRING_LEN];
  146. if (juice_get_local_description(mAgent.get(), sdp, JUICE_MAX_SDP_STRING_LEN) < 0)
  147. throw std::runtime_error("Failed to generate local SDP");
  148. // RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of
  149. // setup:actpass.
  150. // See https://tools.ietf.org/html/rfc5763#section-5
  151. Description desc(string(sdp), type,
  152. type == Description::Type::Offer ? Description::Role::ActPass : mRole);
  153. desc.addIceOption("trickle");
  154. return desc;
  155. }
  156. void IceTransport::setRemoteDescription(const Description &description) {
  157. if (mRole == Description::Role::ActPass)
  158. mRole = description.role() == Description::Role::Active ? Description::Role::Passive
  159. : Description::Role::Active;
  160. if (mRole == description.role())
  161. throw std::logic_error("Incompatible roles with remote description");
  162. mMid = description.bundleMid();
  163. if (juice_set_remote_description(mAgent.get(),
  164. description.generateApplicationSdp("\r\n").c_str()) < 0)
  165. throw std::runtime_error("Failed to parse ICE settings from remote SDP");
  166. }
  167. bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
  168. // Don't try to pass unresolved candidates for more safety
  169. if (!candidate.isResolved())
  170. return false;
  171. return juice_add_remote_candidate(mAgent.get(), string(candidate).c_str()) >= 0;
  172. }
  173. void IceTransport::gatherLocalCandidates(string mid) {
  174. mMid = std::move(mid);
  175. // Change state now as candidates calls can be synchronous
  176. changeGatheringState(GatheringState::InProgress);
  177. if (juice_gather_candidates(mAgent.get()) < 0) {
  178. throw std::runtime_error("Failed to gather local ICE candidates");
  179. }
  180. }
  181. optional<string> IceTransport::getLocalAddress() const {
  182. char str[JUICE_MAX_ADDRESS_STRING_LEN];
  183. if (juice_get_selected_addresses(mAgent.get(), str, JUICE_MAX_ADDRESS_STRING_LEN, NULL, 0) ==
  184. 0) {
  185. return std::make_optional(string(str));
  186. }
  187. return nullopt;
  188. }
  189. optional<string> IceTransport::getRemoteAddress() const {
  190. char str[JUICE_MAX_ADDRESS_STRING_LEN];
  191. if (juice_get_selected_addresses(mAgent.get(), NULL, 0, str, JUICE_MAX_ADDRESS_STRING_LEN) ==
  192. 0) {
  193. return std::make_optional(string(str));
  194. }
  195. return nullopt;
  196. }
  197. bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) {
  198. char sdpLocal[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
  199. char sdpRemote[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
  200. if (juice_get_selected_candidates(mAgent.get(), sdpLocal, JUICE_MAX_CANDIDATE_SDP_STRING_LEN,
  201. sdpRemote, JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0) {
  202. if (local) {
  203. *local = Candidate(sdpLocal, mMid);
  204. local->resolve(Candidate::ResolveMode::Simple);
  205. }
  206. if (remote) {
  207. *remote = Candidate(sdpRemote, mMid);
  208. remote->resolve(Candidate::ResolveMode::Simple);
  209. }
  210. return true;
  211. }
  212. return false;
  213. }
  214. bool IceTransport::send(message_ptr message) {
  215. auto s = state();
  216. if (!message || (s != State::Connected && s != State::Completed))
  217. return false;
  218. PLOG_VERBOSE << "Send size=" << message->size();
  219. return outgoing(message);
  220. }
  221. bool IceTransport::outgoing(message_ptr message) {
  222. // Explicit Congestion Notification takes the least-significant 2 bits of the DS field
  223. int ds = int(message->dscp << 2);
  224. return juice_send_diffserv(mAgent.get(), reinterpret_cast<const char *>(message->data()),
  225. message->size(), ds) >= 0;
  226. }
  227. void IceTransport::changeGatheringState(GatheringState state) {
  228. if (mGatheringState.exchange(state) != state)
  229. mGatheringStateChangeCallback(mGatheringState);
  230. }
  231. void IceTransport::processStateChange(unsigned int state) {
  232. switch (state) {
  233. case JUICE_STATE_DISCONNECTED:
  234. changeState(State::Disconnected);
  235. break;
  236. case JUICE_STATE_CONNECTING:
  237. changeState(State::Connecting);
  238. break;
  239. case JUICE_STATE_CONNECTED:
  240. changeState(State::Connected);
  241. break;
  242. case JUICE_STATE_COMPLETED:
  243. changeState(State::Completed);
  244. break;
  245. case JUICE_STATE_FAILED:
  246. changeState(State::Failed);
  247. break;
  248. };
  249. }
  250. void IceTransport::processCandidate(const string &candidate) {
  251. mCandidateCallback(Candidate(candidate, mMid));
  252. }
  253. void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); }
  254. void IceTransport::StateChangeCallback(juice_agent_t *, juice_state_t state, void *user_ptr) {
  255. auto iceTransport = static_cast<rtc::impl::IceTransport *>(user_ptr);
  256. try {
  257. iceTransport->processStateChange(static_cast<unsigned int>(state));
  258. } catch (const std::exception &e) {
  259. PLOG_WARNING << e.what();
  260. }
  261. }
  262. void IceTransport::CandidateCallback(juice_agent_t *, const char *sdp, void *user_ptr) {
  263. auto iceTransport = static_cast<rtc::impl::IceTransport *>(user_ptr);
  264. try {
  265. iceTransport->processCandidate(sdp);
  266. } catch (const std::exception &e) {
  267. PLOG_WARNING << e.what();
  268. }
  269. }
  270. void IceTransport::GatheringDoneCallback(juice_agent_t *, void *user_ptr) {
  271. auto iceTransport = static_cast<rtc::impl::IceTransport *>(user_ptr);
  272. try {
  273. iceTransport->processGatheringDone();
  274. } catch (const std::exception &e) {
  275. PLOG_WARNING << e.what();
  276. }
  277. }
  278. void IceTransport::RecvCallback(juice_agent_t *, const char *data, size_t size, void *user_ptr) {
  279. auto iceTransport = static_cast<rtc::impl::IceTransport *>(user_ptr);
  280. try {
  281. PLOG_VERBOSE << "Incoming size=" << size;
  282. auto b = reinterpret_cast<const byte *>(data);
  283. iceTransport->incoming(make_message(b, b + size));
  284. } catch (const std::exception &e) {
  285. PLOG_WARNING << e.what();
  286. }
  287. }
  288. void IceTransport::LogCallback(juice_log_level_t level, const char *message) {
  289. plog::Severity severity;
  290. switch (level) {
  291. case JUICE_LOG_LEVEL_FATAL:
  292. severity = plog::fatal;
  293. break;
  294. case JUICE_LOG_LEVEL_ERROR:
  295. severity = plog::error;
  296. break;
  297. case JUICE_LOG_LEVEL_WARN:
  298. severity = plog::warning;
  299. break;
  300. case JUICE_LOG_LEVEL_INFO:
  301. severity = plog::info;
  302. break;
  303. default:
  304. severity = plog::verbose; // libjuice debug as verbose
  305. break;
  306. }
  307. PLOG(severity) << "juice: " << message;
  308. }
  309. #else // USE_NICE == 1
  310. IceTransport::IceTransport(const Configuration &config, candidate_callback candidateCallback,
  311. state_callback stateChangeCallback,
  312. gathering_state_callback gatheringStateChangeCallback)
  313. : Transport(nullptr, std::move(stateChangeCallback)), mRole(Description::Role::ActPass),
  314. mMid("0"), mGatheringState(GatheringState::New),
  315. mCandidateCallback(std::move(candidateCallback)),
  316. mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)),
  317. mNiceAgent(nullptr, nullptr), mMainLoop(nullptr, nullptr), mOutgoingDscp(0) {
  318. PLOG_DEBUG << "Initializing ICE transport (libnice)";
  319. g_log_set_handler("libnice", G_LOG_LEVEL_MASK, LogCallback, this);
  320. IF_PLOG(plog::verbose) {
  321. nice_debug_enable(false); // do not output STUN debug messages
  322. }
  323. mMainLoop = decltype(mMainLoop)(g_main_loop_new(nullptr, FALSE), g_main_loop_unref);
  324. if (!mMainLoop)
  325. std::runtime_error("Failed to create the main loop");
  326. // RFC 8445: The nomination process that was referred to as "aggressive nomination" in RFC 5245
  327. // has been deprecated in this specification.
  328. // libnice defaults to aggressive nomation therefore we change to regular nomination.
  329. // See https://gitlab.freedesktop.org/libnice/libnice/-/merge_requests/125
  330. NiceAgentOption flags = NICE_AGENT_OPTION_REGULAR_NOMINATION;
  331. // Create agent
  332. mNiceAgent = decltype(mNiceAgent)(
  333. nice_agent_new_full(
  334. g_main_loop_get_context(mMainLoop.get()),
  335. NICE_COMPATIBILITY_RFC5245, // RFC 5245 was obsoleted by RFC 8445 but this should be OK
  336. flags),
  337. g_object_unref);
  338. if (!mNiceAgent)
  339. throw std::runtime_error("Failed to create the nice agent");
  340. mMainLoopThread = std::thread(g_main_loop_run, mMainLoop.get());
  341. mStreamId = nice_agent_add_stream(mNiceAgent.get(), 1);
  342. if (!mStreamId)
  343. throw std::runtime_error("Failed to add a stream");
  344. g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", TRUE, nullptr); // decided later
  345. g_object_set(G_OBJECT(mNiceAgent.get()), "ice-udp", TRUE, nullptr);
  346. g_object_set(G_OBJECT(mNiceAgent.get()), "ice-tcp", config.enableIceTcp ? TRUE : FALSE,
  347. nullptr);
  348. // RFC 8445: Agents MUST NOT use an RTO value smaller than 500 ms.
  349. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-initial-timeout", 500, nullptr);
  350. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-max-retransmissions", 3, nullptr);
  351. // RFC 8445: ICE agents SHOULD use a default Ta value, 50 ms, but MAY use another value based on
  352. // the characteristics of the associated data.
  353. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-pacing-timer", 25, nullptr);
  354. g_object_set(G_OBJECT(mNiceAgent.get()), "upnp", FALSE, nullptr);
  355. g_object_set(G_OBJECT(mNiceAgent.get()), "upnp-timeout", 200, nullptr);
  356. // Proxy
  357. if (config.proxyServer.has_value()) {
  358. ProxyServer proxyServer = config.proxyServer.value();
  359. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-type", proxyServer.type, nullptr);
  360. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.hostname.c_str(), nullptr);
  361. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-port", proxyServer.port, nullptr);
  362. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-username", proxyServer.username.c_str(),
  363. nullptr);
  364. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-password", proxyServer.password.c_str(),
  365. nullptr);
  366. }
  367. if (config.enableIceUdpMux) {
  368. PLOG_WARNING << "ICE UDP mux is not available with libnice";
  369. }
  370. // Randomize order
  371. std::vector<IceServer> servers = config.iceServers;
  372. auto seed = static_cast<unsigned int>(system_clock::now().time_since_epoch().count());
  373. std::shuffle(servers.begin(), servers.end(), std::default_random_engine(seed));
  374. // Add one STUN server
  375. bool success = false;
  376. for (auto &server : servers) {
  377. if (server.hostname.empty())
  378. continue;
  379. if (server.type != IceServer::Type::Stun)
  380. continue;
  381. if (server.port == 0)
  382. server.port = 3478; // STUN UDP port
  383. struct addrinfo hints = {};
  384. hints.ai_family = AF_INET; // IPv4
  385. hints.ai_socktype = SOCK_DGRAM;
  386. hints.ai_protocol = IPPROTO_UDP;
  387. hints.ai_flags = AI_ADDRCONFIG;
  388. struct addrinfo *result = nullptr;
  389. if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints,
  390. &result) != 0) {
  391. PLOG_WARNING << "Unable to resolve STUN server address: " << server.hostname << ':'
  392. << server.port;
  393. continue;
  394. }
  395. for (auto p = result; p; p = p->ai_next) {
  396. if (p->ai_family == AF_INET) {
  397. char nodebuffer[MAX_NUMERICNODE_LEN];
  398. char servbuffer[MAX_NUMERICSERV_LEN];
  399. if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
  400. servbuffer, MAX_NUMERICSERV_LEN,
  401. NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
  402. PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port
  403. << "\"";
  404. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr);
  405. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port",
  406. std::stoul(servbuffer), nullptr);
  407. success = true;
  408. break;
  409. }
  410. }
  411. }
  412. freeaddrinfo(result);
  413. if (success)
  414. break;
  415. }
  416. // Add TURN servers
  417. for (auto &server : servers) {
  418. if (server.hostname.empty())
  419. continue;
  420. if (server.type != IceServer::Type::Turn)
  421. continue;
  422. if (server.port == 0)
  423. server.port = server.relayType == IceServer::RelayType::TurnTls ? 5349 : 3478;
  424. struct addrinfo hints = {};
  425. hints.ai_family = AF_UNSPEC;
  426. hints.ai_socktype =
  427. server.relayType == IceServer::RelayType::TurnUdp ? SOCK_DGRAM : SOCK_STREAM;
  428. hints.ai_protocol =
  429. server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP;
  430. hints.ai_flags = AI_ADDRCONFIG;
  431. struct addrinfo *result = nullptr;
  432. if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints,
  433. &result) != 0) {
  434. PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':'
  435. << server.port;
  436. continue;
  437. }
  438. for (auto p = result; p; p = p->ai_next) {
  439. if (p->ai_family == AF_INET || p->ai_family == AF_INET6) {
  440. char nodebuffer[MAX_NUMERICNODE_LEN];
  441. char servbuffer[MAX_NUMERICSERV_LEN];
  442. if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
  443. servbuffer, MAX_NUMERICSERV_LEN,
  444. NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
  445. PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port
  446. << "\"";
  447. NiceRelayType niceRelayType;
  448. switch (server.relayType) {
  449. case IceServer::RelayType::TurnTcp:
  450. niceRelayType = NICE_RELAY_TYPE_TURN_TCP;
  451. break;
  452. case IceServer::RelayType::TurnTls:
  453. niceRelayType = NICE_RELAY_TYPE_TURN_TLS;
  454. break;
  455. default:
  456. niceRelayType = NICE_RELAY_TYPE_TURN_UDP;
  457. break;
  458. }
  459. nice_agent_set_relay_info(mNiceAgent.get(), mStreamId, 1, nodebuffer,
  460. std::stoul(servbuffer), server.username.c_str(),
  461. server.password.c_str(), niceRelayType);
  462. }
  463. }
  464. }
  465. freeaddrinfo(result);
  466. }
  467. g_signal_connect(G_OBJECT(mNiceAgent.get()), "component-state-changed",
  468. G_CALLBACK(StateChangeCallback), this);
  469. g_signal_connect(G_OBJECT(mNiceAgent.get()), "new-candidate-full",
  470. G_CALLBACK(CandidateCallback), this);
  471. g_signal_connect(G_OBJECT(mNiceAgent.get()), "candidate-gathering-done",
  472. G_CALLBACK(GatheringDoneCallback), this);
  473. nice_agent_set_stream_name(mNiceAgent.get(), mStreamId, "application");
  474. nice_agent_set_port_range(mNiceAgent.get(), mStreamId, 1, config.portRangeBegin,
  475. config.portRangeEnd);
  476. nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(mMainLoop.get()),
  477. RecvCallback, this);
  478. }
  479. IceTransport::~IceTransport() { stop(); }
  480. bool IceTransport::stop() {
  481. if (mTimeoutId) {
  482. g_source_remove(mTimeoutId);
  483. mTimeoutId = 0;
  484. }
  485. if (!Transport::stop())
  486. return false;
  487. PLOG_DEBUG << "Stopping ICE thread";
  488. nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(mMainLoop.get()),
  489. NULL, NULL);
  490. nice_agent_remove_stream(mNiceAgent.get(), mStreamId);
  491. g_main_loop_quit(mMainLoop.get());
  492. mMainLoopThread.join();
  493. return true;
  494. }
  495. Description::Role IceTransport::role() const { return mRole; }
  496. Description IceTransport::getLocalDescription(Description::Type type) const {
  497. // RFC 8445: The initiating agent that started the ICE processing MUST take the controlling
  498. // role, and the other MUST take the controlled role.
  499. g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode",
  500. type == Description::Type::Offer ? TRUE : FALSE, nullptr);
  501. unique_ptr<gchar[], void (*)(void *)> sdp(nice_agent_generate_local_sdp(mNiceAgent.get()),
  502. g_free);
  503. // RFC 5763: The endpoint that is the offerer MUST use the setup attribute value of
  504. // setup:actpass.
  505. // See https://tools.ietf.org/html/rfc5763#section-5
  506. Description desc(string(sdp.get()), type,
  507. type == Description::Type::Offer ? Description::Role::ActPass : mRole);
  508. desc.addIceOption("trickle");
  509. return desc;
  510. }
  511. void IceTransport::setRemoteDescription(const Description &description) {
  512. if (mRole == Description::Role::ActPass)
  513. mRole = description.role() == Description::Role::Active ? Description::Role::Passive
  514. : Description::Role::Active;
  515. if (mRole == description.role())
  516. throw std::logic_error("Incompatible roles with remote description");
  517. mMid = description.bundleMid();
  518. mTrickleTimeout = !description.ended() ? 30s : 0s;
  519. // Warning: libnice expects "\n" as end of line
  520. if (nice_agent_parse_remote_sdp(mNiceAgent.get(),
  521. description.generateApplicationSdp("\n").c_str()) < 0)
  522. throw std::runtime_error("Failed to parse ICE settings from remote SDP");
  523. }
  524. bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
  525. // Don't try to pass unresolved candidates to libnice for more safety
  526. if (!candidate.isResolved())
  527. return false;
  528. // Warning: the candidate string must start with "a=candidate:" and it must not end with a
  529. // newline or whitespace, else libnice will reject it.
  530. string sdp(candidate);
  531. NiceCandidate *cand =
  532. nice_agent_parse_remote_candidate_sdp(mNiceAgent.get(), mStreamId, sdp.c_str());
  533. if (!cand) {
  534. PLOG_WARNING << "Rejected ICE candidate: " << sdp;
  535. return false;
  536. }
  537. GSList *list = g_slist_append(nullptr, cand);
  538. int ret = nice_agent_set_remote_candidates(mNiceAgent.get(), mStreamId, 1, list);
  539. g_slist_free_full(list, reinterpret_cast<GDestroyNotify>(nice_candidate_free));
  540. return ret > 0;
  541. }
  542. void IceTransport::gatherLocalCandidates(string mid) {
  543. mMid = std::move(mid);
  544. // Change state now as candidates calls can be synchronous
  545. changeGatheringState(GatheringState::InProgress);
  546. if (!nice_agent_gather_candidates(mNiceAgent.get(), mStreamId)) {
  547. throw std::runtime_error("Failed to gather local ICE candidates");
  548. }
  549. }
  550. optional<string> IceTransport::getLocalAddress() const {
  551. NiceCandidate *local = nullptr;
  552. NiceCandidate *remote = nullptr;
  553. if (nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote)) {
  554. return std::make_optional(AddressToString(local->addr));
  555. }
  556. return nullopt;
  557. }
  558. optional<string> IceTransport::getRemoteAddress() const {
  559. NiceCandidate *local = nullptr;
  560. NiceCandidate *remote = nullptr;
  561. if (nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote)) {
  562. return std::make_optional(AddressToString(remote->addr));
  563. }
  564. return nullopt;
  565. }
  566. bool IceTransport::send(message_ptr message) {
  567. auto s = state();
  568. if (!message || (s != State::Connected && s != State::Completed))
  569. return false;
  570. PLOG_VERBOSE << "Send size=" << message->size();
  571. return outgoing(message);
  572. }
  573. bool IceTransport::outgoing(message_ptr message) {
  574. std::lock_guard lock(mOutgoingMutex);
  575. if (mOutgoingDscp != message->dscp) {
  576. mOutgoingDscp = message->dscp;
  577. // Explicit Congestion Notification takes the least-significant 2 bits of the DS field
  578. int ds = int(message->dscp << 2);
  579. nice_agent_set_stream_tos(mNiceAgent.get(), mStreamId, ds); // ToS is the legacy name for DS
  580. }
  581. return nice_agent_send(mNiceAgent.get(), mStreamId, 1, message->size(),
  582. reinterpret_cast<const char *>(message->data())) >= 0;
  583. }
  584. void IceTransport::changeGatheringState(GatheringState state) {
  585. if (mGatheringState.exchange(state) != state)
  586. mGatheringStateChangeCallback(mGatheringState);
  587. }
  588. void IceTransport::processTimeout() {
  589. PLOG_WARNING << "ICE timeout";
  590. mTimeoutId = 0;
  591. changeState(State::Failed);
  592. }
  593. void IceTransport::processCandidate(const string &candidate) {
  594. mCandidateCallback(Candidate(candidate, mMid));
  595. }
  596. void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); }
  597. void IceTransport::processStateChange(unsigned int state) {
  598. if (state == NICE_COMPONENT_STATE_FAILED && mTrickleTimeout.count() > 0) {
  599. if (mTimeoutId)
  600. g_source_remove(mTimeoutId);
  601. mTimeoutId = g_timeout_add(mTrickleTimeout.count() /* ms */, TimeoutCallback, this);
  602. return;
  603. }
  604. if (state == NICE_COMPONENT_STATE_CONNECTED && mTimeoutId) {
  605. g_source_remove(mTimeoutId);
  606. mTimeoutId = 0;
  607. }
  608. switch (state) {
  609. case NICE_COMPONENT_STATE_DISCONNECTED:
  610. changeState(State::Disconnected);
  611. break;
  612. case NICE_COMPONENT_STATE_CONNECTING:
  613. changeState(State::Connecting);
  614. break;
  615. case NICE_COMPONENT_STATE_CONNECTED:
  616. changeState(State::Connected);
  617. break;
  618. case NICE_COMPONENT_STATE_READY:
  619. changeState(State::Completed);
  620. break;
  621. case NICE_COMPONENT_STATE_FAILED:
  622. changeState(State::Failed);
  623. break;
  624. };
  625. }
  626. string IceTransport::AddressToString(const NiceAddress &addr) {
  627. char buffer[NICE_ADDRESS_STRING_LEN];
  628. nice_address_to_string(&addr, buffer);
  629. unsigned int port = nice_address_get_port(&addr);
  630. std::ostringstream ss;
  631. ss << buffer << ":" << port;
  632. return ss.str();
  633. }
  634. void IceTransport::CandidateCallback(NiceAgent *agent, NiceCandidate *candidate,
  635. gpointer userData) {
  636. auto iceTransport = static_cast<rtc::impl::IceTransport *>(userData);
  637. gchar *cand = nice_agent_generate_local_candidate_sdp(agent, candidate);
  638. try {
  639. iceTransport->processCandidate(cand);
  640. } catch (const std::exception &e) {
  641. PLOG_WARNING << e.what();
  642. }
  643. g_free(cand);
  644. }
  645. void IceTransport::GatheringDoneCallback(NiceAgent * /*agent*/, guint /*streamId*/,
  646. gpointer userData) {
  647. auto iceTransport = static_cast<rtc::impl::IceTransport *>(userData);
  648. try {
  649. iceTransport->processGatheringDone();
  650. } catch (const std::exception &e) {
  651. PLOG_WARNING << e.what();
  652. }
  653. }
  654. void IceTransport::StateChangeCallback(NiceAgent * /*agent*/, guint /*streamId*/,
  655. guint /*componentId*/, guint state, gpointer userData) {
  656. auto iceTransport = static_cast<rtc::impl::IceTransport *>(userData);
  657. try {
  658. iceTransport->processStateChange(state);
  659. } catch (const std::exception &e) {
  660. PLOG_WARNING << e.what();
  661. }
  662. }
  663. void IceTransport::RecvCallback(NiceAgent * /*agent*/, guint /*streamId*/, guint /*componentId*/,
  664. guint len, gchar *buf, gpointer userData) {
  665. auto iceTransport = static_cast<rtc::impl::IceTransport *>(userData);
  666. try {
  667. PLOG_VERBOSE << "Incoming size=" << len;
  668. auto b = reinterpret_cast<byte *>(buf);
  669. iceTransport->incoming(make_message(b, b + len));
  670. } catch (const std::exception &e) {
  671. PLOG_WARNING << e.what();
  672. }
  673. }
  674. gboolean IceTransport::TimeoutCallback(gpointer userData) {
  675. auto iceTransport = static_cast<rtc::impl::IceTransport *>(userData);
  676. try {
  677. iceTransport->processTimeout();
  678. } catch (const std::exception &e) {
  679. PLOG_WARNING << e.what();
  680. }
  681. return FALSE;
  682. }
  683. void IceTransport::LogCallback(const gchar * /*logDomain*/, GLogLevelFlags logLevel,
  684. const gchar *message, gpointer /*userData*/) {
  685. plog::Severity severity;
  686. unsigned int flags = logLevel & G_LOG_LEVEL_MASK;
  687. if (flags & G_LOG_LEVEL_ERROR)
  688. severity = plog::fatal;
  689. else if (flags & G_LOG_LEVEL_CRITICAL)
  690. severity = plog::error;
  691. else if (flags & G_LOG_LEVEL_WARNING)
  692. severity = plog::warning;
  693. else if (flags & G_LOG_LEVEL_MESSAGE)
  694. severity = plog::info;
  695. else if (flags & G_LOG_LEVEL_INFO)
  696. severity = plog::info;
  697. else
  698. severity = plog::verbose; // libnice debug as verbose
  699. PLOG(severity) << "nice: " << message;
  700. }
  701. bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) {
  702. NiceCandidate *niceLocal, *niceRemote;
  703. if (!nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &niceLocal, &niceRemote))
  704. return false;
  705. gchar *sdpLocal = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceLocal);
  706. if (local)
  707. *local = Candidate(sdpLocal, mMid);
  708. g_free(sdpLocal);
  709. gchar *sdpRemote = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceRemote);
  710. if (remote)
  711. *remote = Candidate(sdpRemote, mMid);
  712. g_free(sdpRemote);
  713. if (local)
  714. local->resolve(Candidate::ResolveMode::Simple);
  715. if (remote)
  716. remote->resolve(Candidate::ResolveMode::Simple);
  717. return true;
  718. }
  719. #endif
  720. } // namespace rtc::impl