#include "configuration.hpp"
#include "impl/utils.hpp"
#include <cassert>
#include <regex>
namespace {
bool parse_url(const std::string &url, std::vector<std::optional<std::string>> &result) {
static const char *rs =
R"(^(([^:.@/?#]+):)?(/{0,2}((([^:@]*)(:([^@]*))?)@)?(([^:/?#]*)(:([^/?#]*))?))?([^?#]*)(\?([^#]*))?(#(.*))?)";
static const std::regex r(rs, std::regex::extended);
std::smatch m;
if (!std::regex_match(url, m, r) || m[10].length() == 0)
return false;
result.resize(m.size());
std::transform(m.begin(), m.end(), result.begin(), [](const auto &sm) {
return sm.length() > 0 ? std::make_optional(std::string(sm)) : std::nullopt;
});
assert(result.size() == 18);
return true;
}
}
namespace rtc {
namespace utils = impl::utils;
IceServer::IceServer(const string &url) {
std::vector<optional<string>> opt;
if (!parse_url(url, opt))
throw std::invalid_argument("Invalid ICE server URL: " + url);
string scheme = opt[2].value_or("stun");
relayType = RelayType::TurnUdp;
if (scheme == "stun" || scheme == "STUN")
type = Type::Stun;
else if (scheme == "turn" || scheme == "TURN")
type = Type::Turn;
else if (scheme == "turns" || scheme == "TURNS") {
type = Type::Turn;
relayType = RelayType::TurnTls;
} else
throw std::invalid_argument("Unknown ICE server protocol: " + scheme);
if (auto &query = opt[15]) {
if (query->find("transport=udp") != string::npos)
relayType = RelayType::TurnUdp;
if (query->find("transport=tcp") != string::npos)
relayType = RelayType::TurnTcp;
if (query->find("transport=tls") != string::npos)
relayType = RelayType::TurnTls;
}
username = utils::url_decode(opt[6].value_or(""));
password = utils::url_decode(opt[8].value_or(""));
hostname = opt[10].value();
if (hostname.front() == '[' && hostname.back() == ']') {
hostname.erase(hostname.begin());
hostname.pop_back();
} else {
hostname = utils::url_decode(hostname);
}
string service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478");
try {
port = uint16_t(std::stoul(service));
} catch (...) {
throw std::invalid_argument("Invalid ICE server port in URL: " + service);
}
}
IceServer::IceServer(string hostname_, uint16_t port_)
: hostname(std::move(hostname_)), port(port_), type(Type::Stun) {}
IceServer::IceServer(string hostname_, string service_)
: hostname(std::move(hostname_)), type(Type::Stun) {
try {
port = uint16_t(std::stoul(service_));
} catch (...) {
throw std::invalid_argument("Invalid ICE server port: " + service_);
}
}
IceServer::IceServer(string hostname_, uint16_t port_, string username_, string password_,
RelayType relayType_)
: hostname(std::move(hostname_)), port(port_), type(Type::Turn), username(std::move(username_)),
password(std::move(password_)), relayType(relayType_) {}
IceServer::IceServer(string hostname_, string service_, string username_, string password_,
RelayType relayType_)
: hostname(std::move(hostname_)), type(Type::Turn), username(std::move(username_)),
password(std::move(password_)), relayType(relayType_) {
try {
port = uint16_t(std::stoul(service_));
} catch (...) {
throw std::invalid_argument("Invalid ICE server port: " + service_);
}
}
ProxyServer::ProxyServer(const string &url) {
std::vector<optional<string>> opt;
if (!parse_url(url, opt))
throw std::invalid_argument("Invalid proxy server URL: " + url);
string scheme = opt[2].value_or("http");
if (scheme == "http" || scheme == "HTTP")
type = Type::Http;
else if (scheme == "socks5" || scheme == "SOCKS5")
type = Type::Socks5;
else
throw std::invalid_argument("Unknown proxy server protocol: " + scheme);
username = opt[6];
password = opt[8];
hostname = opt[10].value();
while (!hostname.empty() && hostname.front() == '[')
hostname.erase(hostname.begin());
while (!hostname.empty() && hostname.back() == ']')
hostname.pop_back();
string service = opt[12].value_or(type == Type::Socks5 ? "1080" : "3128");
try {
port = uint16_t(std::stoul(service));
} catch (...) {
throw std::invalid_argument("Invalid proxy server port in URL: " + service);
}
}
ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_)
: type(type_), hostname(std::move(hostname_)), port(port_) {}
ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_, string username_,
string password_)
: type(type_), hostname(std::move(hostname_)), port(port_), username(std::move(username_)),
password(std::move(password_)) {}
}