blob: 7780bbdfb85ba3a075dc67283fdf6bc2374dbd53 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_LIB_INET_SOCKET_ADDRESS_H_
#define GARNET_LIB_INET_SOCKET_ADDRESS_H_
#include <ostream>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "garnet/lib/inet/ip_address.h"
#include "garnet/lib/inet/ip_port.h"
#include "lib/fxl/logging.h"
#include <fuchsia/netstack/cpp/fidl.h>
namespace inet {
// Represents a V4 or V6 socket address.
class SocketAddress {
public:
static const SocketAddress kInvalid;
// Creates an invalid socket.
SocketAddress();
// Creates an IPV4 socket address from four address bytes and an IpPort.
SocketAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, IpPort port);
// Creates an IPV4 socket address from an in_addr_t and an IpPort.
SocketAddress(in_addr_t addr, IpPort port);
// Creates an IPV4 socket address from an sockaddr_in struct.
explicit SocketAddress(const sockaddr_in& addr);
// Creates an IPV6 socket address from eight address words and an IpPort.
SocketAddress(uint16_t w0, uint16_t w1, uint16_t w2, uint16_t w3, uint16_t w4,
uint16_t w5, uint16_t w6, uint16_t w7, IpPort port);
// Creates an IPV6 socket address from two address words and an IpPort.
SocketAddress(uint16_t w0, uint16_t w7, IpPort port);
// Creates an IPV6 socket address from an in6_addr struct and an IpPort.
SocketAddress(const in6_addr& addr, IpPort port);
// Creates an IPV6 socket address from an sockaddr_in6 struct.
explicit SocketAddress(const sockaddr_in6& addr);
// Creates a socket address from a IpAddress and an IpPort.
SocketAddress(const IpAddress& addr, IpPort port);
// Creates a socket address from an sockaddr_storage struct.
explicit SocketAddress(const sockaddr_storage& addr);
// Creates a socket address from a SocketAddress struct.
explicit SocketAddress(const fuchsia::netstack::SocketAddress* addr);
bool is_valid() const { return family() != AF_UNSPEC; }
sa_family_t family() const { return v4_.sin_family; }
bool is_v4() const { return family() == AF_INET; }
bool is_v6() const { return family() == AF_INET6; }
IpAddress address() const {
return is_v4() ? IpAddress(v4_.sin_addr) : IpAddress(v6_.sin6_addr);
}
IpPort port() const { return IpPort::From_in_port_t(v4_.sin_port); }
const sockaddr_in& as_sockaddr_in() const {
FXL_DCHECK(is_v4());
return v4_;
}
const sockaddr_in6& as_sockaddr_in6() const {
FXL_DCHECK(is_v6());
return v6_;
}
const sockaddr* as_sockaddr() const {
return reinterpret_cast<const sockaddr*>(&v4_);
}
socklen_t socklen() const { return is_v4() ? sizeof(v4_) : sizeof(v6_); }
std::string ToString() const;
explicit operator bool() const { return is_valid(); }
bool operator==(const SocketAddress& other) const {
return is_v4() == other.is_v4() &&
std::memcmp(as_sockaddr(), other.as_sockaddr(), socklen()) == 0;
}
bool operator!=(const SocketAddress& other) const {
return !(*this == other);
}
private:
union {
sockaddr_in v4_;
sockaddr_in6 v6_;
};
};
std::ostream& operator<<(std::ostream& os, const SocketAddress& value);
} // namespace inet
template <>
struct std::hash<inet::SocketAddress> {
std::size_t operator()(const inet::SocketAddress& address) const noexcept {
return std::hash<inet::IpAddress>{}(address.address()) ^
(std::hash<uint16_t>{}(address.port().as_uint16_t()) << 1);
}
};
#endif // GARNET_LIB_INET_SOCKET_ADDRESS_H_