icetransport.cpp 30 KB

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