/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/socketaddress.h" #include "rtc_base/numerics/safe_conversions.h" #if defined(WEBRTC_POSIX) #include #include #include #if defined(OPENBSD) #include #endif #if !defined(__native_client__) #include #endif #include #include #include #endif #include #include "rtc_base/byteorder.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/nethelpers.h" #if defined(WEBRTC_WIN) #include "rtc_base/win32.h" #endif namespace rtc { SocketAddress::SocketAddress() { Clear(); } SocketAddress::SocketAddress(const std::string& hostname, int port) { SetIP(hostname); SetPort(port); } SocketAddress::SocketAddress(uint32_t ip_as_host_order_integer, int port) { SetIP(IPAddress(ip_as_host_order_integer)); SetPort(port); } SocketAddress::SocketAddress(const IPAddress& ip, int port) { SetIP(ip); SetPort(port); } SocketAddress::SocketAddress(const SocketAddress& addr) { this->operator=(addr); } void SocketAddress::Clear() { hostname_.clear(); literal_ = false; ip_ = IPAddress(); port_ = 0; scope_id_ = 0; } bool SocketAddress::IsNil() const { return hostname_.empty() && IPIsUnspec(ip_) && 0 == port_; } bool SocketAddress::IsComplete() const { return (!IPIsAny(ip_)) && (0 != port_); } SocketAddress& SocketAddress::operator=(const SocketAddress& addr) { hostname_ = addr.hostname_; ip_ = addr.ip_; port_ = addr.port_; literal_ = addr.literal_; scope_id_ = addr.scope_id_; return *this; } void SocketAddress::SetIP(uint32_t ip_as_host_order_integer) { hostname_.clear(); literal_ = false; ip_ = IPAddress(ip_as_host_order_integer); scope_id_ = 0; } void SocketAddress::SetIP(const IPAddress& ip) { hostname_.clear(); literal_ = false; ip_ = ip; scope_id_ = 0; } void SocketAddress::SetIP(const std::string& hostname) { hostname_ = hostname; literal_ = IPFromString(hostname, &ip_); if (!literal_) { ip_ = IPAddress(); } scope_id_ = 0; } void SocketAddress::SetResolvedIP(uint32_t ip_as_host_order_integer) { ip_ = IPAddress(ip_as_host_order_integer); scope_id_ = 0; } void SocketAddress::SetResolvedIP(const IPAddress& ip) { ip_ = ip; scope_id_ = 0; } void SocketAddress::SetPort(int port) { port_ = rtc::dchecked_cast(port); } uint32_t SocketAddress::ip() const { return ip_.v4AddressAsHostOrderInteger(); } const IPAddress& SocketAddress::ipaddr() const { return ip_; } uint16_t SocketAddress::port() const { return port_; } std::string SocketAddress::HostAsURIString() const { // If the hostname was a literal IP string, it may need to have square // brackets added (for SocketAddress::ToString()). if (!literal_ && !hostname_.empty()) return hostname_; if (ip_.family() == AF_INET6) { return "[" + ip_.ToString() + "]"; } else { return ip_.ToString(); } } std::string SocketAddress::HostAsSensitiveURIString() const { // If the hostname was a literal IP string, it may need to have square // brackets added (for SocketAddress::ToString()). if (!literal_ && !hostname_.empty()) return hostname_; if (ip_.family() == AF_INET6) { return "[" + ip_.ToSensitiveString() + "]"; } else { return ip_.ToSensitiveString(); } } std::string SocketAddress::PortAsString() const { std::ostringstream ost; ost << port_; return ost.str(); } std::string SocketAddress::ToString() const { std::ostringstream ost; ost << *this; return ost.str(); } std::string SocketAddress::ToSensitiveString() const { std::ostringstream ost; ost << HostAsSensitiveURIString() << ":" << port(); return ost.str(); } bool SocketAddress::FromString(const std::string& str) { if (str.at(0) == '[') { std::string::size_type closebracket = str.rfind(']'); if (closebracket != std::string::npos) { std::string::size_type colon = str.find(':', closebracket); if (colon != std::string::npos && colon > closebracket) { SetPort(strtoul(str.substr(colon + 1).c_str(), nullptr, 10)); SetIP(str.substr(1, closebracket - 1)); } else { return false; } } } else { std::string::size_type pos = str.find(':'); if (std::string::npos == pos) return false; SetPort(strtoul(str.substr(pos + 1).c_str(), nullptr, 10)); SetIP(str.substr(0, pos)); } return true; } std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) { os << addr.HostAsURIString() << ":" << addr.port(); return os; } bool SocketAddress::IsAnyIP() const { return IPIsAny(ip_); } bool SocketAddress::IsLoopbackIP() const { return IPIsLoopback(ip_) || (IPIsAny(ip_) && 0 == strcmp(hostname_.c_str(), "localhost")); } bool SocketAddress::IsPrivateIP() const { return IPIsPrivate(ip_); } bool SocketAddress::IsUnresolvedIP() const { return IPIsUnspec(ip_) && !literal_ && !hostname_.empty(); } bool SocketAddress::operator==(const SocketAddress& addr) const { return EqualIPs(addr) && EqualPorts(addr); } bool SocketAddress::operator<(const SocketAddress& addr) const { if (ip_ != addr.ip_) return ip_ < addr.ip_; // We only check hostnames if both IPs are ANY or unspecified. This matches // EqualIPs(). if ((IPIsAny(ip_) || IPIsUnspec(ip_)) && hostname_ != addr.hostname_) return hostname_ < addr.hostname_; return port_ < addr.port_; } bool SocketAddress::EqualIPs(const SocketAddress& addr) const { return (ip_ == addr.ip_) && ((!IPIsAny(ip_) && !IPIsUnspec(ip_)) || (hostname_ == addr.hostname_)); } bool SocketAddress::EqualPorts(const SocketAddress& addr) const { return (port_ == addr.port_); } size_t SocketAddress::Hash() const { size_t h = 0; h ^= HashIP(ip_); h ^= port_ | (port_ << 16); return h; } void SocketAddress::ToSockAddr(sockaddr_in* saddr) const { memset(saddr, 0, sizeof(*saddr)); if (ip_.family() != AF_INET) { saddr->sin_family = AF_UNSPEC; return; } saddr->sin_family = AF_INET; saddr->sin_port = HostToNetwork16(port_); if (IPIsAny(ip_)) { saddr->sin_addr.s_addr = INADDR_ANY; } else { saddr->sin_addr = ip_.ipv4_address(); } } bool SocketAddress::FromSockAddr(const sockaddr_in& saddr) { if (saddr.sin_family != AF_INET) return false; SetIP(NetworkToHost32(saddr.sin_addr.s_addr)); SetPort(NetworkToHost16(saddr.sin_port)); literal_ = false; return true; } static size_t ToSockAddrStorageHelper(sockaddr_storage* addr, IPAddress ip, uint16_t port, int scope_id) { memset(addr, 0, sizeof(sockaddr_storage)); addr->ss_family = static_cast(ip.family()); if (addr->ss_family == AF_INET6) { sockaddr_in6* saddr = reinterpret_cast(addr); saddr->sin6_addr = ip.ipv6_address(); saddr->sin6_port = HostToNetwork16(port); saddr->sin6_scope_id = scope_id; return sizeof(sockaddr_in6); } else if (addr->ss_family == AF_INET) { sockaddr_in* saddr = reinterpret_cast(addr); saddr->sin_addr = ip.ipv4_address(); saddr->sin_port = HostToNetwork16(port); return sizeof(sockaddr_in); } return 0; } size_t SocketAddress::ToDualStackSockAddrStorage(sockaddr_storage *addr) const { return ToSockAddrStorageHelper(addr, ip_.AsIPv6Address(), port_, scope_id_); } size_t SocketAddress::ToSockAddrStorage(sockaddr_storage* addr) const { return ToSockAddrStorageHelper(addr, ip_, port_, scope_id_); } bool SocketAddressFromSockAddrStorage(const sockaddr_storage& addr, SocketAddress* out) { if (!out) { return false; } if (addr.ss_family == AF_INET) { const sockaddr_in* saddr = reinterpret_cast(&addr); *out = SocketAddress(IPAddress(saddr->sin_addr), NetworkToHost16(saddr->sin_port)); return true; } else if (addr.ss_family == AF_INET6) { const sockaddr_in6* saddr = reinterpret_cast(&addr); *out = SocketAddress(IPAddress(saddr->sin6_addr), NetworkToHost16(saddr->sin6_port)); out->SetScopeID(saddr->sin6_scope_id); return true; } return false; } SocketAddress EmptySocketAddressWithFamily(int family) { if (family == AF_INET) { return SocketAddress(IPAddress(INADDR_ANY), 0); } else if (family == AF_INET6) { return SocketAddress(IPAddress(in6addr_any), 0); } return SocketAddress(); } } // namespace rtc