Add scope_id support.

This commit is contained in:
chris_kohlhoff 2006-02-23 12:31:08 +00:00
parent 5d678037e1
commit 255fd73a86
5 changed files with 109 additions and 16 deletions

View File

@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <vector>
@ -505,8 +506,8 @@ inline int poll_write(socket_type s)
#endif // defined(BOOST_WINDOWS)
}
inline const char* inet_ntop(int af, const void* src, char* dest,
size_t length)
inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
unsigned long scope_id = 0)
{
set_error(0);
#if defined(BOOST_WINDOWS)
@ -535,7 +536,7 @@ inline const char* inet_ntop(int af, const void* src, char* dest,
ipv6_address->sin6_family = AF_INET6;
ipv6_address->sin6_port = 0;
ipv6_address->sin6_flowinfo = 0;
ipv6_address->sin6_scope_id = 0;
ipv6_address->sin6_scope_id = scope_id;
memcpy(&ipv6_address->sin6_addr, src, sizeof(in6_addr));
}
@ -553,11 +554,22 @@ inline const char* inet_ntop(int af, const void* src, char* dest,
const char* result = error_wrapper(::inet_ntop(af, src, dest, length));
if (result == 0 && get_error() == 0)
set_error(asio::error::invalid_argument);
if (result != 0 && af == AF_INET6 && scope_id != 0)
{
using namespace std; // For strcat and sprintf.
char if_name[IF_NAMESIZE + 1] = "%";
const in6_addr* ipv6_address = static_cast<const in6_addr*>(src);
bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
sprintf(if_name + 1, "%lu", scope_id);
strcat(dest, if_name);
}
return result;
#endif // defined(BOOST_WINDOWS)
}
inline int inet_pton(int af, const char* src, void* dest)
inline int inet_pton(int af, const char* src, void* dest,
unsigned long* scope_id = 0)
{
set_error(0);
#if defined(BOOST_WINDOWS)
@ -594,6 +606,8 @@ inline int inet_pton(int af, const char* src, void* dest)
{
sockaddr_in6* ipv6_address = reinterpret_cast<sockaddr_in6*>(&address);
memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr));
if (scope_id)
*scope_id = ipv6_address->sin6_scope_id;
}
}
@ -606,6 +620,20 @@ inline int inet_pton(int af, const char* src, void* dest)
int result = error_wrapper(::inet_pton(af, src, dest));
if (result <= 0 && get_error() == 0)
set_error(asio::error::invalid_argument);
if (result > 0 && af == AF_INET6 && scope_id)
{
using namespace std; // For strchr and atoi.
*scope_id = 0;
if (const char* if_name = strchr(src, '%'))
{
in6_addr* ipv6_address = static_cast<in6_addr*>(dest);
bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
if (is_link_local)
*scope_id = if_nametoindex(if_name + 1);
if (*scope_id == 0)
*scope_id = atoi(if_name + 1);
}
}
return result;
#endif // defined(BOOST_WINDOWS)
}

View File

@ -69,6 +69,7 @@
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <net/if.h>
# if defined(__sun)
# include <sys/filio.h>
# endif
@ -102,7 +103,7 @@ typedef int socket_type;
const int invalid_socket = -1;
const int socket_error_retval = -1;
const int max_addr_v4_str_len = INET_ADDRSTRLEN;
const int max_addr_v6_str_len = INET6_ADDRSTRLEN;
const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
typedef sockaddr socket_addr_type;
typedef sockaddr_in inet_addr_v4_type;
typedef sockaddr_in6 inet_addr_v6_type;

View File

@ -49,13 +49,15 @@ public:
/// Default constructor.
address()
: scope_id_(0)
{
in6_addr tmp_addr = IN6ADDR_ANY_INIT;
addr_ = tmp_addr;
}
/// Construct an address from raw bytes.
address(const bytes_type& bytes)
/// Construct an address from raw bytes and scope ID.
address(const bytes_type& bytes, unsigned long scope_id = 0)
: scope_id_(scope_id)
{
using namespace std; // For memcpy.
memcpy(addr_.s6_addr, bytes.elems, 16);
@ -64,7 +66,8 @@ public:
/// Construct an address using an IP address string.
address(const char* host)
{
if (asio::detail::socket_ops::inet_pton(AF_INET6, host, &addr_) <= 0)
if (asio::detail::socket_ops::inet_pton(
AF_INET6, host, &addr_, &scope_id_) <= 0)
{
asio::error e(asio::detail::socket_ops::get_error());
boost::throw_exception(e);
@ -75,7 +78,7 @@ public:
address(const std::string& host)
{
if (asio::detail::socket_ops::inet_pton(
AF_INET6, host.c_str(), &addr_) <= 0)
AF_INET6, host.c_str(), &addr_, &scope_id_) <= 0)
{
asio::error e(asio::detail::socket_ops::get_error());
boost::throw_exception(e);
@ -84,7 +87,8 @@ public:
/// Copy constructor.
address(const address& other)
: addr_(other.addr_)
: addr_(other.addr_),
scope_id_(other.scope_id_)
{
}
@ -92,6 +96,7 @@ public:
address& operator=(const address& other)
{
addr_ = other.addr_;
scope_id_ = other.scope_id_;
return *this;
}
@ -111,6 +116,18 @@ public:
return *this;
}
/// Get the scope ID of the address.
unsigned long scope_id() const
{
return scope_id_;
}
/// Set the scope ID of the address.
void scope_id(unsigned long id)
{
scope_id_ = id;
}
/// Get the address in bytes.
bytes_type to_bytes() const
{
@ -126,7 +143,7 @@ public:
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);
asio::detail::max_addr_v6_str_len, scope_id_);
if (addr == 0)
{
asio::error e(asio::detail::socket_ops::get_error());
@ -135,6 +152,18 @@ public:
return addr;
}
/// Determine whether the address is a loopback address.
bool is_loopback() const
{
return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
}
/// Determine whether the address is unspecified.
bool is_unspecified() const
{
return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
}
/// Determine whether the address is link local.
bool is_link_local() const
{
@ -165,6 +194,36 @@ public:
return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
}
/// Determine whether the address is a global multicast address.
bool is_multicast_global() const
{
return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0;
}
/// Determine whether the address is a link-local multicast address.
bool is_multicast_link_local() const
{
return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0;
}
/// Determine whether the address is a node-local multicast address.
bool is_multicast_node_local() const
{
return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0;
}
/// Determine whether the address is a org-local multicast address.
bool is_multicast_org_local() const
{
return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0;
}
/// Determine whether the address is a site-local multicast address.
bool is_multicast_site_local() const
{
return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0;
}
/// Compare two addresses for equality.
friend bool operator==(const address& a1, const address& a2)
{
@ -204,6 +263,9 @@ public:
private:
// The underlying IPv6 address.
in6_addr addr_;
// The scope ID associated with the address.
unsigned long scope_id_;
};
/// Output an address as a string.
@ -216,7 +278,7 @@ private:
*
* @return The output stream.
*
* @relates tcp::endpoint
* @relates ipv6::address
*/
template <typename Ostream>
Ostream& operator<<(Ostream& os, const address& addr)

View File

@ -202,7 +202,7 @@ public:
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;
addr_.sin6_scope_id = addr.scope_id();
}
/// Copy constructor.
@ -274,7 +274,7 @@ public:
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);
return asio::ipv6::address(bytes, addr_.sin6_scope_id);
}
/// Set the IP address associated with the endpoint.
@ -283,6 +283,7 @@ public:
using namespace std; // For memcpy.
asio::ipv6::address::bytes_type bytes = addr.to_bytes();
memcpy(addr_.sin6_addr.s6_addr, bytes.elems, 16);
addr_.sin6_scope_id = addr.scope_id();
}
/// Compare two endpoints for equality.

View File

@ -156,7 +156,7 @@ public:
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;
addr_.sin6_scope_id = addr.scope_id();
}
/// Copy constructor.
@ -228,7 +228,7 @@ public:
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);
return asio::ipv6::address(bytes, addr_.sin6_scope_id);
}
/// Set the IP address associated with the endpoint.
@ -237,6 +237,7 @@ public:
using namespace std; // For memcpy.
asio::ipv6::address::bytes_type bytes = addr.to_bytes();
memcpy(addr_.sin6_addr.s6_addr, bytes.elems, 16);
addr_.sin6_scope_id = addr.scope_id();
}
/// Compare two endpoints for equality.