|
@@ -21,6 +21,7 @@
|
|
|
#include <algorithm>
|
|
|
#include <array>
|
|
|
#include <sstream>
|
|
|
+#include <unordered_map>
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
#include <winsock2.h>
|
|
@@ -47,20 +48,40 @@ inline bool hasprefix(const string &str, const string &prefix) {
|
|
|
|
|
|
namespace rtc {
|
|
|
|
|
|
-Candidate::Candidate(string candidate, string mid) : mIsResolved(false) {
|
|
|
- const std::array prefixes{"a=", "candidate:"};
|
|
|
- for (const string &prefix : prefixes)
|
|
|
- if (hasprefix(candidate, prefix))
|
|
|
- candidate.erase(0, prefix.size());
|
|
|
+Candidate::Candidate(string candidate, string mid)
|
|
|
+ : mFamily(Family::Unresolved), mType(Type::Unknown), mTransportType(TransportType::Unknown),
|
|
|
+ mPort(0), mPriority(0) {
|
|
|
+
|
|
|
+ if (!candidate.empty()) {
|
|
|
+ const std::array prefixes{"a=", "candidate:"};
|
|
|
+ for (const string &prefix : prefixes)
|
|
|
+ if (hasprefix(candidate, prefix))
|
|
|
+ candidate.erase(0, prefix.size());
|
|
|
+ }
|
|
|
|
|
|
mCandidate = std::move(candidate);
|
|
|
mMid = std::move(mid);
|
|
|
}
|
|
|
|
|
|
bool Candidate::resolve(ResolveMode mode) {
|
|
|
- if (mIsResolved)
|
|
|
+ using TypeMap_t = std::unordered_map<string, Type>;
|
|
|
+ using TcpTypeMap_t = std::unordered_map<string, TransportType>;
|
|
|
+
|
|
|
+ static const TypeMap_t TypeMap = {{"host", Type::Host},
|
|
|
+ {"srflx", Type::ServerReflexive},
|
|
|
+ {"prflx", Type::PeerReflexive},
|
|
|
+ {"relay", Type::Relayed}};
|
|
|
+
|
|
|
+ static const TcpTypeMap_t TcpTypeMap = {{"active", TransportType::TcpActive},
|
|
|
+ {"passive", TransportType::TcpPassive},
|
|
|
+ {"so", TransportType::TcpSo}};
|
|
|
+
|
|
|
+ if (mFamily != Family::Unresolved)
|
|
|
return true;
|
|
|
|
|
|
+ if(mCandidate.empty())
|
|
|
+ throw std::logic_error("Candidate is empty");
|
|
|
+
|
|
|
PLOG_VERBOSE << "Resolving candidate (mode="
|
|
|
<< (mode == ResolveMode::Simple ? "simple" : "lookup")
|
|
|
<< "): " << mCandidate;
|
|
@@ -75,16 +96,39 @@ bool Candidate::resolve(ResolveMode mode) {
|
|
|
string left;
|
|
|
std::getline(iss, left);
|
|
|
|
|
|
+ if (auto it = TypeMap.find(type); it != TypeMap.end())
|
|
|
+ mType = it->second;
|
|
|
+ else
|
|
|
+ mType = Type::Unknown;
|
|
|
+
|
|
|
+ if (transport == "UDP" || transport == "udp") {
|
|
|
+ mTransportType = TransportType::Udp;
|
|
|
+ }
|
|
|
+ else if (transport == "TCP" || transport == "tcp") {
|
|
|
+ std::istringstream iss(left);
|
|
|
+ string tcptype_, tcptype;
|
|
|
+ if(iss >> tcptype_ >> tcptype && tcptype_ == "tcptype") {
|
|
|
+ if (auto it = TcpTypeMap.find(tcptype); it != TcpTypeMap.end())
|
|
|
+ mTransportType = it->second;
|
|
|
+ else
|
|
|
+ mTransportType = TransportType::TcpUnknown;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ mTransportType = TransportType::TcpUnknown;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mTransportType = TransportType::Unknown;
|
|
|
+ }
|
|
|
+
|
|
|
// Try to resolve the node
|
|
|
struct addrinfo hints = {};
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
hints.ai_flags = AI_ADDRCONFIG;
|
|
|
- if (transport == "UDP" || transport == "udp") {
|
|
|
+ if (mTransportType == TransportType::Udp) {
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
hints.ai_protocol = IPPROTO_UDP;
|
|
|
}
|
|
|
-
|
|
|
- if (transport == "TCP" || transport == "tcp") {
|
|
|
+ else if (mTransportType != TransportType::Unknown) {
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
}
|
|
@@ -102,13 +146,18 @@ bool Candidate::resolve(ResolveMode mode) {
|
|
|
if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer,
|
|
|
MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN,
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
|
|
|
+
|
|
|
+ mAddress = nodebuffer;
|
|
|
+ mPort = uint16_t(std::stoul(servbuffer));
|
|
|
+ mFamily = p->ai_family == AF_INET6 ? Family::Ipv6 : Family::Ipv4;
|
|
|
+
|
|
|
const char sp{' '};
|
|
|
std::ostringstream oss;
|
|
|
oss << foundation << sp << component << sp << transport << sp << priority;
|
|
|
oss << sp << nodebuffer << sp << servbuffer << sp << "typ" << sp << type;
|
|
|
oss << left;
|
|
|
mCandidate = oss.str();
|
|
|
- mIsResolved = true;
|
|
|
+
|
|
|
PLOG_VERBOSE << "Resolved candidate: " << mCandidate;
|
|
|
break;
|
|
|
}
|
|
@@ -119,11 +168,9 @@ bool Candidate::resolve(ResolveMode mode) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return mIsResolved;
|
|
|
+ return mFamily != Family::Unresolved;
|
|
|
}
|
|
|
|
|
|
-bool Candidate::isResolved() const { return mIsResolved; }
|
|
|
-
|
|
|
string Candidate::candidate() const { return "candidate:" + mCandidate; }
|
|
|
|
|
|
string Candidate::mid() const { return mMid; }
|
|
@@ -134,38 +181,60 @@ Candidate::operator string() const {
|
|
|
return line.str();
|
|
|
}
|
|
|
|
|
|
+bool Candidate::isResolved() const { return mFamily != Family::Unresolved; }
|
|
|
+
|
|
|
+Candidate::Family Candidate::family() const { return mFamily; }
|
|
|
+
|
|
|
+Candidate::Type Candidate::type() const { return mType; }
|
|
|
+
|
|
|
+Candidate::TransportType Candidate::transportType() const { return mTransportType; }
|
|
|
+
|
|
|
+std::optional<string> Candidate::address() const {
|
|
|
+ return isResolved() ? std::make_optional(mAddress) : nullopt;
|
|
|
+}
|
|
|
+
|
|
|
+std::optional<uint16_t> Candidate::port() const {
|
|
|
+ return isResolved() ? std::make_optional(mPort) : nullopt;
|
|
|
+}
|
|
|
+
|
|
|
+std::optional<uint32_t> Candidate::priority() const {
|
|
|
+ return isResolved() ? std::make_optional(mPriority) : nullopt;
|
|
|
+}
|
|
|
+
|
|
|
} // namespace rtc
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate) {
|
|
|
return out << std::string(candidate);
|
|
|
}
|
|
|
|
|
|
-std::ostream &operator<<(std::ostream &out, const rtc::CandidateType &type) {
|
|
|
+std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type) {
|
|
|
switch (type) {
|
|
|
- case rtc::CandidateType::Host:
|
|
|
- return out << "Host";
|
|
|
- case rtc::CandidateType::PeerReflexive:
|
|
|
- return out << "PeerReflexive";
|
|
|
- case rtc::CandidateType::Relayed:
|
|
|
- return out << "Relayed";
|
|
|
- case rtc::CandidateType::ServerReflexive:
|
|
|
- return out << "ServerReflexive";
|
|
|
+ case rtc::Candidate::Type::Host:
|
|
|
+ return out << "host";
|
|
|
+ case rtc::Candidate::Type::PeerReflexive:
|
|
|
+ return out << "peer_reflexive";
|
|
|
+ case rtc::Candidate::Type::ServerReflexive:
|
|
|
+ return out << "server_reflexive";
|
|
|
+ case rtc::Candidate::Type::Relayed:
|
|
|
+ return out << "relayed";
|
|
|
default:
|
|
|
- return out << "Unknown";
|
|
|
+ return out << "unknown";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-std::ostream &operator<<(std::ostream &out, const rtc::CandidateTransportType &transportType) {
|
|
|
+std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType) {
|
|
|
switch (transportType) {
|
|
|
- case rtc::CandidateTransportType::TcpActive:
|
|
|
- return out << "TcpActive";
|
|
|
- case rtc::CandidateTransportType::TcpPassive:
|
|
|
- return out << "TcpPassive";
|
|
|
- case rtc::CandidateTransportType::TcpSo:
|
|
|
- return out << "TcpSo";
|
|
|
- case rtc::CandidateTransportType::Udp:
|
|
|
- return out << "Udp";
|
|
|
+ case rtc::Candidate::TransportType::Udp:
|
|
|
+ return out << "UDP";
|
|
|
+ case rtc::Candidate::TransportType::TcpActive:
|
|
|
+ return out << "TCP_active";
|
|
|
+ case rtc::Candidate::TransportType::TcpPassive:
|
|
|
+ return out << "TCP_passive";
|
|
|
+ case rtc::Candidate::TransportType::TcpSo:
|
|
|
+ return out << "TCP_so";
|
|
|
+ case rtc::Candidate::TransportType::TcpUnknown:
|
|
|
+ return out << "TCP_unknown";
|
|
|
default:
|
|
|
- return out << "Unknown";
|
|
|
+ return out << "unknown";
|
|
|
}
|
|
|
}
|