// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/ip_endpoint.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#if defined(OS_WIN)
#include <winsock2.h>
#elif defined(OS_POSIX)
#include <netinet/in.h>
#endif
namespace net {
IPEndPoint::IPEndPoint() : port_(0) {}
IPEndPoint::~IPEndPoint() {}
IPEndPoint::IPEndPoint(const IPAddressNumber& address, int port)
: address_(address),
port_(port) {}
IPEndPoint::IPEndPoint(const IPEndPoint& endpoint) {
address_ = endpoint.address_;
port_ = endpoint.port_;
}
int IPEndPoint::GetFamily() const {
switch (address_.size()) {
case kIPv4AddressSize: {
return AF_INET;
}
case kIPv6AddressSize: {
return AF_INET6;
}
default: {
NOTREACHED() << "Bad IP address";
return AF_UNSPEC;
}
}
}
bool IPEndPoint::ToSockAddr(struct sockaddr* address,
size_t* address_length) const {
DCHECK(address);
DCHECK(address_length);
switch (address_.size()) {
case kIPv4AddressSize: {
if (*address_length < sizeof(struct sockaddr_in))
return false;
*address_length = sizeof(struct sockaddr_in);
struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(address);
memset(addr, 0, sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
addr->sin_port = htons(port_);
memcpy(&addr->sin_addr, &address_[0], kIPv4AddressSize);
break;
}
case kIPv6AddressSize: {
if (*address_length < sizeof(struct sockaddr_in6))
return false;
*address_length = sizeof(struct sockaddr_in6);
struct sockaddr_in6* addr6 =
reinterpret_cast<struct sockaddr_in6*>(address);
memset(addr6, 0, sizeof(struct sockaddr_in6));
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(port_);
memcpy(&addr6->sin6_addr, &address_[0], kIPv6AddressSize);
break;
}
default: {
NOTREACHED() << "Bad IP address";
break;
}
}
return true;
}
bool IPEndPoint::FromSockAddr(const struct sockaddr* address,
size_t address_length) {
DCHECK(address);
switch (address->sa_family) {
case AF_INET: {
const struct sockaddr_in* addr =
reinterpret_cast<const struct sockaddr_in*>(address);
port_ = ntohs(addr->sin_port);
const char* bytes = reinterpret_cast<const char*>(&addr->sin_addr);
address_.assign(&bytes[0], &bytes[kIPv4AddressSize]);
break;
}
case AF_INET6: {
const struct sockaddr_in6* addr =
reinterpret_cast<const struct sockaddr_in6*>(address);
port_ = ntohs(addr->sin6_port);
const char* bytes = reinterpret_cast<const char*>(&addr->sin6_addr);
address_.assign(&bytes[0], &bytes[kIPv6AddressSize]);
break;
}
default: {
NOTREACHED() << "Bad IP address";
break;
}
}
return true;
}
std::string IPEndPoint::ToString() const {
struct sockaddr_storage addr_storage;
size_t addr_len = sizeof(addr_storage);
struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
if (!ToSockAddr(addr, &addr_len)) {
return "";
}
return NetAddressToStringWithPort(addr, addr_len);
}
bool IPEndPoint::operator<(const IPEndPoint& that) const {
// Sort IPv4 before IPv6.
if (address_.size() != that.address_.size()) {
return address_.size() < that.address_.size();
}
if (address_ != that.address_) {
return address_ < that.address_;
}
return port_ < that.port_;
}
bool IPEndPoint::operator==(const IPEndPoint& that) const {
return address_ == that.address_ && port_ == that.port_;
}
} // namespace net