configuration.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /**
  2. * Copyright (c) 2019 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 "configuration.hpp"
  9. #include "impl/utils.hpp"
  10. #include <cassert>
  11. #include <regex>
  12. namespace {
  13. bool parse_url(const std::string &url, std::vector<std::optional<std::string>> &result) {
  14. // Modified regex from RFC 3986, see https://www.rfc-editor.org/rfc/rfc3986.html#appendix-B
  15. static const char *rs =
  16. R"(^(([^:.@/?#]+):)?(/{0,2}((([^:@]*)(:([^@]*))?)@)?(([^:/?#]*)(:([^/?#]*))?))?([^?#]*)(\?([^#]*))?(#(.*))?)";
  17. static const std::regex r(rs, std::regex::extended);
  18. std::smatch m;
  19. if (!std::regex_match(url, m, r) || m[10].length() == 0)
  20. return false;
  21. result.resize(m.size());
  22. std::transform(m.begin(), m.end(), result.begin(), [](const auto &sm) {
  23. return sm.length() > 0 ? std::make_optional(std::string(sm)) : std::nullopt;
  24. });
  25. assert(result.size() == 18);
  26. return true;
  27. }
  28. } // namespace
  29. namespace rtc {
  30. namespace utils = impl::utils;
  31. IceServer::IceServer(const string &url) {
  32. std::vector<optional<string>> opt;
  33. if (!parse_url(url, opt))
  34. throw std::invalid_argument("Invalid ICE server URL: " + url);
  35. string scheme = opt[2].value_or("stun");
  36. relayType = RelayType::TurnUdp;
  37. if (scheme == "stun" || scheme == "STUN")
  38. type = Type::Stun;
  39. else if (scheme == "turn" || scheme == "TURN")
  40. type = Type::Turn;
  41. else if (scheme == "turns" || scheme == "TURNS") {
  42. type = Type::Turn;
  43. relayType = RelayType::TurnTls;
  44. } else
  45. throw std::invalid_argument("Unknown ICE server protocol: " + scheme);
  46. if (auto &query = opt[15]) {
  47. if (query->find("transport=udp") != string::npos)
  48. relayType = RelayType::TurnUdp;
  49. if (query->find("transport=tcp") != string::npos)
  50. relayType = RelayType::TurnTcp;
  51. if (query->find("transport=tls") != string::npos)
  52. relayType = RelayType::TurnTls;
  53. }
  54. username = utils::url_decode(opt[6].value_or(""));
  55. password = utils::url_decode(opt[8].value_or(""));
  56. hostname = opt[10].value();
  57. if (hostname.front() == '[' && hostname.back() == ']') {
  58. // IPv6 literal
  59. hostname.erase(hostname.begin());
  60. hostname.pop_back();
  61. } else {
  62. hostname = utils::url_decode(hostname);
  63. }
  64. string service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478");
  65. try {
  66. port = uint16_t(std::stoul(service));
  67. } catch (...) {
  68. throw std::invalid_argument("Invalid ICE server port in URL: " + service);
  69. }
  70. }
  71. IceServer::IceServer(string hostname_, uint16_t port_)
  72. : hostname(std::move(hostname_)), port(port_), type(Type::Stun) {}
  73. IceServer::IceServer(string hostname_, string service_)
  74. : hostname(std::move(hostname_)), type(Type::Stun) {
  75. try {
  76. port = uint16_t(std::stoul(service_));
  77. } catch (...) {
  78. throw std::invalid_argument("Invalid ICE server port: " + service_);
  79. }
  80. }
  81. IceServer::IceServer(string hostname_, uint16_t port_, string username_, string password_,
  82. RelayType relayType_)
  83. : hostname(std::move(hostname_)), port(port_), type(Type::Turn), username(std::move(username_)),
  84. password(std::move(password_)), relayType(relayType_) {}
  85. IceServer::IceServer(string hostname_, string service_, string username_, string password_,
  86. RelayType relayType_)
  87. : hostname(std::move(hostname_)), type(Type::Turn), username(std::move(username_)),
  88. password(std::move(password_)), relayType(relayType_) {
  89. try {
  90. port = uint16_t(std::stoul(service_));
  91. } catch (...) {
  92. throw std::invalid_argument("Invalid ICE server port: " + service_);
  93. }
  94. }
  95. ProxyServer::ProxyServer(const string &url) {
  96. std::vector<optional<string>> opt;
  97. if (!parse_url(url, opt))
  98. throw std::invalid_argument("Invalid proxy server URL: " + url);
  99. string scheme = opt[2].value_or("http");
  100. if (scheme == "http" || scheme == "HTTP")
  101. type = Type::Http;
  102. else if (scheme == "socks5" || scheme == "SOCKS5")
  103. type = Type::Socks5;
  104. else
  105. throw std::invalid_argument("Unknown proxy server protocol: " + scheme);
  106. username = opt[6];
  107. password = opt[8];
  108. hostname = opt[10].value();
  109. while (!hostname.empty() && hostname.front() == '[')
  110. hostname.erase(hostname.begin());
  111. while (!hostname.empty() && hostname.back() == ']')
  112. hostname.pop_back();
  113. string service = opt[12].value_or(type == Type::Socks5 ? "1080" : "3128");
  114. try {
  115. port = uint16_t(std::stoul(service));
  116. } catch (...) {
  117. throw std::invalid_argument("Invalid proxy server port in URL: " + service);
  118. }
  119. }
  120. ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_)
  121. : type(type_), hostname(std::move(hostname_)), port(port_) {}
  122. ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_, string username_,
  123. string password_)
  124. : type(type_), hostname(std::move(hostname_)), port(port_), username(std::move(username_)),
  125. password(std::move(password_)) {}
  126. } // namespace rtc