Add initial support for IPv6.

This commit is contained in:
chris_kohlhoff 2006-02-08 11:22:58 +00:00
parent 068d28d85e
commit f0e4fcea41
8 changed files with 971 additions and 27 deletions

View File

@ -91,6 +91,9 @@ nobase_include_HEADERS = \
asio/ipv4/multicast.hpp \
asio/ipv4/tcp.hpp \
asio/ipv4/udp.hpp \
asio/ipv6/address.hpp \
asio/ipv6/tcp.hpp \
asio/ipv6/udp.hpp \
asio/is_read_buffered.hpp \
asio/is_write_buffered.hpp \
asio/locking_dispatcher.hpp \

View File

@ -45,6 +45,9 @@
#include "asio/ipv4/multicast.hpp"
#include "asio/ipv4/tcp.hpp"
#include "asio/ipv4/udp.hpp"
#include "asio/ipv6/address.hpp"
#include "asio/ipv6/tcp.hpp"
#include "asio/ipv6/udp.hpp"
#include "asio/is_read_buffered.hpp"
#include "asio/is_write_buffered.hpp"
#include "asio/locking_dispatcher.hpp"

View File

@ -510,33 +510,45 @@ inline const char* inet_ntop(int af, const void* src, char* dest,
{
set_error(0);
#if defined(BOOST_WINDOWS)
using namespace std; // For strncat.
using namespace std; // For memcpy.
if (af != AF_INET)
if (af != AF_INET && af != AF_INET6)
{
set_error(asio::error::address_family_not_supported);
return 0;
}
char* addr_str = error_wrapper(
::inet_ntoa(*static_cast<const in_addr*>(src)));
if (addr_str)
sockaddr_storage address;
DWORD address_length;
if (af == AF_INET)
{
*dest = '\0';
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
strncat_s(dest, length, addr_str, length);
#else
strncat(dest, addr_str, length);
#endif
return dest;
address_length = sizeof(sockaddr_in);
sockaddr_in* ipv4_address = reinterpret_cast<sockaddr_in*>(&address);
ipv4_address->sin_family = AF_INET;
ipv4_address->sin_port = 0;
memcpy(&ipv4_address->sin_addr, src, sizeof(in_addr));
}
else // AF_INET6
{
address_length = sizeof(sockaddr_in6);
sockaddr_in6* ipv6_address = reinterpret_cast<sockaddr_in6*>(&address);
ipv6_address->sin6_family = AF_INET6;
ipv6_address->sin6_port = 0;
ipv6_address->sin6_flowinfo = 0;
ipv6_address->sin6_scope_id = 0;
memcpy(&ipv6_address->sin6_addr, src, sizeof(in6_addr));
}
DWORD string_length = length;
int result = error_wrapper(::WSAAddressToStringA(
reinterpret_cast<sockaddr*>(&address),
address_length, 0, dest, &string_length));
// Windows may not set an error code on failure.
if (get_error() == 0)
if (result == socket_error_retval && get_error() == 0)
set_error(asio::error::invalid_argument);
return 0;
return result == socket_error_retval ? 0 : dest;
#else // defined(BOOST_WINDOWS)
const char* result = error_wrapper(::inet_ntop(af, src, dest, length));
if (result == 0 && get_error() == 0)
@ -549,26 +561,47 @@ inline int inet_pton(int af, const char* src, void* dest)
{
set_error(0);
#if defined(BOOST_WINDOWS)
using namespace std; // For strcmp.
using namespace std; // For memcpy and strcmp.
if (af != AF_INET)
if (af != AF_INET && af != AF_INET6)
{
set_error(asio::error::address_family_not_supported);
return -1;
}
u_long_type addr = error_wrapper(::inet_addr(src));
if (addr != INADDR_NONE || strcmp(src, "255.255.255.255") == 0)
sockaddr_storage address;
int address_length = sizeof(sockaddr_storage);
int result = error_wrapper(::WSAStringToAddressA(
const_cast<char*>(src), af, 0,
reinterpret_cast<sockaddr*>(&address),
&address_length));
if (af == AF_INET)
{
static_cast<in_addr*>(dest)->s_addr = addr;
return 1;
if (result != socket_error_retval)
{
sockaddr_in* ipv4_address = reinterpret_cast<sockaddr_in*>(&address);
memcpy(dest, &ipv4_address->sin_addr, sizeof(in_addr));
}
else if (strcmp(src, "255.255.255.255") == 0)
{
static_cast<in_addr*>(dest)->s_addr = INADDR_NONE;
}
}
else // AF_INET6
{
if (result != socket_error_retval)
{
sockaddr_in6* ipv6_address = reinterpret_cast<sockaddr_in6*>(&address);
memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr));
}
}
// Windows may not set an error code on failure.
if (get_error() == 0)
if (result == socket_error_retval && get_error() == 0)
set_error(asio::error::invalid_argument);
return 0;
return result == socket_error_retval ? -1 : 1;
#else // defined(BOOST_WINDOWS)
int result = error_wrapper(::inet_pton(af, src, dest));
if (result <= 0 && get_error() == 0)

View File

@ -82,9 +82,11 @@ namespace detail {
typedef SOCKET socket_type;
const SOCKET invalid_socket = INVALID_SOCKET;
const int socket_error_retval = SOCKET_ERROR;
const int max_addr_str_len = 256;
const int max_addr_v4_str_len = 256;
const int max_addr_v6_str_len = 256;
typedef sockaddr socket_addr_type;
typedef sockaddr_in inet_addr_v4_type;
typedef sockaddr_in6 inet_addr_v6_type;
typedef int socket_addr_len_type;
typedef unsigned long ioctl_arg_type;
typedef u_long u_long_type;
@ -99,9 +101,11 @@ const int message_do_not_route = MSG_DONTROUTE;
typedef int socket_type;
const int invalid_socket = -1;
const int socket_error_retval = -1;
const int max_addr_str_len = INET_ADDRSTRLEN;
const int max_addr_v4_str_len = INET_ADDRSTRLEN;
const int max_addr_v6_str_len = INET6_ADDRSTRLEN;
typedef sockaddr socket_addr_type;
typedef sockaddr_in inet_addr_v4_type;
typedef sockaddr_in6 inet_addr_v6_type;
typedef socklen_t socket_addr_len_type;
typedef int ioctl_arg_type;
typedef uint32_t u_long_type;

View File

@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp"
#include <string>
#include <boost/array.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
@ -41,12 +42,22 @@ namespace ipv4 {
class address
{
public:
/// The type used to represent an address as an array of bytes.
typedef boost::array<unsigned char, 4> bytes_type;
/// Default constructor.
address()
{
addr_.s_addr = 0;
}
/// Construct an address from raw bytes.
address(const bytes_type& bytes)
{
using namespace std; // For memcpy.
memcpy(&addr_.s_addr, bytes.elems, 4);
}
/// Construct an address from a unsigned long in host byte order.
address(unsigned long addr)
{
@ -110,6 +121,15 @@ public:
return *this;
}
/// Get the address in bytes.
bytes_type to_bytes() const
{
using namespace std; // For memcpy.
bytes_type bytes;
memcpy(bytes.elems, &addr_.s_addr, 4);
return bytes;
}
/// Get the address as an unsigned long in host byte order
unsigned long to_ulong() const
{
@ -119,10 +139,10 @@ public:
/// Get the address as a string in dotted decimal format.
std::string to_string() const
{
char addr_str[asio::detail::max_addr_str_len];
char addr_str[asio::detail::max_addr_v4_str_len];
const char* addr =
asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str,
asio::detail::max_addr_str_len);
asio::detail::max_addr_v4_str_len);
if (addr == 0)
{
asio::error e(asio::detail::socket_ops::get_error());

View File

@ -0,0 +1,233 @@
//
// address.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_IPV6_ADDRESS_HPP
#define ASIO_IPV6_ADDRESS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstring>
#include <string>
#include <stdexcept>
#include <boost/array.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace ipv6 {
/// Implements IP version 6 style addresses.
/**
* The asio::ipv6::address class provides the ability to use and
* manipulate IP version 6 addresses.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
class address
{
public:
/// The type used to represent an address as an array of bytes.
typedef boost::array<unsigned char, 16> bytes_type;
/// Default constructor.
address()
{
in6_addr tmp_addr = IN6ADDR_ANY_INIT;
addr_ = tmp_addr;
}
/// Construct an address from raw bytes.
address(const bytes_type& bytes)
{
using namespace std; // For memcpy.
memcpy(addr_.s6_addr, bytes.elems, 16);
}
/// Construct an address using an IP address string.
address(const char* host)
{
if (asio::detail::socket_ops::inet_pton(AF_INET6, host, &addr_) <= 0)
{
asio::error e(asio::detail::socket_ops::get_error());
boost::throw_exception(e);
}
}
/// Construct an address using an IP address string.
address(const std::string& host)
{
if (asio::detail::socket_ops::inet_pton(
AF_INET6, host.c_str(), &addr_) <= 0)
{
asio::error e(asio::detail::socket_ops::get_error());
boost::throw_exception(e);
}
}
/// Copy constructor.
address(const address& other)
: addr_(other.addr_)
{
}
/// Assign from another address.
address& operator=(const address& other)
{
addr_ = other.addr_;
return *this;
}
/// Assign from an IP address string.
address& operator=(const char* addr)
{
address tmp(addr);
addr_ = tmp.addr_;
return *this;
}
/// Assign from an IP address string.
address& operator=(const std::string& addr)
{
address tmp(addr);
addr_ = tmp.addr_;
return *this;
}
/// Get the address in bytes.
bytes_type to_bytes() const
{
using namespace std; // For memcpy.
bytes_type bytes;
memcpy(bytes.elems, addr_.s6_addr, 16);
return bytes;
}
/// Get the address as a string.
std::string to_string() const
{
char addr_str[asio::detail::max_addr_v6_str_len];
const char* addr =
asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str,
asio::detail::max_addr_v6_str_len);
if (addr == 0)
{
asio::error e(asio::detail::socket_ops::get_error());
boost::throw_exception(e);
}
return addr;
}
/// Determine whether the address is link local.
bool is_link_local() const
{
return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0;
}
/// Determine whether the address is site local.
bool is_site_local() const
{
return IN6_IS_ADDR_SITELOCAL(&addr_) != 0;
}
/// Determine whether the address is a mapped IPv4 address.
bool is_ipv4_mapped() const
{
return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
}
/// Determine whether the address is an IPv4-compatible address.
bool is_ipv4_compatible() const
{
return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
}
/// Determine whether the address is a multicast address.
bool is_multicast() const
{
return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
}
/// Compare two addresses for equality.
friend bool operator==(const address& a1, const address& a2)
{
using namespace std; // For memcmp.
return memcmp(&a1.addr_, &a2.addr_, sizeof(in6_addr)) == 0;
}
/// Compare two addresses for inequality.
friend bool operator!=(const address& a1, const address& a2)
{
using namespace std; // For memcmp.
return memcmp(&a1.addr_, &a2.addr_, sizeof(in6_addr)) != 0;
}
/// Compare addresses for ordering.
friend bool operator<(const address& a1, const address& a2)
{
using namespace std; // For memcmp.
return memcmp(&a1.addr_, &a2.addr_, sizeof(in6_addr)) < 0;
}
/// Obtain an address object that represents any address.
static address any()
{
return address();
}
/// Obtain an address object that represents the loopback address.
static address loopback()
{
address tmp;
in6_addr tmp_addr = IN6ADDR_LOOPBACK_INIT;
tmp.addr_ = tmp_addr;
return tmp;
}
private:
// The underlying IPv6 address.
in6_addr addr_;
};
/// Output an address as a string.
/**
* Used to output a human-readable string for a specified address.
*
* @param os The output stream to which the string will be written.
*
* @param addr The address to be written.
*
* @return The output stream.
*
* @relates tcp::endpoint
*/
template <typename Ostream>
Ostream& operator<<(Ostream& os, const address& addr)
{
os << addr.to_string();
return os;
}
} // namespace ipv6
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IPV6_ADDRESS_HPP

View File

@ -0,0 +1,347 @@
//
// tcp.hpp
// ~~~~~~~
//
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_IPV6_TCP_HPP
#define ASIO_IPV6_TCP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <boost/detail/workaround.hpp>
#include <cstring>
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
# include <iostream>
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
#include <memory>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/error.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/ipv6/address.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_option.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace ipv6 {
/// Encapsulates the flags needed for TCP.
/**
* The asio::ipv6::tcp class contains flags necessary for TCP sockets.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Safe.
*
* @par Concepts:
* Protocol.
*/
class tcp
{
public:
class endpoint;
/// Obtain an identifier for the type of the protocol.
int type() const
{
return SOCK_STREAM;
}
/// Obtain an identifier for the protocol.
int protocol() const
{
return IPPROTO_TCP;
}
/// Obtain an identifier for the protocol family.
int family() const
{
return PF_INET6;
}
/// Template typedefs for acceptor and socket types.
template <typename Allocator>
struct types
{
/// The service type for IPv4 TCP sockets.
typedef stream_socket_service<tcp, Allocator> socket_service;
/// The IPv4 TCP socket type.
typedef basic_stream_socket<socket_service> socket;
/// The service type for IPv4 TCP acceptors.
typedef socket_acceptor_service<tcp, Allocator> acceptor_service;
/// The IPv4 TCP acceptor type.
typedef basic_socket_acceptor<acceptor_service> acceptor;
};
/// The IPv4 TCP socket type.
typedef types<std::allocator<void> >::socket socket;
/// The IPv4 TCP acceptor type.
typedef types<std::allocator<void> >::acceptor acceptor;
/// Socket option for disabling the Nagle algorithm.
/**
* Implements the IPPROTO_TCP/TCP_NODELAY socket option.
*
* @par Examples:
* Setting the option:
* @code
* asio::stream_socket socket(io_service);
* ...
* asio::ipv6::tcp::no_delay option(true);
* socket.set_option(option);
* @endcode
*
* @par
* Getting the current option value:
* @code
* asio::stream_socket socket(io_service);
* ...
* asio::ipv6::tcp::no_delay option;
* socket.get_option(option);
* bool is_set = option.get();
* @endcode
*
* @par Concepts:
* Socket_Option, Boolean_Socket_Option.
*/
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined no_delay;
#else
typedef asio::detail::socket_option::boolean<
IPPROTO_TCP, TCP_NODELAY> no_delay;
#endif
};
/// Describes an endpoint for a TCP socket.
/**
* The asio::ipv6::tcp::endpoint class describes an endpoint that may be
* associated with a particular socket.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* Endpoint.
*/
class tcp::endpoint
{
public:
/// The protocol type associated with the endpoint.
typedef tcp protocol_type;
/// The type of the endpoint structure. This type is dependent on the
/// underlying implementation of the socket layer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined data_type;
#else
typedef asio::detail::socket_addr_type data_type;
#endif
/// The type for the size of the endpoint structure. This type is dependent on
/// the underlying implementation of the socket layer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined size_type;
#else
typedef asio::detail::socket_addr_len_type size_type;
#endif
/// Default constructor.
endpoint()
{
addr_.sin6_family = AF_INET6;
addr_.sin6_port = 0;
addr_.sin6_flowinfo = 0;
in6_addr tmp_addr = IN6ADDR_LOOPBACK_INIT;
addr_.sin6_addr = tmp_addr;
addr_.sin6_scope_id = 0;
}
/// Construct an endpoint using a port number, specified in the host's byte
/// order. The IP address will be the any address (i.e. in6addr_any). This
/// constructor would typically be used for accepting new connections.
endpoint(unsigned short port_num)
{
addr_.sin6_family = AF_INET6;
addr_.sin6_port =
asio::detail::socket_ops::host_to_network_short(port_num);
addr_.sin6_flowinfo = 0;
in6_addr tmp_addr = IN6ADDR_LOOPBACK_INIT;
addr_.sin6_addr = tmp_addr;
addr_.sin6_scope_id = 0;
}
/// Construct an endpoint using a port number and an IP address. This
/// constructor may be used for accepting connections on a specific interface
/// or for making a connection to a remote endpoint.
endpoint(unsigned short port_num, const asio::ipv6::address& addr)
{
using namespace std; // For memcpy.
addr_.sin6_family = AF_INET6;
addr_.sin6_port =
asio::detail::socket_ops::host_to_network_short(port_num);
addr_.sin6_flowinfo = 0;
asio::ipv6::address::bytes_type bytes = addr.to_bytes();
memcpy(addr_.sin6_addr.s6_addr, bytes.elems, 16);
addr_.sin6_scope_id = 0;
}
/// Copy constructor.
endpoint(const endpoint& other)
: addr_(other.addr_)
{
}
/// Assign from another endpoint.
endpoint& operator=(const endpoint& other)
{
addr_ = other.addr_;
return *this;
}
/// The protocol associated with the endpoint.
protocol_type protocol() const
{
return protocol_type();
}
/// Get the underlying endpoint in the native type.
data_type* data()
{
return reinterpret_cast<data_type*>(&addr_);
}
/// Get the underlying endpoint in the native type.
const data_type* data() const
{
return reinterpret_cast<const data_type*>(&addr_);
}
/// Get the underlying size of the endpoint in the native type.
size_type size() const
{
return sizeof(addr_);
}
/// Set the underlying size of the endpoint in the native type.
void size(size_type size)
{
if (size != sizeof(addr_))
{
asio::error e(asio::error::invalid_argument);
boost::throw_exception(e);
}
}
/// Get the port associated with the endpoint. The port number is always in
/// the host's byte order.
unsigned short port() const
{
return asio::detail::socket_ops::network_to_host_short(
addr_.sin6_port);
}
/// Set the port associated with the endpoint. The port number is always in
/// the host's byte order.
void port(unsigned short port_num)
{
addr_.sin6_port =
asio::detail::socket_ops::host_to_network_short(port_num);
}
/// Get the IP address associated with the endpoint.
asio::ipv6::address address() const
{
using namespace std; // For memcpy.
asio::ipv6::address::bytes_type bytes;
memcpy(bytes.elems, addr_.sin6_addr.s6_addr, 16);
return asio::ipv6::address(bytes);
}
/// Set the IP address associated with the endpoint.
void address(const asio::ipv6::address& addr)
{
using namespace std; // For memcpy.
asio::ipv6::address::bytes_type bytes = addr.to_bytes();
memcpy(addr_.sin6_addr.s6_addr, bytes.elems, 16);
}
/// Compare two endpoints for equality.
friend bool operator==(const endpoint& e1, const endpoint& e2)
{
return e1.address() == e2.address() && e1.port() == e2.port();
}
/// Compare two endpoints for inequality.
friend bool operator!=(const endpoint& e1, const endpoint& e2)
{
return e1.address() != e2.address() || e1.port() != e2.port();
}
/// Compare endpoints for ordering.
friend bool operator<(const endpoint& e1, const endpoint& e2)
{
if (e1.address() < e2.address())
return true;
if (e1.address() != e2.address())
return false;
return e1.port() < e2.port();
}
private:
// The underlying IPv4 socket address.
asio::detail::inet_addr_v6_type addr_;
};
/// Output an endpoint as a string.
/**
* Used to output a human-readable string for a specified endpoint.
*
* @param os The output stream to which the string will be written.
*
* @param endpoint The endpoint to be written.
*
* @return The output stream.
*
* @relates tcp::endpoint
*/
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
std::ostream& operator<<(std::ostream& os, const tcp::endpoint& endpoint)
{
os << '[' << endpoint.address().to_string() << ']' << ':' << endpoint.port();
return os;
}
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
template <typename Ostream>
Ostream& operator<<(Ostream& os, const tcp::endpoint& endpoint)
{
os << '[' << endpoint.address().to_string() << ']' << ':' << endpoint.port();
return os;
}
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
} // namespace ipv6
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IPV6_TCP_HPP

View File

@ -0,0 +1,301 @@
//
// udp.hpp
// ~~~~~~~
//
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_IPV6_UDP_HPP
#define ASIO_IPV6_UDP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
# include <iostream>
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
#include <memory>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_datagram_socket.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/error.hpp"
#include "asio/ipv6/address.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace ipv6 {
/// Encapsulates the flags needed for UDP.
/**
* The asio::ipv6::udp class contains flags necessary for UDP sockets.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Safe.
*
* @par Concepts:
* Protocol.
*/
class udp
{
public:
class endpoint;
/// Obtain an identifier for the type of the protocol.
int type() const
{
return SOCK_DGRAM;
}
/// Obtain an identifier for the protocol.
int protocol() const
{
return IPPROTO_UDP;
}
/// Obtain an identifier for the protocol family.
int family() const
{
return PF_INET6;
}
/// Template typedefs for socket types.
template <typename Allocator>
struct types
{
/// The service type for IPv4 UDP sockets.
typedef datagram_socket_service<udp, Allocator> socket_service;
/// The IPv4 UDP socket type.
typedef basic_datagram_socket<socket_service> socket;
};
/// The IPv4 UDP socket type.
typedef types<std::allocator<void> >::socket socket;
};
/// Describes an endpoint for a UDP socket.
/**
* The asio::ipv6::udp::endpoint class describes an endpoint that may be
* associated with a particular socket.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* Endpoint.
*/
class udp::endpoint
{
public:
/// The protocol type associated with the endpoint.
typedef udp protocol_type;
/// The type of the endpoint structure. This type is dependent on the
/// underlying implementation of the socket layer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined data_type;
#else
typedef asio::detail::socket_addr_type data_type;
#endif
/// The type for the size of the endpoint structure. This type is dependent on
/// the underlying implementation of the socket layer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined size_type;
#else
typedef asio::detail::socket_addr_len_type size_type;
#endif
/// Default constructor.
endpoint()
{
addr_.sin6_family = AF_INET6;
addr_.sin6_port = 0;
addr_.sin6_flowinfo = 0;
in6_addr tmp_addr = IN6ADDR_LOOPBACK_INIT;
addr_.sin6_addr = tmp_addr;
addr_.sin6_scope_id = 0;
}
/// Construct an endpoint using a port number, specified in the host's byte
/// order. The IP address will be the any address (i.e. in6addr_any). This
/// constructor would typically be used for accepting new connections.
endpoint(unsigned short port_num)
{
addr_.sin6_family = AF_INET6;
addr_.sin6_port =
asio::detail::socket_ops::host_to_network_short(port_num);
addr_.sin6_flowinfo = 0;
in6_addr tmp_addr = IN6ADDR_LOOPBACK_INIT;
addr_.sin6_addr = tmp_addr;
addr_.sin6_scope_id = 0;
}
/// Construct an endpoint using a port number and an IP address. This
/// constructor may be used for accepting connections on a specific interface
/// or for making a connection to a remote endpoint.
endpoint(unsigned short port_num, const asio::ipv6::address& addr)
{
using namespace std; // For memcpy.
addr_.sin6_family = AF_INET6;
addr_.sin6_port =
asio::detail::socket_ops::host_to_network_short(port_num);
addr_.sin6_flowinfo = 0;
asio::ipv6::address::bytes_type bytes = addr.to_bytes();
memcpy(addr_.sin6_addr.s6_addr, bytes.elems, 16);
addr_.sin6_scope_id = 0;
}
/// Copy constructor.
endpoint(const endpoint& other)
: addr_(other.addr_)
{
}
/// Assign from another endpoint.
endpoint& operator=(const endpoint& other)
{
addr_ = other.addr_;
return *this;
}
/// The protocol associated with the endpoint.
protocol_type protocol() const
{
return protocol_type();
}
/// Get the underlying endpoint in the native type.
data_type* data()
{
return reinterpret_cast<data_type*>(&addr_);
}
/// Get the underlying endpoint in the native type.
const data_type* data() const
{
return reinterpret_cast<const data_type*>(&addr_);
}
/// Get the underlying size of the endpoint in the native type.
size_type size() const
{
return sizeof(addr_);
}
/// Set the underlying size of the endpoint in the native type.
void size(size_type size)
{
if (size != sizeof(addr_))
{
asio::error e(asio::error::invalid_argument);
boost::throw_exception(e);
}
}
/// Get the port associated with the endpoint. The port number is always in
/// the host's byte order.
unsigned short port() const
{
return asio::detail::socket_ops::network_to_host_short(
addr_.sin6_port);
}
/// Set the port associated with the endpoint. The port number is always in
/// the host's byte order.
void port(unsigned short port_num)
{
addr_.sin6_port =
asio::detail::socket_ops::host_to_network_short(port_num);
}
/// Get the IP address associated with the endpoint.
asio::ipv6::address address() const
{
using namespace std; // For memcpy.
asio::ipv6::address::bytes_type bytes;
memcpy(bytes.elems, addr_.sin6_addr.s6_addr, 16);
return asio::ipv6::address(bytes);
}
/// Set the IP address associated with the endpoint.
void address(const asio::ipv6::address& addr)
{
using namespace std; // For memcpy.
asio::ipv6::address::bytes_type bytes = addr.to_bytes();
memcpy(addr_.sin6_addr.s6_addr, bytes.elems, 16);
}
/// Compare two endpoints for equality.
friend bool operator==(const endpoint& e1, const endpoint& e2)
{
return e1.address() == e2.address() && e1.port() == e2.port();
}
/// Compare two endpoints for inequality.
friend bool operator!=(const endpoint& e1, const endpoint& e2)
{
return e1.address() != e2.address() || e1.port() != e2.port();
}
/// Compare endpoints for ordering.
friend bool operator<(const endpoint& e1, const endpoint& e2)
{
if (e1.address() < e2.address())
return true;
if (e1.address() != e2.address())
return false;
return e1.port() < e2.port();
}
private:
// The underlying IPv4 socket address.
asio::detail::inet_addr_v6_type addr_;
};
/// Output an endpoint as a string.
/**
* Used to output a human-readable string for a specified endpoint.
*
* @param os The output stream to which the string will be written.
*
* @param endpoint The endpoint to be written.
*
* @return The output stream.
*
* @relates udp::endpoint
*/
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
std::ostream& operator<<(std::ostream& os, const udp::endpoint& endpoint)
{
os << '[' << endpoint.address().to_string() << ']' << ':' << endpoint.port();
return os;
}
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
template <typename Ostream>
Ostream& operator<<(Ostream& os, const udp::endpoint& endpoint)
{
os << '[' << endpoint.address().to_string() << ']' << ':' << endpoint.port();
return os;
}
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
} // namespace ipv6
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IPV6_UDP_HPP