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 "asio/detail/push_options.hpp"
#include <boost/config.hpp> #include <boost/config.hpp>
#include <cstdlib>
#include <cstring> #include <cstring>
#include <cerrno> #include <cerrno>
#include <vector> #include <vector>
@ -505,8 +506,8 @@ inline int poll_write(socket_type s)
#endif // defined(BOOST_WINDOWS) #endif // defined(BOOST_WINDOWS)
} }
inline const char* inet_ntop(int af, const void* src, char* dest, inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
size_t length) unsigned long scope_id = 0)
{ {
set_error(0); set_error(0);
#if defined(BOOST_WINDOWS) #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_family = AF_INET6;
ipv6_address->sin6_port = 0; ipv6_address->sin6_port = 0;
ipv6_address->sin6_flowinfo = 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)); 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)); const char* result = error_wrapper(::inet_ntop(af, src, dest, length));
if (result == 0 && get_error() == 0) if (result == 0 && get_error() == 0)
set_error(asio::error::invalid_argument); 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; return result;
#endif // defined(BOOST_WINDOWS) #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); set_error(0);
#if defined(BOOST_WINDOWS) #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); sockaddr_in6* ipv6_address = reinterpret_cast<sockaddr_in6*>(&address);
memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr)); 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)); int result = error_wrapper(::inet_pton(af, src, dest));
if (result <= 0 && get_error() == 0) if (result <= 0 && get_error() == 0)
set_error(asio::error::invalid_argument); 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; return result;
#endif // defined(BOOST_WINDOWS) #endif // defined(BOOST_WINDOWS)
} }

View File

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

View File

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

View File

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

View File

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