icetransport.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  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 "transport.hpp"
  21. #include <iostream>
  22. #include <random>
  23. #include <sstream>
  24. #ifdef _WIN32
  25. #include <winsock2.h>
  26. #include <ws2tcpip.h>
  27. #else
  28. #include <arpa/inet.h>
  29. #include <netdb.h>
  30. #include <netinet/in.h>
  31. #include <sys/socket.h>
  32. #endif
  33. #include <sys/types.h>
  34. using namespace std::chrono_literals;
  35. using std::shared_ptr;
  36. using std::weak_ptr;
  37. #if USE_JUICE
  38. namespace rtc {
  39. IceTransport::IceTransport(const Configuration &config, Description::Role role,
  40. candidate_callback candidateCallback, state_callback stateChangeCallback,
  41. gathering_state_callback gatheringStateChangeCallback)
  42. : Transport(nullptr, std::move(stateChangeCallback)), mRole(role), mMid("0"),
  43. mGatheringState(GatheringState::New), mCandidateCallback(std::move(candidateCallback)),
  44. mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)),
  45. mAgent(nullptr, nullptr) {
  46. PLOG_DEBUG << "Initializing ICE transport (libjuice)";
  47. if (config.enableIceTcp) {
  48. PLOG_WARNING << "ICE-TCP is not supported with libjuice";
  49. }
  50. juice_set_log_handler(IceTransport::LogCallback);
  51. juice_set_log_level(JUICE_LOG_LEVEL_VERBOSE);
  52. juice_config_t jconfig = {};
  53. jconfig.cb_state_changed = IceTransport::StateChangeCallback;
  54. jconfig.cb_candidate = IceTransport::CandidateCallback;
  55. jconfig.cb_gathering_done = IceTransport::GatheringDoneCallback;
  56. jconfig.cb_recv = IceTransport::RecvCallback;
  57. jconfig.user_ptr = this;
  58. // Randomize servers order
  59. std::vector<IceServer> servers = config.iceServers;
  60. unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  61. std::shuffle(servers.begin(), servers.end(), std::default_random_engine(seed));
  62. // Pick a STUN server (TURN support is not implemented in libjuice yet)
  63. for (auto &server : servers) {
  64. if (!server.hostname.empty() && server.type == IceServer::Type::Stun) {
  65. if (server.service.empty())
  66. server.service = "3478"; // STUN UDP port
  67. PLOG_DEBUG << "Using STUN server \"" << server.hostname << ":" << server.service
  68. << "\"";
  69. mStunHostname = server.hostname;
  70. mStunService = server.service;
  71. jconfig.stun_server_host = mStunHostname.c_str();
  72. jconfig.stun_server_port = std::stoul(mStunService);
  73. break;
  74. }
  75. }
  76. // Port range
  77. if (config.portRangeBegin > 1024 ||
  78. (config.portRangeEnd != 0 && config.portRangeEnd != 65535)) {
  79. jconfig.local_port_range_begin = config.portRangeBegin;
  80. jconfig.local_port_range_end = config.portRangeEnd;
  81. }
  82. // Create agent
  83. mAgent = decltype(mAgent)(juice_create(&jconfig), juice_destroy);
  84. if (!mAgent)
  85. throw std::runtime_error("Failed to create the ICE agent");
  86. }
  87. IceTransport::~IceTransport() {
  88. stop();
  89. mAgent.reset();
  90. }
  91. bool IceTransport::stop() {
  92. return Transport::stop();
  93. }
  94. Description::Role IceTransport::role() const { return mRole; }
  95. Description IceTransport::getLocalDescription(Description::Type type) const {
  96. char sdp[JUICE_MAX_SDP_STRING_LEN];
  97. if (juice_get_local_description(mAgent.get(), sdp, JUICE_MAX_SDP_STRING_LEN) < 0)
  98. throw std::runtime_error("Failed to generate local SDP");
  99. return Description(string(sdp), type, mRole);
  100. }
  101. void IceTransport::setRemoteDescription(const Description &description) {
  102. mRole = description.role() == Description::Role::Active ? Description::Role::Passive
  103. : Description::Role::Active;
  104. mMid = description.dataMid();
  105. if (juice_set_remote_description(mAgent.get(), string(description).c_str()) < 0)
  106. throw std::runtime_error("Failed to parse remote SDP");
  107. }
  108. bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
  109. // Don't try to pass unresolved candidates for more safety
  110. if (!candidate.isResolved())
  111. return false;
  112. return juice_add_remote_candidate(mAgent.get(), string(candidate).c_str()) >= 0;
  113. }
  114. void IceTransport::gatherLocalCandidates() {
  115. // Change state now as candidates calls can be synchronous
  116. changeGatheringState(GatheringState::InProgress);
  117. if (juice_gather_candidates(mAgent.get()) < 0) {
  118. throw std::runtime_error("Failed to gather local ICE candidates");
  119. }
  120. }
  121. std::optional<string> IceTransport::getLocalAddress() const {
  122. char str[JUICE_MAX_ADDRESS_STRING_LEN];
  123. if (juice_get_selected_addresses(mAgent.get(), str, JUICE_MAX_ADDRESS_STRING_LEN, NULL, 0) ==
  124. 0) {
  125. return std::make_optional(string(str));
  126. }
  127. return nullopt;
  128. }
  129. std::optional<string> IceTransport::getRemoteAddress() const {
  130. char str[JUICE_MAX_ADDRESS_STRING_LEN];
  131. if (juice_get_selected_addresses(mAgent.get(), NULL, 0, str, JUICE_MAX_ADDRESS_STRING_LEN) ==
  132. 0) {
  133. return std::make_optional(string(str));
  134. }
  135. return nullopt;
  136. }
  137. bool IceTransport::send(message_ptr message) {
  138. auto s = state();
  139. if (!message || (s != State::Connected && s != State::Completed))
  140. return false;
  141. PLOG_VERBOSE << "Send size=" << message->size();
  142. return outgoing(message);
  143. }
  144. bool IceTransport::outgoing(message_ptr message) {
  145. return juice_send(mAgent.get(), reinterpret_cast<const char *>(message->data()),
  146. message->size()) >= 0;
  147. }
  148. void IceTransport::changeGatheringState(GatheringState state) {
  149. if (mGatheringState.exchange(state) != state)
  150. mGatheringStateChangeCallback(mGatheringState);
  151. }
  152. void IceTransport::processStateChange(unsigned int state) {
  153. switch (state) {
  154. case JUICE_STATE_DISCONNECTED:
  155. changeState(State::Disconnected);
  156. break;
  157. case JUICE_STATE_CONNECTING:
  158. changeState(State::Connecting);
  159. break;
  160. case JUICE_STATE_CONNECTED:
  161. changeState(State::Connected);
  162. break;
  163. case JUICE_STATE_COMPLETED:
  164. changeState(State::Completed);
  165. break;
  166. case JUICE_STATE_FAILED:
  167. changeState(State::Failed);
  168. break;
  169. };
  170. }
  171. void IceTransport::processCandidate(const string &candidate) {
  172. mCandidateCallback(Candidate(candidate, mMid));
  173. }
  174. void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); }
  175. void IceTransport::StateChangeCallback(juice_agent_t *agent, juice_state_t state, void *user_ptr) {
  176. auto iceTransport = static_cast<rtc::IceTransport *>(user_ptr);
  177. try {
  178. iceTransport->processStateChange(static_cast<unsigned int>(state));
  179. } catch (const std::exception &e) {
  180. PLOG_WARNING << e.what();
  181. }
  182. }
  183. void IceTransport::CandidateCallback(juice_agent_t *agent, const char *sdp, void *user_ptr) {
  184. auto iceTransport = static_cast<rtc::IceTransport *>(user_ptr);
  185. try {
  186. iceTransport->processCandidate(sdp);
  187. } catch (const std::exception &e) {
  188. PLOG_WARNING << e.what();
  189. }
  190. }
  191. void IceTransport::GatheringDoneCallback(juice_agent_t *agent, void *user_ptr) {
  192. auto iceTransport = static_cast<rtc::IceTransport *>(user_ptr);
  193. try {
  194. iceTransport->processGatheringDone();
  195. } catch (const std::exception &e) {
  196. PLOG_WARNING << e.what();
  197. }
  198. }
  199. void IceTransport::RecvCallback(juice_agent_t *agent, const char *data, size_t size,
  200. void *user_ptr) {
  201. auto iceTransport = static_cast<rtc::IceTransport *>(user_ptr);
  202. try {
  203. PLOG_VERBOSE << "Incoming size=" << size;
  204. auto b = reinterpret_cast<const byte *>(data);
  205. iceTransport->incoming(make_message(b, b + size));
  206. } catch (const std::exception &e) {
  207. PLOG_WARNING << e.what();
  208. }
  209. }
  210. void IceTransport::LogCallback(juice_log_level_t level, const char *message) {
  211. plog::Severity severity;
  212. switch (level) {
  213. case JUICE_LOG_LEVEL_FATAL:
  214. severity = plog::fatal;
  215. break;
  216. case JUICE_LOG_LEVEL_ERROR:
  217. severity = plog::error;
  218. break;
  219. case JUICE_LOG_LEVEL_WARN:
  220. severity = plog::warning;
  221. break;
  222. case JUICE_LOG_LEVEL_INFO:
  223. severity = plog::info;
  224. break;
  225. default:
  226. severity = plog::verbose; // libjuice debug as verbose
  227. break;
  228. }
  229. PLOG(severity) << "juice: " << message;
  230. }
  231. } // namespace rtc
  232. #else // USE_JUICE == 0
  233. namespace rtc {
  234. IceTransport::IceTransport(const Configuration &config, Description::Role role,
  235. candidate_callback candidateCallback, state_callback stateChangeCallback,
  236. gathering_state_callback gatheringStateChangeCallback)
  237. : Transport(nullptr, std::move(stateChangeCallback)), mRole(role), mMid("0"),
  238. mGatheringState(GatheringState::New), mCandidateCallback(std::move(candidateCallback)),
  239. mGatheringStateChangeCallback(std::move(gatheringStateChangeCallback)),
  240. mNiceAgent(nullptr, nullptr), mMainLoop(nullptr, nullptr) {
  241. PLOG_DEBUG << "Initializing ICE transport (libnice)";
  242. g_log_set_handler("libnice", G_LOG_LEVEL_MASK, LogCallback, this);
  243. IF_PLOG(plog::verbose) {
  244. nice_debug_enable(false); // do not output STUN debug messages
  245. }
  246. mMainLoop = decltype(mMainLoop)(g_main_loop_new(nullptr, FALSE), g_main_loop_unref);
  247. if (!mMainLoop)
  248. std::runtime_error("Failed to create the main loop");
  249. // RFC 5245 was obsoleted by RFC 8445 but this should be OK.
  250. mNiceAgent = decltype(mNiceAgent)(
  251. nice_agent_new(g_main_loop_get_context(mMainLoop.get()), NICE_COMPATIBILITY_RFC5245),
  252. g_object_unref);
  253. if (!mNiceAgent)
  254. throw std::runtime_error("Failed to create the nice agent");
  255. mMainLoopThread = std::thread(g_main_loop_run, mMainLoop.get());
  256. mStreamId = nice_agent_add_stream(mNiceAgent.get(), 1);
  257. if (!mStreamId)
  258. throw std::runtime_error("Failed to add a stream");
  259. g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", TRUE, nullptr); // decided later
  260. g_object_set(G_OBJECT(mNiceAgent.get()), "ice-udp", TRUE, nullptr);
  261. g_object_set(G_OBJECT(mNiceAgent.get()), "ice-tcp", config.enableIceTcp ? TRUE : FALSE,
  262. nullptr);
  263. // RFC 8445: Agents MUST NOT use an RTO value smaller than 500 ms.
  264. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-initial-timeout", 500, nullptr);
  265. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-max-retransmissions", 3, nullptr);
  266. // RFC 8445: ICE agents SHOULD use a default Ta value, 50 ms, but MAY use another value based on
  267. // the characteristics of the associated data.
  268. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-pacing-timer", 25, nullptr);
  269. g_object_set(G_OBJECT(mNiceAgent.get()), "upnp", FALSE, nullptr);
  270. g_object_set(G_OBJECT(mNiceAgent.get()), "upnp-timeout", 200, nullptr);
  271. // Proxy
  272. if (config.proxyServer.has_value()) {
  273. ProxyServer proxyServer = config.proxyServer.value();
  274. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-type", proxyServer.type, nullptr);
  275. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.ip.c_str(), nullptr);
  276. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-port", proxyServer.port, nullptr);
  277. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-username", proxyServer.username.c_str(),
  278. nullptr);
  279. g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-password", proxyServer.password.c_str(),
  280. nullptr);
  281. }
  282. // Randomize order
  283. std::vector<IceServer> servers = config.iceServers;
  284. unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  285. std::shuffle(servers.begin(), servers.end(), std::default_random_engine(seed));
  286. // Add one STUN server
  287. bool success = false;
  288. for (auto &server : servers) {
  289. if (server.hostname.empty())
  290. continue;
  291. if (server.type != IceServer::Type::Stun)
  292. continue;
  293. if (server.service.empty())
  294. server.service = "3478"; // STUN UDP port
  295. struct addrinfo hints = {};
  296. hints.ai_family = AF_INET; // IPv4
  297. hints.ai_socktype = SOCK_DGRAM;
  298. hints.ai_protocol = IPPROTO_UDP;
  299. hints.ai_flags = AI_ADDRCONFIG;
  300. struct addrinfo *result = nullptr;
  301. if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0)
  302. continue;
  303. for (auto p = result; p; p = p->ai_next) {
  304. if (p->ai_family == AF_INET) {
  305. char nodebuffer[MAX_NUMERICNODE_LEN];
  306. char servbuffer[MAX_NUMERICSERV_LEN];
  307. if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
  308. servbuffer, MAX_NUMERICNODE_LEN,
  309. NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
  310. PLOG_DEBUG << "Using STUN server \"" << server.hostname << ":" << server.service
  311. << "\"";
  312. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr);
  313. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port",
  314. std::stoul(servbuffer), nullptr);
  315. success = true;
  316. break;
  317. }
  318. }
  319. }
  320. freeaddrinfo(result);
  321. if (success)
  322. break;
  323. }
  324. // Add TURN servers
  325. for (auto &server : servers) {
  326. if (server.hostname.empty())
  327. continue;
  328. if (server.type != IceServer::Type::Turn)
  329. continue;
  330. if (server.service.empty())
  331. server.service = server.relayType == IceServer::RelayType::TurnTls ? "5349" : "3478";
  332. struct addrinfo hints = {};
  333. hints.ai_family = AF_UNSPEC;
  334. hints.ai_socktype =
  335. server.relayType == IceServer::RelayType::TurnUdp ? SOCK_DGRAM : SOCK_STREAM;
  336. hints.ai_protocol =
  337. server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP;
  338. hints.ai_flags = AI_ADDRCONFIG;
  339. struct addrinfo *result = nullptr;
  340. if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0)
  341. continue;
  342. for (auto p = result; p; p = p->ai_next) {
  343. if (p->ai_family == AF_INET || p->ai_family == AF_INET6) {
  344. char nodebuffer[MAX_NUMERICNODE_LEN];
  345. char servbuffer[MAX_NUMERICSERV_LEN];
  346. if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
  347. servbuffer, MAX_NUMERICNODE_LEN,
  348. NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
  349. NiceRelayType niceRelayType;
  350. switch (server.relayType) {
  351. case IceServer::RelayType::TurnTcp:
  352. niceRelayType = NICE_RELAY_TYPE_TURN_TCP;
  353. break;
  354. case IceServer::RelayType::TurnTls:
  355. niceRelayType = NICE_RELAY_TYPE_TURN_TLS;
  356. break;
  357. default:
  358. niceRelayType = NICE_RELAY_TYPE_TURN_UDP;
  359. break;
  360. }
  361. nice_agent_set_relay_info(mNiceAgent.get(), mStreamId, 1, nodebuffer,
  362. std::stoul(servbuffer), server.username.c_str(),
  363. server.password.c_str(), niceRelayType);
  364. }
  365. }
  366. }
  367. freeaddrinfo(result);
  368. }
  369. g_signal_connect(G_OBJECT(mNiceAgent.get()), "component-state-changed",
  370. G_CALLBACK(StateChangeCallback), this);
  371. g_signal_connect(G_OBJECT(mNiceAgent.get()), "new-candidate-full",
  372. G_CALLBACK(CandidateCallback), this);
  373. g_signal_connect(G_OBJECT(mNiceAgent.get()), "candidate-gathering-done",
  374. G_CALLBACK(GatheringDoneCallback), this);
  375. nice_agent_set_stream_name(mNiceAgent.get(), mStreamId, "application");
  376. nice_agent_set_port_range(mNiceAgent.get(), mStreamId, 1, config.portRangeBegin,
  377. config.portRangeEnd);
  378. nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(mMainLoop.get()),
  379. RecvCallback, this);
  380. }
  381. IceTransport::~IceTransport() { stop(); }
  382. bool IceTransport::stop() {
  383. if (mTimeoutId) {
  384. g_source_remove(mTimeoutId);
  385. mTimeoutId = 0;
  386. }
  387. if (!Transport::stop())
  388. return false;
  389. PLOG_DEBUG << "Stopping ICE thread";
  390. nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(mMainLoop.get()),
  391. NULL, NULL);
  392. nice_agent_remove_stream(mNiceAgent.get(), mStreamId);
  393. g_main_loop_quit(mMainLoop.get());
  394. mMainLoopThread.join();
  395. return true;
  396. }
  397. Description::Role IceTransport::role() const { return mRole; }
  398. Description IceTransport::getLocalDescription(Description::Type type) const {
  399. // RFC 8445: The initiating agent that started the ICE processing MUST take the controlling
  400. // role, and the other MUST take the controlled role.
  401. g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode",
  402. type == Description::Type::Offer ? TRUE : FALSE, nullptr);
  403. std::unique_ptr<gchar[], void (*)(void *)> sdp(nice_agent_generate_local_sdp(mNiceAgent.get()),
  404. g_free);
  405. return Description(string(sdp.get()), type, mRole);
  406. }
  407. void IceTransport::setRemoteDescription(const Description &description) {
  408. mRole = description.role() == Description::Role::Active ? Description::Role::Passive
  409. : Description::Role::Active;
  410. mMid = description.dataMid();
  411. mTrickleTimeout = !description.ended() ? 30s : 0s;
  412. // Warning: libnice expects "\n" as end of line
  413. if (nice_agent_parse_remote_sdp(mNiceAgent.get(), description.generateSdp("\n").c_str()) < 0)
  414. throw std::runtime_error("Failed to parse remote SDP");
  415. }
  416. bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
  417. // Don't try to pass unresolved candidates to libnice for more safety
  418. if (!candidate.isResolved())
  419. return false;
  420. // Warning: the candidate string must start with "a=candidate:" and it must not end with a
  421. // newline, else libnice will reject it.
  422. string sdp(candidate);
  423. NiceCandidate *cand =
  424. nice_agent_parse_remote_candidate_sdp(mNiceAgent.get(), mStreamId, sdp.c_str());
  425. if (!cand)
  426. return false;
  427. GSList *list = g_slist_append(nullptr, cand);
  428. int ret = nice_agent_set_remote_candidates(mNiceAgent.get(), mStreamId, 1, list);
  429. g_slist_free_full(list, reinterpret_cast<GDestroyNotify>(nice_candidate_free));
  430. return ret > 0;
  431. }
  432. void IceTransport::gatherLocalCandidates() {
  433. // Change state now as candidates calls can be synchronous
  434. changeGatheringState(GatheringState::InProgress);
  435. if (!nice_agent_gather_candidates(mNiceAgent.get(), mStreamId)) {
  436. throw std::runtime_error("Failed to gather local ICE candidates");
  437. }
  438. }
  439. std::optional<string> IceTransport::getLocalAddress() const {
  440. NiceCandidate *local = nullptr;
  441. NiceCandidate *remote = nullptr;
  442. if (nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote)) {
  443. return std::make_optional(AddressToString(local->addr));
  444. }
  445. return nullopt;
  446. }
  447. std::optional<string> IceTransport::getRemoteAddress() const {
  448. NiceCandidate *local = nullptr;
  449. NiceCandidate *remote = nullptr;
  450. if (nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote)) {
  451. return std::make_optional(AddressToString(remote->addr));
  452. }
  453. return nullopt;
  454. }
  455. bool IceTransport::send(message_ptr message) {
  456. auto s = state();
  457. if (!message || (s != State::Connected && s != State::Completed))
  458. return false;
  459. PLOG_VERBOSE << "Send size=" << message->size();
  460. return outgoing(message);
  461. }
  462. bool IceTransport::outgoing(message_ptr message) {
  463. return nice_agent_send(mNiceAgent.get(), mStreamId, 1, message->size(),
  464. reinterpret_cast<const char *>(message->data())) >= 0;
  465. }
  466. void IceTransport::changeGatheringState(GatheringState state) {
  467. if (mGatheringState.exchange(state) != state)
  468. mGatheringStateChangeCallback(mGatheringState);
  469. }
  470. void IceTransport::processTimeout() {
  471. PLOG_WARNING << "ICE timeout";
  472. mTimeoutId = 0;
  473. changeState(State::Failed);
  474. }
  475. void IceTransport::processCandidate(const string &candidate) {
  476. mCandidateCallback(Candidate(candidate, mMid));
  477. }
  478. void IceTransport::processGatheringDone() { changeGatheringState(GatheringState::Complete); }
  479. void IceTransport::processStateChange(unsigned int state) {
  480. if (state == NICE_COMPONENT_STATE_FAILED && mTrickleTimeout.count() > 0) {
  481. if (mTimeoutId)
  482. g_source_remove(mTimeoutId);
  483. mTimeoutId = g_timeout_add(mTrickleTimeout.count() /* ms */, TimeoutCallback, this);
  484. return;
  485. }
  486. if (state == NICE_COMPONENT_STATE_CONNECTED && mTimeoutId) {
  487. g_source_remove(mTimeoutId);
  488. mTimeoutId = 0;
  489. }
  490. switch (state) {
  491. case NICE_COMPONENT_STATE_DISCONNECTED:
  492. changeState(State::Disconnected);
  493. break;
  494. case NICE_COMPONENT_STATE_CONNECTING:
  495. changeState(State::Connecting);
  496. break;
  497. case NICE_COMPONENT_STATE_CONNECTED:
  498. changeState(State::Connected);
  499. break;
  500. case NICE_COMPONENT_STATE_READY:
  501. changeState(State::Completed);
  502. break;
  503. case NICE_COMPONENT_STATE_FAILED:
  504. changeState(State::Failed);
  505. break;
  506. };
  507. }
  508. string IceTransport::AddressToString(const NiceAddress &addr) {
  509. char buffer[NICE_ADDRESS_STRING_LEN];
  510. nice_address_to_string(&addr, buffer);
  511. unsigned int port = nice_address_get_port(&addr);
  512. std::ostringstream ss;
  513. ss << buffer << ":" << port;
  514. return ss.str();
  515. }
  516. void IceTransport::CandidateCallback(NiceAgent *agent, NiceCandidate *candidate,
  517. gpointer userData) {
  518. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  519. gchar *cand = nice_agent_generate_local_candidate_sdp(agent, candidate);
  520. try {
  521. iceTransport->processCandidate(cand);
  522. } catch (const std::exception &e) {
  523. PLOG_WARNING << e.what();
  524. }
  525. g_free(cand);
  526. }
  527. void IceTransport::GatheringDoneCallback(NiceAgent *agent, guint streamId, gpointer userData) {
  528. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  529. try {
  530. iceTransport->processGatheringDone();
  531. } catch (const std::exception &e) {
  532. PLOG_WARNING << e.what();
  533. }
  534. }
  535. void IceTransport::StateChangeCallback(NiceAgent *agent, guint streamId, guint componentId,
  536. guint state, gpointer userData) {
  537. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  538. try {
  539. iceTransport->processStateChange(state);
  540. } catch (const std::exception &e) {
  541. PLOG_WARNING << e.what();
  542. }
  543. }
  544. void IceTransport::RecvCallback(NiceAgent *agent, guint streamId, guint componentId, guint len,
  545. gchar *buf, gpointer userData) {
  546. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  547. try {
  548. PLOG_VERBOSE << "Incoming size=" << len;
  549. auto b = reinterpret_cast<byte *>(buf);
  550. iceTransport->incoming(make_message(b, b + len));
  551. } catch (const std::exception &e) {
  552. PLOG_WARNING << e.what();
  553. }
  554. }
  555. gboolean IceTransport::TimeoutCallback(gpointer userData) {
  556. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  557. try {
  558. iceTransport->processTimeout();
  559. } catch (const std::exception &e) {
  560. PLOG_WARNING << e.what();
  561. }
  562. return FALSE;
  563. }
  564. void IceTransport::LogCallback(const gchar *logDomain, GLogLevelFlags logLevel,
  565. const gchar *message, gpointer userData) {
  566. plog::Severity severity;
  567. unsigned int flags = logLevel & G_LOG_LEVEL_MASK;
  568. if (flags & G_LOG_LEVEL_ERROR)
  569. severity = plog::fatal;
  570. else if (flags & G_LOG_LEVEL_CRITICAL)
  571. severity = plog::error;
  572. else if (flags & G_LOG_LEVEL_WARNING)
  573. severity = plog::warning;
  574. else if (flags & G_LOG_LEVEL_MESSAGE)
  575. severity = plog::info;
  576. else if (flags & G_LOG_LEVEL_INFO)
  577. severity = plog::info;
  578. else
  579. severity = plog::verbose; // libnice debug as verbose
  580. PLOG(severity) << "nice: " << message;
  581. }
  582. bool IceTransport::getSelectedCandidatePair(CandidateInfo *localInfo, CandidateInfo *remoteInfo) {
  583. NiceCandidate *local, *remote;
  584. gboolean result = nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote);
  585. if (!result)
  586. return false;
  587. char ipaddr[INET6_ADDRSTRLEN];
  588. nice_address_to_string(&local->addr, ipaddr);
  589. localInfo->address = std::string(ipaddr);
  590. localInfo->port = nice_address_get_port(&local->addr);
  591. localInfo->type = IceTransport::NiceTypeToCandidateType(local->type);
  592. localInfo->transportType =
  593. IceTransport::NiceTransportTypeToCandidateTransportType(local->transport);
  594. nice_address_to_string(&remote->addr, ipaddr);
  595. remoteInfo->address = std::string(ipaddr);
  596. remoteInfo->port = nice_address_get_port(&remote->addr);
  597. remoteInfo->type = IceTransport::NiceTypeToCandidateType(remote->type);
  598. remoteInfo->transportType =
  599. IceTransport::NiceTransportTypeToCandidateTransportType(remote->transport);
  600. return true;
  601. }
  602. const CandidateType IceTransport::NiceTypeToCandidateType(NiceCandidateType type) {
  603. switch (type) {
  604. case NiceCandidateType::NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
  605. return CandidateType::PeerReflexive;
  606. case NiceCandidateType::NICE_CANDIDATE_TYPE_RELAYED:
  607. return CandidateType::Relayed;
  608. case NiceCandidateType::NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
  609. return CandidateType::ServerReflexive;
  610. default:
  611. return CandidateType::Host;
  612. }
  613. }
  614. const CandidateTransportType
  615. IceTransport::NiceTransportTypeToCandidateTransportType(NiceCandidateTransport type) {
  616. switch (type) {
  617. case NiceCandidateTransport::NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
  618. return CandidateTransportType::TcpActive;
  619. case NiceCandidateTransport::NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
  620. return CandidateTransportType::TcpPassive;
  621. case NiceCandidateTransport::NICE_CANDIDATE_TRANSPORT_TCP_SO:
  622. return CandidateTransportType::TcpSo;
  623. default:
  624. return CandidateTransportType::Udp;
  625. }
  626. }
  627. } // namespace rtc
  628. #endif