/* * libjingle * Copyright 2004--2005, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "talk/base/socketaddress.h" #ifdef POSIX #include #include #include #if defined(OPENBSD) #include #endif #if !defined(__native_client__) #include #endif #include #include #include #endif #include #include "talk/base/byteorder.h" #include "talk/base/common.h" #include "talk/base/logging.h" #include "talk/base/nethelpers.h" #ifdef WIN32 #include "talk/base/win32.h" #endif namespace talk_base { SocketAddress::SocketAddress() { Clear(); } SocketAddress::SocketAddress(const std::string& hostname, int port) { SetIP(hostname); SetPort(port); } SocketAddress::SocketAddress(uint32 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 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 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) { ASSERT((0 <= port) && (port < 65536)); port_ = port; } uint32 SocketAddress::ip() const { return ip_.v4AddressAsHostOrderInteger(); } const IPAddress& SocketAddress::ipaddr() const { return ip_; } uint16 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(), NULL, 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(), NULL, 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, int port, int scope_id) { memset(addr, 0, sizeof(sockaddr_storage)); addr->ss_family = 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_); } std::string SocketAddress::IPToString(uint32 ip_as_host_order_integer) { return IPAddress(ip_as_host_order_integer).ToString(); } std::string IPToSensitiveString(uint32 ip_as_host_order_integer) { return IPAddress(ip_as_host_order_integer).ToSensitiveString(); } bool SocketAddress::StringToIP(const std::string& hostname, uint32* ip) { in_addr addr; if (talk_base::inet_pton(AF_INET, hostname.c_str(), &addr) == 0) return false; *ip = NetworkToHost32(addr.s_addr); return true; } bool SocketAddress::StringToIP(const std::string& hostname, IPAddress* ip) { in_addr addr4; if (talk_base::inet_pton(AF_INET, hostname.c_str(), &addr4) > 0) { if (ip) { *ip = IPAddress(addr4); } return true; } in6_addr addr6; if (talk_base::inet_pton(AF_INET6, hostname.c_str(), &addr6) > 0) { if (ip) { *ip = IPAddress(addr6); } return true; } return false; } uint32 SocketAddress::StringToIP(const std::string& hostname) { uint32 ip = 0; StringToIP(hostname, &ip); return ip; } 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 talk_base