icetransport.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /**
  2. * Copyright (c) 2019 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 <netdb.h>
  20. #include <netinet/in.h>
  21. #include <sys/socket.h>
  22. #include <sys/types.h>
  23. #include <chrono>
  24. #include <iostream>
  25. #include <random>
  26. #include <sstream>
  27. namespace rtc {
  28. using std::shared_ptr;
  29. using std::weak_ptr;
  30. IceTransport::IceTransport(const IceConfiguration &config, Description::Role role,
  31. candidate_callback candidateCallback, ready_callback ready)
  32. : mRole(role), mCandidateCallback(std::move(candidateCallback)), mReadyCallback(ready),
  33. mNiceAgent(nullptr, nullptr), mMainLoop(nullptr, nullptr) {
  34. auto logLevelFlags = GLogLevelFlags(G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION);
  35. g_log_set_handler(nullptr, logLevelFlags, LogCallback, this);
  36. nice_debug_disable(true);
  37. mMainLoop = decltype(mMainLoop)(g_main_loop_new(nullptr, FALSE), g_main_loop_unref);
  38. if (!mMainLoop)
  39. std::runtime_error("Failed to create the main loop");
  40. mNiceAgent = decltype(mNiceAgent)(
  41. nice_agent_new(g_main_loop_get_context(mMainLoop.get()), NICE_COMPATIBILITY_RFC5245),
  42. g_object_unref);
  43. if (!mNiceAgent)
  44. throw std::runtime_error("Failed to create the nice agent");
  45. mMainLoopThread = std::thread(g_main_loop_run, mMainLoop.get());
  46. g_object_set(G_OBJECT(mNiceAgent.get()), "upnp", FALSE, nullptr);
  47. g_object_set(G_OBJECT(mNiceAgent.get()), "controlling-mode", FALSE, nullptr);
  48. g_object_set(G_OBJECT(mNiceAgent.get()), "ice-udp", TRUE, nullptr);
  49. g_object_set(G_OBJECT(mNiceAgent.get()), "ice-tcp", FALSE, nullptr);
  50. std::vector<IceServer> servers = config.servers;
  51. unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  52. std::shuffle(servers.begin(), servers.end(), std::default_random_engine(seed));
  53. bool success = false;
  54. for (const auto &server : servers) {
  55. struct addrinfo hints = {};
  56. hints.ai_family = AF_INET; // IPv4
  57. hints.ai_socktype = SOCK_DGRAM;
  58. hints.ai_protocol = IPPROTO_UDP;
  59. hints.ai_flags = AI_ADDRCONFIG;
  60. struct addrinfo *result = nullptr;
  61. if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0)
  62. continue;
  63. for (auto p = result; p; p = p->ai_next) {
  64. if(p->ai_family == AF_INET) {
  65. char nodebuffer[MAX_NUMERICNODE_LEN];
  66. char servbuffer[MAX_NUMERICSERV_LEN];
  67. if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
  68. servbuffer, MAX_NUMERICNODE_LEN,
  69. NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
  70. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr);
  71. g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port",
  72. std::atoi(servbuffer), nullptr);
  73. success = true;
  74. break;
  75. }
  76. }
  77. }
  78. freeaddrinfo(result);
  79. if (success)
  80. break;
  81. }
  82. g_signal_connect(G_OBJECT(mNiceAgent.get()), "component-state-changed",
  83. G_CALLBACK(StateChangedCallback), this);
  84. g_signal_connect(G_OBJECT(mNiceAgent.get()), "new-candidate-full",
  85. G_CALLBACK(CandidateCallback), this);
  86. g_signal_connect(G_OBJECT(mNiceAgent.get()), "candidate-gathering-done",
  87. G_CALLBACK(GatheringDoneCallback), this);
  88. mStreamId = nice_agent_add_stream(mNiceAgent.get(), 1);
  89. if (mStreamId == 0)
  90. throw std::runtime_error("Failed to add a stream");
  91. nice_agent_set_stream_name(mNiceAgent.get(), mStreamId, "application");
  92. nice_agent_set_port_range(mNiceAgent.get(), mStreamId, 1,
  93. config.portRangeBegin, config.portRangeEnd);
  94. nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(mMainLoop.get()),
  95. RecvCallback, this);
  96. }
  97. IceTransport::~IceTransport() {
  98. g_main_loop_quit(mMainLoop.get());
  99. if (mMainLoopThread.joinable())
  100. mMainLoopThread.join();
  101. }
  102. Description::Role IceTransport::role() const { return mRole; }
  103. IceTransport::State IceTransport::state() const { return mState; }
  104. Description IceTransport::getLocalDescription() const {
  105. std::unique_ptr<gchar[], void (*)(void *)> sdp(nice_agent_generate_local_sdp(mNiceAgent.get()),
  106. g_free);
  107. return Description(string(sdp.get()));
  108. }
  109. void IceTransport::setRemoteDescription(const Description &description) {
  110. if (nice_agent_parse_remote_sdp(mNiceAgent.get(), string(description).c_str()))
  111. throw std::runtime_error("Unable to parse remote SDP");
  112. }
  113. void IceTransport::gatherLocalCandidates() {
  114. if (!nice_agent_gather_candidates(mNiceAgent.get(), mStreamId))
  115. throw std::runtime_error("Unable to gather local ICE candidates");
  116. }
  117. bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
  118. NiceCandidate *cand = nice_agent_parse_remote_candidate_sdp(mNiceAgent.get(), mStreamId,
  119. string(candidate).c_str());
  120. if (!cand)
  121. return false;
  122. GSList *list = g_slist_append(nullptr, cand);
  123. int ret = nice_agent_set_remote_candidates(mNiceAgent.get(), mStreamId, 1, list);
  124. g_slist_free_full(list, reinterpret_cast<GDestroyNotify>(nice_candidate_free));
  125. return ret > 0;
  126. }
  127. bool IceTransport::send(message_ptr message) {
  128. if (!mStreamId)
  129. return false;
  130. outgoing(message);
  131. return true;
  132. }
  133. void IceTransport::incoming(message_ptr message) { recv(message); }
  134. void IceTransport::incoming(const byte *data, int size) {
  135. incoming(make_message(data, data + size));
  136. }
  137. void IceTransport::outgoing(message_ptr message) {
  138. nice_agent_send(mNiceAgent.get(), mStreamId, 1, message->size(),
  139. reinterpret_cast<const char *>(message->data()));
  140. }
  141. void IceTransport::processCandidate(const string &candidate) {
  142. mCandidateCallback(Candidate(candidate, getStreamName()));
  143. }
  144. void IceTransport::processGatheringDone() { mCandidateCallback(nullopt); }
  145. void IceTransport::changeState(uint32_t state) {
  146. mState = static_cast<State>(state);
  147. if (mState == State::CONNECTED)
  148. mReadyCallback();
  149. }
  150. string IceTransport::getStreamName() const {
  151. const gchar *stream = nice_agent_get_stream_name(mNiceAgent.get(), mStreamId);
  152. return string(stream);
  153. }
  154. void IceTransport::CandidateCallback(NiceAgent *agent, NiceCandidate *candidate,
  155. gpointer userData) {
  156. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  157. gchar *cand = nice_agent_generate_local_candidate_sdp(agent, candidate);
  158. iceTransport->processCandidate(cand);
  159. g_free(cand);
  160. }
  161. void IceTransport::GatheringDoneCallback(NiceAgent *agent, guint streamId, gpointer userData) {
  162. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  163. iceTransport->processGatheringDone();
  164. }
  165. void IceTransport::StateChangedCallback(NiceAgent *agent, guint streamId, guint componentId,
  166. guint state, gpointer userData) {
  167. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  168. iceTransport->changeState(state);
  169. }
  170. void IceTransport::RecvCallback(NiceAgent *agent, guint streamId, guint componentId, guint len,
  171. gchar *buf, gpointer userData) {
  172. auto iceTransport = static_cast<rtc::IceTransport *>(userData);
  173. iceTransport->incoming(reinterpret_cast<std::byte *>(buf), len);
  174. }
  175. void IceTransport::LogCallback(const gchar *logDomain, GLogLevelFlags logLevel, const gchar *message,
  176. gpointer userData) {
  177. std::cout << message << std::endl;
  178. }
  179. } // namespace rtc