diff --git a/src/beast/Builds/VisualStudio2013/beast.vcxproj b/src/beast/Builds/VisualStudio2013/beast.vcxproj index f4b93cdcb6..f883a8a237 100644 --- a/src/beast/Builds/VisualStudio2013/beast.vcxproj +++ b/src/beast/Builds/VisualStudio2013/beast.vcxproj @@ -157,8 +157,12 @@ + + + + @@ -577,6 +581,24 @@ true true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + true diff --git a/src/beast/Builds/VisualStudio2013/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2013/beast.vcxproj.filters index 9a1c036675..36c5a3064a 100644 --- a/src/beast/Builds/VisualStudio2013/beast.vcxproj.filters +++ b/src/beast/Builds/VisualStudio2013/beast.vcxproj.filters @@ -294,6 +294,9 @@ {44489531-f44a-439a-a6ea-d32c252b1e8b} + + {43cc0f2a-9905-4081-8104-48d2c4be9e7e} + @@ -1143,9 +1146,6 @@ beast\utility - - beast\net - beast @@ -1254,6 +1254,21 @@ beast\insight + + beast\net\detail + + + beast\net + + + beast\net + + + beast\net + + + beast\net + @@ -1769,9 +1784,6 @@ beast\utility\impl - - beast\net\impl - beast\asio @@ -1820,6 +1832,18 @@ beast\insight\impl + + beast\net\impl + + + beast\net\impl + + + beast\net\impl + + + beast\net\impl + diff --git a/src/beast/beast/Net.h b/src/beast/beast/Net.h index 79515845ad..4ad0b89a66 100644 --- a/src/beast/beast/Net.h +++ b/src/beast/beast/Net.h @@ -24,5 +24,13 @@ #include "net/DynamicBuffer.h" #include "net/IPAddress.h" +#include "net/IPAddressV4.h" +#include "net/IPAddressV6.h" +#include "net/IPEndpoint.h" + +// VFALCO DEPRECATED, REMOVE ASAP! +namespace beast { +typedef IP::Endpoint IPAddress; +} #endif diff --git a/src/beast/beast/asio/IPAddressConversion.h b/src/beast/beast/asio/IPAddressConversion.h index 9624c6a8dc..182691c043 100644 --- a/src/beast/beast/asio/IPAddressConversion.h +++ b/src/beast/beast/asio/IPAddressConversion.h @@ -20,41 +20,47 @@ #ifndef BEAST_ASIO_IPADDRESSCONVERSION_H_INCLUDED #define BEAST_ASIO_IPADDRESSCONVERSION_H_INCLUDED -#include "../net/IPAddress.h" +#include "../net/IPEndpoint.h" #include #include namespace beast { +namespace IP { +/** Convert to Endpoint. + The port is set to zero. +*/ +Endpoint from_asio (boost::asio::ip::address const& address); + +/** Convert to Endpoint. */ +Endpoint from_asio (boost::asio::ip::tcp::endpoint const& endpoint); + +/** Convert to asio::ip::address. + The port is ignored. +*/ +boost::asio::ip::address to_asio_address (Endpoint const& endpoint); + +/** Convert to asio::ip::tcp::endpoint. */ +boost::asio::ip::tcp::endpoint to_asio_endpoint (Endpoint const& endpoint); + +} +} + +namespace beast { + +// DEPRECATED struct IPAddressConversion { - /** Convert to IPAddress. - The port is set to zero. - */ - static IPAddress from_asio (boost::asio::ip::address const& address); - - /** Convert to IPAddress, including port. */ - static IPAddress from_asio (boost::asio::ip::tcp::endpoint const& endpoint); - - /** Convert to asio::ip::address. - The port is ignored. - */ - static boost::asio::ip::address to_asio_address (IPAddress const& address); - - /** Convert to asio::ip::tcp::endpoint. */ - static boost::asio::ip::tcp::endpoint to_asio_endpoint (IPAddress const& address); - - /** Conversions to string. */ - /** @{ */ - static std::string to_string (boost::asio::ip::tcp::endpoint const& endpoint) - { - std::stringstream ss; - ss << endpoint; - return ss.str(); - } - /** @} */ + static IP::Endpoint from_asio (boost::asio::ip::address const& address) + { return IP::from_asio (address); } + static IP::Endpoint from_asio (boost::asio::ip::tcp::endpoint const& endpoint) + { return IP::from_asio (endpoint); } + static boost::asio::ip::address to_asio_address (IP::Endpoint const& address) + { return IP::to_asio_address (address); } + static boost::asio::ip::tcp::endpoint to_asio_endpoint (IP::Endpoint const& address) + { return IP::to_asio_endpoint (address); } }; } diff --git a/src/beast/beast/asio/impl/IPAddressConversion.cpp b/src/beast/beast/asio/impl/IPAddressConversion.cpp index 32c8cba860..62511b6f64 100644 --- a/src/beast/beast/asio/impl/IPAddressConversion.cpp +++ b/src/beast/beast/asio/impl/IPAddressConversion.cpp @@ -20,34 +20,35 @@ #include "../IPAddressConversion.h" namespace beast { +namespace IP { -IPAddress IPAddressConversion::from_asio (boost::asio::ip::address const& address) +Endpoint from_asio (boost::asio::ip::address const& address) { if (address.is_v4 ()) { boost::asio::ip::address_v4::bytes_type const bytes ( address.to_v4().to_bytes()); - return IPAddress (IPAddress::V4 ( + return Endpoint (AddressV4 ( bytes [0], bytes [1], bytes [2], bytes [3])); } // VFALCO TODO IPv6 support bassertfalse; - return IPAddress(); + return Endpoint(); } -IPAddress IPAddressConversion::from_asio (boost::asio::ip::tcp::endpoint const& endpoint) +Endpoint from_asio (boost::asio::ip::tcp::endpoint const& endpoint) { - return from_asio (endpoint.address()).withPort (endpoint.port()); + return from_asio (endpoint.address()).at_port (endpoint.port()); } -boost::asio::ip::address IPAddressConversion::to_asio_address (IPAddress const& address) +boost::asio::ip::address to_asio_address (Endpoint const& endpoint) { - if (address.isV4 ()) + if (endpoint.address().is_v4()) { return boost::asio::ip::address ( boost::asio::ip::address_v4 ( - address.v4().value)); + endpoint.address().to_v4().value)); } // VFALCO TODO IPv6 support @@ -56,10 +57,11 @@ boost::asio::ip::address IPAddressConversion::to_asio_address (IPAddress const& boost::asio::ip::address_v6 ()); } -boost::asio::ip::tcp::endpoint IPAddressConversion::to_asio_endpoint (IPAddress const& address) +boost::asio::ip::tcp::endpoint to_asio_endpoint (Endpoint const& endpoint) { return boost::asio::ip::tcp::endpoint ( - to_asio_address (address), address.port()); + to_asio_address (endpoint), endpoint.port()); } } +} diff --git a/src/beast/beast/insight/impl/StatsDCollector.cpp b/src/beast/beast/insight/impl/StatsDCollector.cpp index 744b3b2704..02e25bf9ff 100644 --- a/src/beast/beast/insight/impl/StatsDCollector.cpp +++ b/src/beast/beast/insight/impl/StatsDCollector.cpp @@ -215,11 +215,11 @@ private: static boost::asio::ip::udp::endpoint to_endpoint ( IPAddress const &address) { - if (address.isV4 ()) + if (address.is_v4 ()) { return boost::asio::ip::udp::endpoint ( boost::asio::ip::address_v4 ( - address.v4().value), address.port ()); + address.to_v4().value), address.port ()); } // VFALCO TODO IPv6 support diff --git a/src/beast/beast/net/IPAddress.h b/src/beast/beast/net/IPAddress.h index c67a31179c..0211677afd 100644 --- a/src/beast/beast/net/IPAddress.h +++ b/src/beast/beast/net/IPAddress.h @@ -23,388 +23,140 @@ #include #include #include - + #include "../CStdInt.h" +#include "IPAddressV4.h" +#include "IPAddressV6.h" //------------------------------------------------------------------------------ namespace beast { +namespace IP { -/** Represents an IP address (v4 or v6) and port combination. */ -class IPAddress +/** A version-independent IP address. + This object can represent either an IPv4 or IPv6 address. +*/ +class Address { public: + /** Create an unspecified IPv4 address. */ + Address (); + + /** Create an IPv4 address. */ + Address (AddressV4 const& addr); + + /** Create an IPv6 address. */ + Address (AddressV6 const& addr); + + /** Assign a copy from another address in any format. */ + /** @{ */ + Address& operator= (AddressV4 const& addr); + Address& operator= (AddressV6 const& addr); + /** @} */ + + /** Create an Address from a string. + @return A pair with the address, and bool set to `true` on success. + */ + static std::pair from_string (std::string const& s); + + /** Returns a string representing the address. */ + std::string to_string () const; + + /** Returns `true` if this address represents an IPv4 address. */ + bool is_v4 () const + { return m_type == ipv4; } + + /** Returns `true` if this address represents an IPv6 address. */ + bool is_v6 () const + { return m_type == ipv6; } + + /** Returns the IPv4 address. + Precondition: + is_v4() returns true + */ + AddressV4 const& to_v4 () const; + + /** Returns the IPv6 address. + Precondition: + is_v6() returns true + */ + AddressV6 const& to_v6 () const; + + /** Arithmetic comparison. */ + /** @{ */ + friend bool operator== (Address const& lhs, Address const& rhs); + friend bool operator< (Address const& lhs, Address const& rhs); + + friend bool operator!= (Address const& lhs, Address const& rhs) + { return ! (lhs == rhs); } + friend bool operator> (Address const& lhs, Address const& rhs) + { return rhs < lhs; } + friend bool operator<= (Address const& lhs, Address const& rhs) + { return ! (lhs > rhs); } + friend bool operator>= (Address const& lhs, Address const& rhs) + { return ! (rhs > lhs); } + /** @} */ + +private: enum Type { - none, ipv4, ipv6 }; - template - static std::string numberToString (Number n) - { - std::ostringstream os; - os << std::dec << n; - return std::string (os.str()); - } - - //-------------------------------------------------------------------------- - - /** Used for IPv4 formats. */ - struct V4 - { - /** Construct the "any" address. */ - V4 (); - - /** Construct from a 32-bit unsigned. - @note Octets are formed in order from the MSB to the LSB. - */ - explicit V4 (uint32 value_); - - /** Construct from four individual octets.. - @note The resulting address is a.b.c.d - */ - V4 (uint8 a, uint8 b, uint8 c, uint8 d); - - /** Construct a copy of another address. */ - V4 (V4 const& other); - - /** Assign a copy of another address. */ - V4& operator= (V4 const& other); - - /** Returns a V4 address representing the local broadcast address. */ - static V4 localBroadcastAddress (); - - /** Returns the directed broadcast address for the network implied by this address. */ - V4 broadcastAddress () const; - - /** Returns the IPv4 address class as 'A', 'B', 'C', or 'D'. - @note Class 'D' represents multicast addresses (224.*.*.*). - */ - char getClass () const; - - /** Returns `true` if this is a public routable address. */ - bool isPublic () const; - - /** Returns `true` if this is a private, non-routable address. */ - bool isPrivate () const; - - /** Returns `true` if this is a broadcast address. */ - bool isBroadcast () const; - - /** Returns `true` if this is a multicast address. */ - bool isMulticast () const; - - /** Returns `true` if this refers to any loopback adapter address. */ - bool isLoopback () const; - - /** Supports access via operator[]. */ - template - class Proxy - { - public: - typedef typename std::conditional < - IsConst, uint32 const*, uint32*>::type Pointer; - - Proxy (int shift, Pointer value) - : m_shift (shift) - , m_value (value) - { - } - - operator uint8() const - { - return ((*m_value)>>m_shift) & 0xff; - } - - template - Proxy& operator= (IntegralType v) - { - (*m_value) = - ( (*m_value) & (~((0xff)< operator[] (std::size_t index) const; - - /** Provides read/write access to individual octets of the IPv4 address. */ - Proxy operator[] (std::size_t index); - - /** Convert the address to a human readable string. */ - /** @{ */ - std::string to_string () const; - operator std::string () const; - /** @} */ - - struct hasher - { - std::size_t operator() (V4 const& v) const - { - return v.value; - } - }; - - /** The value as a 32 bit unsigned. */ - uint32 value; - }; - - //-------------------------------------------------------------------------- - - /** Used for IPv6 formats. */ - struct V6 - { - /** Returns `true` if this is a public routable address. */ - bool isPublic () const - { - return false; - } - - /** Returns `true` if this is a private, non-routable address. */ - bool isPrivate () const - { - return false; - } - - /** Returns `true` if this is a broadcast address. */ - bool isBroadcast () const - { - return false; - } - - /** Returns `true` if this is a multicast address. */ - bool isMulticast () const - { - return false; - } - - /** Returns `true` if this refers to any loopback adapter address. */ - bool isLoopback () const - { - return false; - } - - /** Convert the address to a human readable string. */ - /** @{ */ - std::string to_string () const - { - return std::string(); - } - - operator std::string () const - { - return to_string(); - } - /** @} */ - - struct hasher - { - std::size_t operator() (V6 const&) const - { - return 0; - } - }; - }; - - //-------------------------------------------------------------------------- - - /** Create an empty address. */ - IPAddress (); - - /** Create an IPv4 address with optional port. */ - IPAddress (V4 const& v4, uint16 port = 0); - - /** Create an IPv6 address with optional port. */ - IPAddress (V6 const& v6, uint16 port = 0); - - /** Create a copy of another IPAddress. */ - IPAddress (IPAddress const& other); - - /** Copy assign another IPAddress. */ - IPAddress& operator= (IPAddress const& other); - - /** Create an IPAddress from a string. - If a parsing error occurs, the endpoint will be empty. - */ - static IPAddress from_string (std::string const& s); - - /** Create an IPAddress from a string. - If a parsing error occurs, the endpoint will be empty. - This recognizes an alternate form of the text. Instead of a colon - separating the optional port specification, any amount of whitespace - is allowed. - */ - static IPAddress from_string_altform (std::string const& s); - - /** Copy assign an IPv4 address. - The port is set to zero. - */ - IPAddress& operator= (V4 const& address); - - /** Copy assign an IPv6 address. - The port is set to zero. - */ - IPAddress& operator= (V6 const& address); - - /** Returns a new IPAddress with this address, and the given port. */ - IPAddress withPort (uint16 port) const; - - /** Returns `true` if this IPAddress refers to nothing. */ - bool empty () const; - - /** Returns `true` if this IPAddress refers to nothing. */ - bool isNull () const; - - /** Returns `true` if this IPAddress refers to something. */ - bool isNotNull () const; - - /** Returns the type of this IPAddress. */ - Type type () const; - - /** Returns `true` if this IPAddress represents an IPv4 address. */ - bool isV4 () const; - - /** Returns `true` if this IPAddress represents an IPv6 address. */ - bool isV6 () const; - - /** Returns the IPv4 address. - Undefined behavior results if type() != ipv4. - */ - V4 const& v4 () const; - - /** Returns the IPv6 address. - Undefined behavior results if type() != ipv4. - */ - V6 const& v6 () const; - - /** Returns the port number. - Undefined if type() == none. - */ - uint16 port () const; - - /** Returns `true` if this is a public routable address. */ - bool isPublic () const; - - /** Returns `true` if this is a private, non-routable address. */ - bool isPrivate () const; - - /** Returns `true` if this is a broadcast address. */ - bool isBroadcast () const; - - /** Returns `true` if this is a multicast address. */ - bool isMulticast () const; - - /** Returns `true` if this refers to any loopback adapter address. */ - bool isLoopback () const; - - /** Convert the address to a human readable string. */ - /** @{ */ - std::string to_string () const; - operator std::string () const; - /** @} */ - - typedef std::hash hasher; - - struct key_equal; - - /** LessThanComparable functor that ignores the port. */ - struct LessWithoutPort - { - bool operator() (IPAddress const& lhs, IPAddress const& rhs) const; - }; - - /** EqualityComparable functor that ignores the port. */ - struct EqualWithoutPort - { - bool operator() (IPAddress const& lhs, IPAddress const& rhs) const; - }; - -private: Type m_type; - uint16 m_port; - V4 m_v4; - V6 m_v6; + AddressV4 m_v4; + AddressV6 m_v6; }; -/** Comparison. */ -/** @{ */ -bool operator== (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs); -bool operator!= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs); -bool operator< (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs); -bool operator<= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs); -bool operator> (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs); -bool operator>= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs); +//------------------------------------------------------------------------------ -bool operator== (IPAddress const& lhs, IPAddress const& rhs); -bool operator!= (IPAddress const& lhs, IPAddress const& rhs); -bool operator< (IPAddress const& lhs, IPAddress const& rhs); -bool operator<= (IPAddress const& lhs, IPAddress const& rhs); -bool operator> (IPAddress const& lhs, IPAddress const& rhs); -bool operator>= (IPAddress const& lhs, IPAddress const& rhs); +// Properties -/** Output stream conversions. */ -/** @{ */ -std::ostream& operator<< (std::ostream& os, IPAddress::V4 const& addr); -std::ostream& operator<< (std::ostream& os, IPAddress::V6 const& addr); -std::ostream& operator<< (std::ostream& os, IPAddress const& ep); -/** @} */ +/** Returns `true` if this is a loopback address. */ +bool is_loopback (Address const& addr); -/** Input stream conversions. */ -/** @{ */ -std::istream& operator>> (std::istream& is, IPAddress::V4& addr); -std::istream& operator>> (std::istream& is, IPAddress& ep); -//std::istream& operator>> (std::istream &is, IPAddress::V6&); -/** @} */ +/** Returns `true` if the address is unspecified. */ +bool is_unspecified (Address const& addr); -struct IPAddress::key_equal -{ - bool operator() (IPAddress const& lhs, IPAddress const& rhs) const - { - return lhs == rhs; - } -}; +/** Returns `true` if the address is a multicast address. */ +bool is_multicast (Address const& addr); + +/** Returns `true` if the address is a private unroutable address. */ +bool is_private (Address const& addr); + +/** Returns `true` if the address is a public routable address. */ +bool is_public (Address const& addr); + +//------------------------------------------------------------------------------ + +/** boost::hash support. */ +std::size_t hash_value (Address const& addr); + +/** Returns the address represented as a string. */ +inline std::string to_string (Address const& addr) + { return addr.to_string (); } + +/** Output stream conversion. */ +template +OutputStream& operator<< (OutputStream& os, Address const& addr) + { return os << to_string (addr); } + +/** Input stream conversion. */ +std::istream& operator>> (std::istream& is, Address& addr); -inline bool IPAddress::LessWithoutPort::operator() ( - IPAddress const& lhs, IPAddress const& rhs) const -{ - return lhs.withPort (0) < rhs.withPort (0); } - -inline bool IPAddress::EqualWithoutPort::operator() ( - IPAddress const& lhs, IPAddress const& rhs) const -{ - return lhs.withPort (0) == rhs.withPort (0); -} - } //------------------------------------------------------------------------------ namespace std { - template <> -struct hash +struct hash { - std::size_t operator() (beast::IPAddress const& value) const - { - std::size_t hash (0); - if (value.isV4()) - hash = beast::IPAddress::V4::hasher() (value.v4()); - else if (value.isV6()) - hash = beast::IPAddress::V6::hasher() (value.v6()); - hash += value.port(); - return hash; - } + std::size_t operator() (beast::IP::Address const& addr) const + { return hash_value (addr); } }; - } #endif diff --git a/src/beast/beast/net/IPAddressV4.h b/src/beast/beast/net/IPAddressV4.h new file mode 100644 index 0000000000..58090734e3 --- /dev/null +++ b/src/beast/beast/net/IPAddressV4.h @@ -0,0 +1,197 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_IPADDRESSV4_H_INCLUDED +#define BEAST_NET_IPADDRESSV4_H_INCLUDED + +#include +#include +#include + +#include "../CStdInt.h" + +namespace beast { +namespace IP { + +/** Represents a version 4 IP address. */ +struct AddressV4 +{ + /** Default constructor represents the 'any' address. */ + AddressV4 (); + + /** Construct from a 32-bit unsigned. + @note Octets are formed in order from the MSB to the LSB. + */ + explicit AddressV4 (uint32 value_); + + /** Construct from four individual octets.. + @note The resulting address is a.b.c.d + */ + AddressV4 (uint8 a, uint8 b, uint8 c, uint8 d); + + /** Create an address from an IPv4 address string in dotted decimal form. + @return A pair with the address, and bool set to `true` on success. + */ + static std::pair from_string (std::string const& s); + + /** Returns an address that represents 'any' address. */ + static AddressV4 any () + { return AddressV4(); } + + /** Returns an address that represents the loopback address. */ + static AddressV4 loopback () + { return AddressV4 (0x7f000001); } + + /** Returns an address that represents the broadcast address. */ + static AddressV4 broadcast () + { return AddressV4 (0xffffffff); } + + /** Returns the broadcast address for the specified address. */ + static AddressV4 broadcast (AddressV4 const& address); + + /** Returns the broadcast address corresponding to the address and mask. */ + static AddressV4 broadcast ( + AddressV4 const& address, AddressV4 const& mask); + + /** Returns `true` if this is a broadcast address. */ + bool is_broadcast () const + { return *this == broadcast (*this); } + + /** Returns the address class for the given address. + @note Class 'D' represents multicast addresses (224.*.*.*). + */ + static char get_class (AddressV4 const& address); + + /** Returns the netmask for the address class or address. */ + /** @{ */ + static AddressV4 netmask (char address_class); + static AddressV4 netmask (AddressV4 const& v); + /** @} */ + + /** Arithmetic comparison. */ + /** @{ */ + friend bool operator== (AddressV4 const& lhs, AddressV4 const& rhs) + { return lhs.value == rhs.value; } + friend bool operator< (AddressV4 const& lhs, AddressV4 const& rhs) + { return lhs.value < rhs.value; } + + friend bool operator!= (AddressV4 const& lhs, AddressV4 const& rhs) + { return ! (lhs == rhs); } + friend bool operator> (AddressV4 const& lhs, AddressV4 const& rhs) + { return rhs < lhs; } + friend bool operator<= (AddressV4 const& lhs, AddressV4 const& rhs) + { return ! (lhs > rhs); } + friend bool operator>= (AddressV4 const& lhs, AddressV4 const& rhs) + { return ! (rhs > lhs); } + /** @} */ + + /** Array indexing for reading and writing indiviual octets. */ + /** @{ */ + template + class Proxy + { + public: + typedef typename std::conditional < + IsConst, uint32 const*, uint32*>::type Pointer; + + Proxy (int shift, Pointer value) + : m_shift (shift) + , m_value (value) + { + } + + operator uint8() const + { + return ((*m_value)>>m_shift) & 0xff; + } + + template + Proxy& operator= (IntegralType v) + { + (*m_value) = + ( (*m_value) & (~((0xff)< operator[] (std::size_t index) const; + Proxy operator[] (std::size_t index); + /** @{ */ + + /** The value as a 32 bit unsigned. */ + uint32 value; +}; + +//------------------------------------------------------------------------------ + +/** Returns `true` if this is a loopback address. */ +bool is_loopback (AddressV4 const& addr); + +/** Returns `true` if the address is unspecified. */ +bool is_unspecified (AddressV4 const& addr); + +/** Returns `true` if the address is a multicast address. */ +bool is_multicast (AddressV4 const& addr); + +/** Returns `true` if the address is a private unroutable address. */ +bool is_private (AddressV4 const& addr); + +/** Returns `true` if the address is a public routable address. */ +bool is_public (AddressV4 const& addr); + +//------------------------------------------------------------------------------ + +/** boost::hash support. */ +inline std::size_t hash_value (AddressV4 const& addr) + { return addr.value; } + +/** Returns the address represented as a string. */ +std::string to_string (AddressV4 const& addr); + +/** Output stream conversion. */ +template +OutputStream& operator<< (OutputStream& os, AddressV4 const& addr) + { return os << to_string (addr); } + +/** Input stream conversion. */ +std::istream& operator>> (std::istream& is, AddressV4& addr); + +} +} + +//------------------------------------------------------------------------------ + +namespace std { +template struct hash; +/** std::hash support. */ +template <> +struct hash +{ + std::size_t operator() (beast::IP::AddressV4 const& addr) const + { return hash_value (addr); } +}; +} + +#endif diff --git a/src/beast/beast/net/IPAddressV6.h b/src/beast/beast/net/IPAddressV6.h new file mode 100644 index 0000000000..12ed877fc0 --- /dev/null +++ b/src/beast/beast/net/IPAddressV6.h @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_IPADDRESSV6_H_INCLUDED +#define BEAST_NET_IPADDRESSV6_H_INCLUDED + +#include +#include +#include + +#include "../CStdInt.h" + +namespace beast { +namespace IP { + +/** Represents a version 4 IP address. */ +struct AddressV6 +{ + // VFALCO TODO + + /** Arithmetic comparison. */ + /** @{ */ + friend bool operator== (AddressV6 const&, AddressV6 const&) + { bassertfalse; return false; } + friend bool operator< (AddressV6 const&, AddressV6 const&) + { bassertfalse; return false; } + + friend bool operator!= (AddressV6 const& lhs, AddressV6 const& rhs) + { return ! (lhs == rhs); } + friend bool operator> (AddressV6 const& lhs, AddressV6 const& rhs) + { return rhs < lhs; } + friend bool operator<= (AddressV6 const& lhs, AddressV6 const& rhs) + { return ! (lhs > rhs); } + friend bool operator>= (AddressV6 const& lhs, AddressV6 const& rhs) + { return ! (rhs > lhs); } + /** @} */ +}; + +//------------------------------------------------------------------------------ + +/** Returns `true` if this is a loopback address. */ +bool is_loopback (AddressV6 const& addr); + +/** Returns `true` if the address is unspecified. */ +bool is_unspecified (AddressV6 const& addr); + +/** Returns `true` if the address is a multicast address. */ +bool is_multicast (AddressV6 const& addr); + +/** Returns `true` if the address is a private unroutable address. */ +bool is_private (AddressV6 const& addr); + +/** Returns `true` if the address is a public routable address. */ +bool is_public (AddressV6 const& addr); + +//------------------------------------------------------------------------------ + +/** boost::hash support. */ +inline std::size_t hash_value (AddressV6 const&) + { bassertfalse; return 0; } + +/** Returns the address represented as a string. */ +std::string to_string (AddressV6 const& addr); + +/** Output stream conversion. */ +template +OutputStream& operator<< (OutputStream& os, AddressV6 const& addr) + { return os << to_string (addr); } + +/** Input stream conversion. */ +std::istream& operator>> (std::istream& is, AddressV6& addr); + +} +} + +//------------------------------------------------------------------------------ + +namespace std { +template struct hash; +/** std::hash support. */ +template <> +struct hash +{ + std::size_t operator() (beast::IP::AddressV6 const& addr) const + { return hash_value (addr); } +}; +} + +#endif diff --git a/src/beast/beast/net/IPEndpoint.h b/src/beast/beast/net/IPEndpoint.h new file mode 100644 index 0000000000..033f98c131 --- /dev/null +++ b/src/beast/beast/net/IPEndpoint.h @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_IPENDPOINT_H_INCLUDED +#define BEAST_NET_IPENDPOINT_H_INCLUDED + +#include +#include + +#include "../CStdInt.h" +#include "IPAddress.h" + +namespace beast { +namespace IP { + +typedef uint16 Port; + +/** A version-independent IP address and port combination. */ +class Endpoint +{ +public: + /** Create an unspecified endpoint. */ + Endpoint (); + + /** Create an endpoint from the address and optional port. */ + explicit Endpoint (Address const& addr, Port port = 0); + + /** Create an Endpoint from a string. + If the port is omitted, the endpoint will have a zero port. + @return A pair with the endpoint, and bool set to `true` on success. + */ + static std::pair from_string_checked (std::string const& s); + static Endpoint from_string (std::string const& s); + static Endpoint from_string_altform (std::string const& s); + + /** Returns a string representing the endpoint. */ + std::string to_string () const; + + /** Returns the port number on the endpoint. */ + Port port () const + { return m_port; } + + /** Returns a new Endpoint with a different port. */ + Endpoint at_port (Port port) const + { return Endpoint (m_addr, port); } + + /** Returns the address portion of this endpoint. */ + Address const& address () const + { return m_addr; } + + /** Convenience accessors for the address part. */ + /** @{ */ + bool is_v4 () const + { return m_addr.is_v4(); } + bool is_v6 () const + { return m_addr.is_v6(); } + AddressV4 const& to_v4 () const + { return m_addr.to_v4 (); } + AddressV6 const& to_v6 () const + { return m_addr.to_v6 (); } + /** @} */ + + /** Arithmetic comparison. */ + /** @{ */ + friend bool operator== (Endpoint const& lhs, Endpoint const& rhs); + friend bool operator< (Endpoint const& lhs, Endpoint const& rhs); + + friend bool operator!= (Endpoint const& lhs, Endpoint const& rhs) + { return ! (lhs == rhs); } + friend bool operator> (Endpoint const& lhs, Endpoint const& rhs) + { return rhs < lhs; } + friend bool operator<= (Endpoint const& lhs, Endpoint const& rhs) + { return ! (lhs > rhs); } + friend bool operator>= (Endpoint const& lhs, Endpoint const& rhs) + { return ! (rhs > lhs); } + /** @} */ + +private: + Address m_addr; + Port m_port; +}; + +//------------------------------------------------------------------------------ + +// Properties + +/** Returns `true` if the endpoint is a loopback address. */ +inline bool is_loopback (Endpoint const& endpoint) + { return is_loopback (endpoint.address ()); } + +/** Returns `true` if the endpoint is unspecified. */ +inline bool is_unspecified (Endpoint const& endpoint) + { return is_unspecified (endpoint.address ()); } + +/** Returns `true` if the endpoint is a multicast address. */ +inline bool is_multicast (Endpoint const& endpoint) + { return is_multicast (endpoint.address ()); } + +/** Returns `true` if the endpoint is a private unroutable address. */ +inline bool is_private (Endpoint const& endpoint) + { return is_private (endpoint.address ()); } + +/** Returns `true` if the endpoint is a public routable address. */ +inline bool is_public (Endpoint const& endpoint) + { return is_public (endpoint.address ()); } + +//------------------------------------------------------------------------------ + +/** boost::hash support. */ +std::size_t hash_value (Endpoint const& endpoint); + +/** Returns the endpoint represented as a string. */ +inline std::string to_string (Endpoint const& endpoint) + { return endpoint.to_string(); } + +/** Output stream conversion. */ +template +OutputStream& operator<< (OutputStream& os, Endpoint const& endpoint) +{ + os << to_string (endpoint); + return os; +} + +/** Input stream conversion. */ +std::istream& operator>> (std::istream& is, Endpoint& endpoint); + +} +} + +//------------------------------------------------------------------------------ + +namespace std { +template struct hash; +/** std::hash support. */ +template <> +struct hash +{ + std::size_t operator() (beast::IP::Endpoint const& endpoint) const + { return hash_value (endpoint); } +}; +} + +#endif diff --git a/src/beast/beast/net/Net.cpp b/src/beast/beast/net/Net.cpp index a176d962f5..afac1339de 100644 --- a/src/beast/beast/net/Net.cpp +++ b/src/beast/beast/net/Net.cpp @@ -25,3 +25,8 @@ #include "impl/DynamicBuffer.cpp" #include "impl/IPAddress.cpp" +#include "impl/IPAddressV4.cpp" +#include "impl/IPAddressV6.cpp" +#include "impl/IPEndpoint.cpp" + + diff --git a/src/beast/beast/net/detail/Parse.h b/src/beast/beast/net/detail/Parse.h new file mode 100644 index 0000000000..415f068cbd --- /dev/null +++ b/src/beast/beast/net/detail/Parse.h @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_DETAIL_PARSE_H_INCLUDED +#define BEAST_NET_DETAIL_PARSE_H_INCLUDED + +#include +#include + +namespace beast { +namespace IP { + +namespace detail { + +/** Require and consume the specified character from the input. + @return `true` if the character matched. +*/ +template +bool expect (InputStream& is, char v) +{ + char c; + if (is.get(c) && v == c) + return true; + is.unget(); + is.setstate (std::ios_base::failbit); + return false; +} + +/** Used to disambiguate 8-bit integers from characters. */ +template +struct integer_holder +{ + IntType* pi; + explicit integer_holder (IntType& i) + : pi (&i) + { + } + template + IntType& operator= (OtherIntType o) const + { + *pi = o; + return *pi; + } +}; + +/** Parse 8-bit unsigned integer. */ +template +InputStream& operator>> (InputStream& is, integer_holder const& i) +{ + uint16 v; + is >> v; + if (! (v>=0 && v<=255)) + { + is.setstate (std::ios_base::failbit); + return is; + } + i = uint8(v); + return is; +} + +/** Free function for template argument deduction. */ +template +integer_holder integer (IntType& i) +{ + return integer_holder (i); +} + +} + +} +} + +#endif diff --git a/src/beast/beast/net/impl/IPAddress.cpp b/src/beast/beast/net/impl/IPAddress.cpp index 5190759f5b..c8314019fc 100644 --- a/src/beast/beast/net/impl/IPAddress.cpp +++ b/src/beast/beast/net/impl/IPAddress.cpp @@ -17,685 +17,236 @@ */ //============================================================================== +#include + #include "../IPAddress.h" +#include "../detail/Parse.h" namespace beast { +namespace IP { -IPAddress::V4::V4 () - : value (0) -{ -} - -IPAddress::V4::V4 (uint32 value_) - : value (value_) -{ -} - -IPAddress::V4::V4 (uint8 a, uint8 b, uint8 c, uint8 d) - : value ((a<<24)|(b<<16)|(c<<8)|d) -{ -} - -IPAddress::V4::V4 (V4 const& other) - : value (other.value) -{ -} - -IPAddress::V4& IPAddress::V4::operator= (V4 const& other) -{ - value = other.value; - return *this; -} - -IPAddress::V4 IPAddress::V4::localBroadcastAddress () -{ - return V4 (0xffffffff); -} - -IPAddress::V4 IPAddress::V4::broadcastAddress () const -{ - switch (getClass()) - { - case 'A': return V4 ((value&0xff000000)|0x00ffffff); - case 'B': return V4 ((value&0xffff0000)|0x0000ffff); - case 'C': return V4 ((value&0xffffff00)|0x000000ff); - default: - case 'D': - bassertfalse; - break; - } - return V4(); -} - -char IPAddress::V4::getClass () const -{ - static char const* table = "AAAABBCD"; - return table[(value&0xE0000000)>>29]; -} - -bool IPAddress::V4::isPublic () const -{ - return !isPrivate() && !isBroadcast() && !isMulticast(); -} - -bool IPAddress::V4::isPrivate () const -{ - return - ((value&0xff000000)==0x0a000000) || // Prefix /8, 10.##.#.# - ((value&0xfff00000)==0xac100000) || // Prefix /12 172.16.#.# - 172.31.#.# - ((value&0xffff0000)==0xc0a80000) || // Prefix /16 192.168.#.# - isLoopback(); -} - -bool IPAddress::V4::isBroadcast () const -{ - return (value == broadcastAddress().value); -} - -bool IPAddress::V4::isMulticast () const -{ - return getClass() == 'D'; -} - -bool IPAddress::V4::isLoopback () const -{ - return (value&0xff000000)==0x7f000000; -} - -IPAddress::V4::Proxy IPAddress::V4::operator[] (std::size_t index) const -{ - switch (index) - { - default: - bassertfalse; - case 0: return Proxy (24, &value); - case 1: return Proxy (16, &value); - case 2: return Proxy ( 8, &value); - case 3: return Proxy ( 0, &value); - }; -}; - -IPAddress::V4::Proxy IPAddress::V4::operator[] (std::size_t index) -{ - switch (index) - { - default: - bassertfalse; - case 0: return Proxy (24, &value); - case 1: return Proxy (16, &value); - case 2: return Proxy ( 8, &value); - case 3: return Proxy ( 0, &value); - }; -}; - -std::string IPAddress::V4::to_string () const -{ - std::string s; - s.reserve (15); - s.append (numberToString ((int)((*this)[0]))); s.push_back ('.'); - s.append (numberToString ((int)((*this)[1]))); s.push_back ('.'); - s.append (numberToString ((int)((*this)[2]))); s.push_back ('.'); - s.append (numberToString ((int)((*this)[3]))); - return s; -} - -IPAddress::V4::operator std::string () const -{ - return to_string(); -} - -//------------------------------------------------------------------------------ - -IPAddress::IPAddress () - : m_type (none) -{ -} - -IPAddress::IPAddress (V4 const& v4, uint16 port) +Address::Address () : m_type (ipv4) - , m_port (port) - , m_v4 (v4) { } -IPAddress::IPAddress (V6 const& v6, uint16 port) +Address::Address (AddressV4 const& addr) + : m_type (ipv4) + , m_v4 (addr) +{ +} + +Address::Address (AddressV6 const& addr) : m_type (ipv6) - , m_port (port) - , m_v6 (v6) + , m_v6 (addr) { } -IPAddress::IPAddress (IPAddress const& other) - : m_type (other.m_type) - , m_port (other.m_port) -{ - switch (m_type) - { - case ipv4: m_v4 = other.m_v4; break; - case ipv6: m_v6 = other.m_v6; break; - default: - case none: - break; - }; -} - -IPAddress& IPAddress::operator= (IPAddress const& other) -{ - m_type = other.m_type; - m_port = other.m_port; - switch (m_type) - { - case ipv4: m_v4 = other.m_v4; break; - case ipv6: m_v6 = other.m_v6; break; - default: - case none: - break; - }; - return *this; -} - -IPAddress IPAddress::from_string (std::string const& s) -{ - std::stringstream is (s); - IPAddress ep; - is >> ep; - if (! is.fail() && is.rdbuf()->in_avail() == 0) - return ep; - return IPAddress(); -} - -IPAddress& IPAddress::operator= (V4 const& address) +Address& Address::operator= (AddressV4 const& addr) { m_type = ipv4; - m_port = 0; - m_v4 = address; + m_v6 = AddressV6(); + m_v4 = addr; return *this; } -IPAddress& IPAddress::operator= (V6 const& address) +Address& Address::operator= (AddressV6 const& addr) { m_type = ipv6; - m_port = 0; - m_v6 = address; + m_v4 = AddressV4(); + m_v6 = addr; return *this; } -IPAddress IPAddress::withPort (uint16 port) const +std::pair Address::from_string (std::string const& s) { - switch (m_type) - { - case ipv4: return IPAddress (m_v4, port); - case ipv6: return IPAddress (m_v6, port); - default: - case none: - bassertfalse; - break; - }; - return IPAddress(); + std::stringstream is (s); + Address addr; + is >> addr; + if (! is.fail() && is.rdbuf()->in_avail() == 0) + return std::make_pair (addr, true); + return std::make_pair (Address (), false); } -bool IPAddress::empty () const +std::string Address::to_string () const { - return m_type == none; + return (is_v4 ()) + ? IP::to_string (to_v4()) + : IP::to_string (to_v6()); } -bool IPAddress::isNull () const -{ - return empty (); -} - -bool IPAddress::isNotNull () const -{ - return ! empty (); -} - -IPAddress::Type IPAddress::type () const -{ - return m_type; -} - -bool IPAddress::isV4 () const -{ - return m_type == ipv4; -} - -bool IPAddress::isV6 () const -{ - return m_type == ipv6; -} - -IPAddress::V4 const& IPAddress::v4 () const +AddressV4 const& Address::to_v4 () const { + if (m_type != ipv4) + throw std::bad_cast(); return m_v4; } -IPAddress::V6 const& IPAddress::v6 () const +AddressV6 const& Address::to_v6 () const { + if (m_type != ipv6) + throw std::bad_cast(); return m_v6; } -uint16 IPAddress::port () const +bool operator== (Address const& lhs, Address const& rhs) { - return m_port; -} - -bool IPAddress::isPublic () const -{ - switch (m_type) + if (lhs.is_v4 ()) { - case ipv4: return m_v4.isPublic(); - case ipv6: return m_v6.isPublic(); - default: - bassertfalse; - case none: - break; - }; - return false; -} - -bool IPAddress::isPrivate () const -{ - switch (m_type) - { - case ipv4: return m_v4.isPrivate(); - case ipv6: return m_v6.isPrivate(); - default: - bassertfalse; - case none: - break; - }; - return false; -} - -bool IPAddress::isBroadcast () const -{ - switch (m_type) - { - case ipv4: return m_v4.isBroadcast(); - case ipv6: return m_v6.isBroadcast(); - default: - bassertfalse; - case none: - break; - }; - return false; -} - -bool IPAddress::isMulticast () const -{ - switch (m_type) - { - case ipv4: return m_v4.isMulticast(); - case ipv6: return m_v6.isMulticast(); - default: - bassertfalse; - case none: - break; - }; - return false; -} - -bool IPAddress::isLoopback () const -{ - switch (m_type) - { - case ipv4: return m_v4.isLoopback(); - case ipv6: return m_v6.isLoopback(); - default: - bassertfalse; - case none: - break; - }; - return false; -} - -std::string IPAddress::to_string () const -{ - switch (m_type) - { - case ipv4: - { - std::string s (m_v4.to_string()); - if (m_port != 0) - { - s.append (":"); - s.append (numberToString (m_port)); - } - return s; - } - - case ipv6: - return m_v6.to_string(); - - default: - case none: - bassertfalse; - break; - }; - return std::string(); -} - -IPAddress::operator std::string () const -{ - return to_string(); -} - -//------------------------------------------------------------------------------ - -namespace parse -{ - -/** Require and consume the specified character from the input. - @return `true` if the character matched. -*/ -bool expect (std::istream& is, char v) -{ - char c; - if (is.get(c) && v == c) - return true; - - is.unget(); - is.setstate (std::ios_base::failbit); - return false; -} - -namespace detail -{ - -/** Used to disambiguate 8-bit integers from characters. */ -template -struct integer_holder -{ - IntType* pi; - explicit integer_holder (IntType& i) - : pi (&i) - { - } - template - IntType& operator= (OtherIntType o) const - { - *pi = o; - return *pi; - } -}; - -/** Parse 8-bit unsigned integer. */ -std::istream& operator>> (std::istream& is, integer_holder const& i) -{ - uint16 v; - is >> v; - if (! (v>=0 && v<=255)) - { - is.setstate (std::ios_base::failbit); - return is; - } - i = uint8(v); - return is; -} - -} - -/** Free function for template argument deduction. */ -template -detail::integer_holder integer (IntType& i) -{ - return detail::integer_holder (i); -} - -} - -/** Parse IPv4 address. */ -std::istream& operator>> (std::istream &is, IPAddress::V4& addr) -{ - uint8 octets [4]; - is >> parse::integer (octets [0]); - for (int i = 1; i < 4; ++i) - { - if (!is || !parse::expect (is, '.')) - return is; - is >> parse::integer (octets [i]); - if (!is) - return is; - } - addr = IPAddress::V4 (octets[0], octets[1], octets[2], octets[3]); - return is; -} - -/** Parse an IPAddress. - @note Currently only IPv4 addresses are supported. -*/ -std::istream& operator>> (std::istream &is, IPAddress& ep) -{ - IPAddress::V4 v4; - is >> v4; - if (is.fail()) - return is; - - if (is.rdbuf()->in_avail()>0) - { - char c; - is.get(c); - if (c != ':') - { - is.unget(); - ep = IPAddress (v4); - return is; - } - - uint16 port; - is >> port; - if (is.fail()) - return is; - - ep = IPAddress (v4, port); + if (rhs.is_v4 ()) + return lhs.to_v4() == rhs.to_v4(); } else { - ep = IPAddress (v4); + if (rhs.is_v6 ()) + return lhs.to_v6() == rhs.to_v6(); } + return false; +} + +bool operator< (Address const& lhs, Address const& rhs) +{ + if (lhs.m_type < rhs.m_type) + return true; + if (lhs.is_v4 ()) + return lhs.to_v4() < rhs.to_v4(); + return lhs.to_v6() < rhs.to_v6(); +} + +//------------------------------------------------------------------------------ + +bool is_loopback (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_loopback (addr.to_v4 ()) + : is_loopback (addr.to_v6 ()); +} + +bool is_unspecified (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_unspecified (addr.to_v4 ()) + : is_unspecified (addr.to_v6 ()); +} + +bool is_multicast (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_multicast (addr.to_v4 ()) + : is_multicast (addr.to_v6 ()); +} + +bool is_private (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_private (addr.to_v4 ()) + : is_private (addr.to_v6 ()); +} + +bool is_public (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_public (addr.to_v4 ()) + : is_public (addr.to_v6 ()); +} + +//------------------------------------------------------------------------------ + +std::size_t hash_value (Address const& addr) +{ + return (addr.is_v4 ()) + ? hash_value (addr.to_v4()) + : hash_value (addr.to_v6()); +} + +std::istream& operator>> (std::istream& is, Address& addr) +{ + // VFALCO TODO Support ipv6! + AddressV4 addrv4; + is >> addrv4; + addr = Address (addrv4); return is; } //------------------------------------------------------------------------------ -IPAddress IPAddress::from_string_altform (std::string const& s) -{ - // Accept the regular form if it parses - { - IPAddress ep (IPAddress::from_string (s)); - if (! ep.empty()) - return ep; - } - - // Now try the alt form - std::stringstream is (s); - - IPAddress::V4 v4; - is >> v4; - if (! is.fail()) - { - IPAddress ep (v4); - - if (is.rdbuf()->in_avail()>0) - { - if (! parse::expect (is, ' ')) - return IPAddress(); - - while (is.rdbuf()->in_avail()>0) - { - char c; - is.get(c); - if (c != ' ') - { - is.unget(); - break; - } - } - - uint16 port; - is >> port; - if (is.fail()) - return IPAddress(); - - return ep.withPort (port); - } - else - { - // Just an address with no port - return ep; - } - } - - // Could be V6 here... - - return IPAddress(); -} - -//------------------------------------------------------------------------------ - -bool operator== (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) - { return lhs.value == rhs.value; } - -bool operator< (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) - { return lhs.value < rhs.value; } - -bool operator!= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) - { return ! (lhs == rhs); } - -bool operator> (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) - { return rhs < lhs; } - -bool operator<= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) - { return ! (rhs < lhs); } - -bool operator>= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) - { return ! (lhs < rhs); } - -//------------------------------------------------------------------------------ - -bool operator== (IPAddress const& lhs, IPAddress const& rhs) -{ - if (lhs.type() != rhs.type()) - return false; - switch (lhs.type()) - { - case IPAddress::none: return true; - case IPAddress::ipv4: - if (lhs.v4() != rhs.v4()) - return false; - if (lhs.port() != rhs.port()) - return false; - return true; - case IPAddress::ipv6: - default: - bassertfalse; - } - return false; -} - -bool operator< (IPAddress const& lhs, IPAddress const& rhs) -{ - if (lhs.type() > rhs.type()) - return false; - if (lhs.type() < rhs.type()) - return true; - switch (lhs.type()) - { - case IPAddress::none: return true; - case IPAddress::ipv4: - if (lhs.v4() < rhs.v4()) - return true; - if (lhs.v4() > rhs.v4()) - return false; - return lhs.port() < rhs.port(); - case IPAddress::ipv6: - default: - bassertfalse; - } - return false; -} - -bool operator!= (IPAddress const& lhs, IPAddress const& rhs) - { return ! (lhs == rhs); } - -bool operator> (IPAddress const& lhs, IPAddress const& rhs) - { return rhs < lhs; } - -bool operator<= (IPAddress const& lhs, IPAddress const& rhs) - { return ! (rhs < lhs); } - -bool operator>= (IPAddress const& lhs, IPAddress const& rhs) - { return ! (lhs < rhs); } - -//------------------------------------------------------------------------------ - -std::ostream& operator<< (std::ostream &os, IPAddress::V4 const& addr) -{ - os << addr.to_string(); - return os; -} - -std::ostream& operator<< (std::ostream &os, IPAddress::V6 const& addr) -{ - os << addr.to_string(); - return os; -} - -std::ostream& operator<< (std::ostream &os, IPAddress const& ep) -{ - os << ep.to_string(); - return os; -} - -//------------------------------------------------------------------------------ - class IPAddressTests : public UnitTest { public: - bool parse (char const* text, IPAddress& ep) + void shouldParseV4 (std::string const& s, uint32 value) { - std::string input (text); - std::istringstream stream (input); - stream >> ep; - return !stream.fail(); + std::pair const result ( + AddressV4::from_string (s)); + + if (expect (result.second)) + { + if (expect (result.first.value == value)) + { + expect (to_string (result.first) == s); + } + } } - void shouldPass (char const* text) + void failParseV4 (std::string const& s) { - IPAddress ep; - expect (parse (text, ep)); - expect (ep.to_string() == std::string(text)); + unexpected (AddressV4::from_string (s).second); } - void shouldFail (char const* text) + void testAddressV4 () { - IPAddress ep; - unexpected (parse (text, ep)); + beginTestCase ("AddressV4"); + + expect (AddressV4().value == 0); + expect (is_unspecified (AddressV4())); + expect (AddressV4(0x01020304).value == 0x01020304); + expect (AddressV4(1, 2, 3, 4).value == 0x01020304); + + unexpected (is_unspecified (AddressV4(1, 2, 3, 4))); + + AddressV4 const v1 (1); + expect (AddressV4(v1).value == 1); + + { + AddressV4 v; + v = v1; + expect (v.value == v1.value); + } + + { + AddressV4 v; + v [0] = 1; + v [1] = 2; + v [2] = 3; + v [3] = 4; + expect (v.value == 0x01020304); + } + + expect (to_string (AddressV4(0x01020304)) == "1.2.3.4"); + + shouldParseV4 ("1.2.3.4", 0x01020304); + shouldParseV4 ("255.255.255.255", 0xffffffff); + shouldParseV4 ("0.0.0.0", 0); + + failParseV4 ("."); + failParseV4 (".."); + failParseV4 ("..."); + failParseV4 ("...."); + failParseV4 ("1"); + failParseV4 ("1."); + failParseV4 ("1.2"); + failParseV4 ("1.2."); + failParseV4 ("1.2.3"); + failParseV4 ("1.2.3."); + failParseV4 ("256.0.0.0"); + failParseV4 ("-1.2.3.4"); } - void testParse () + void testAddressV4Proxy () { - beginTestCase ("parse"); + beginTestCase ("AddressV4::Proxy"); - shouldPass ("0.0.0.0"); - shouldPass ("192.168.0.1"); - shouldPass ("168.127.149.132"); - shouldPass ("168.127.149.132:80"); - shouldPass ("168.127.149.132:54321"); - - shouldFail (""); - shouldFail ("255"); - shouldFail ("512"); - shouldFail ("1.2.3.256"); - shouldFail ("1.2.3:80"); - } - - void testV4Proxy () - { - beginTestCase("v4 proxy"); - - IPAddress::V4 v4 (10, 0, 0, 1); + AddressV4 v4 (10, 0, 0, 1); expect (v4[0]==10); expect (v4[1]==0); expect (v4[2]==0); @@ -711,43 +262,131 @@ public: expect (v4[3]==1); } - void testPrint () + //-------------------------------------------------------------------------- + + void testAddress () { - beginTestCase ("addresses"); + beginTestCase ("Address"); - IPAddress ep; + std::pair result ( + Address::from_string ("1.2.3.4")); + expect (result.second); + if (expect (result.first.is_v4 ())) + expect (result.first.to_v4() == AddressV4 (1, 2, 3, 4)); + } - ep = IPAddress(IPAddress::V4(127,0,0,1)).withPort (80); - expect (!ep.isPublic()); - expect ( ep.isPrivate()); - expect (!ep.isBroadcast()); - expect (!ep.isMulticast()); - expect ( ep.isLoopback()); - expect (ep.to_string() == "127.0.0.1:80"); + //-------------------------------------------------------------------------- - ep = IPAddress::V4(10,0,0,1); - expect ( ep.v4().getClass() == 'A'); - expect (!ep.isPublic()); - expect ( ep.isPrivate()); - expect (!ep.isBroadcast()); - expect (!ep.isMulticast()); - expect (!ep.isLoopback()); - expect (ep.to_string() == "10.0.0.1"); + void testEndpoint () + { + beginTestCase ("Endpoint"); - ep = IPAddress::V4(166,78,151,147); - expect ( ep.isPublic()); - expect (!ep.isPrivate()); - expect (!ep.isBroadcast()); - expect (!ep.isMulticast()); - expect (!ep.isLoopback()); - expect (ep.to_string() == "166.78.151.147"); + { + std::pair result ( + Endpoint::from_string_checked ("1.2.3.4")); + expect (result.second); + if (expect (result.first.address().is_v4 ())) + { + expect (result.first.address().to_v4() == + AddressV4 (1, 2, 3, 4)); + expect (result.first.port() == 0); + expect (to_string (result.first) == "1.2.3.4"); + } + } + + { + std::pair result ( + Endpoint::from_string_checked ("1.2.3.4:5")); + expect (result.second); + if (expect (result.first.address().is_v4 ())) + { + expect (result.first.address().to_v4() == + AddressV4 (1, 2, 3, 4)); + expect (result.first.port() == 5); + expect (to_string (result.first) == "1.2.3.4:5"); + } + } + + Endpoint ep; + + ep = Endpoint (AddressV4 (127,0,0,1), 80); + expect (! is_unspecified (ep)); + expect (! is_public (ep)); + expect ( is_private (ep)); + expect (! is_multicast (ep)); + expect ( is_loopback (ep)); + expect (to_string (ep) == "127.0.0.1:80"); + + ep = Endpoint (AddressV4 (10,0,0,1)); + expect (AddressV4::get_class (ep.to_v4()) == 'A'); + expect (! is_unspecified (ep)); + expect (! is_public (ep)); + expect ( is_private (ep)); + expect (! is_multicast (ep)); + expect (! is_loopback (ep)); + expect (to_string (ep) == "10.0.0.1"); + + ep = Endpoint (AddressV4 (166,78,151,147)); + expect (! is_unspecified (ep)); + expect ( is_public (ep)); + expect (! is_private (ep)); + expect (! is_multicast (ep)); + expect (! is_loopback (ep)); + expect (to_string (ep) == "166.78.151.147"); + } + + //-------------------------------------------------------------------------- + + template + bool parse (char const* text, T& t) + { + std::string input (text); + std::istringstream stream (input); + stream >> t; + return !stream.fail(); + } + + template + void shouldPass (char const* text) + { + T t; + expect (parse (text, t)); + expect (to_string (t) == std::string (text)); + } + + template + void shouldFail (char const* text) + { + T t; + unexpected (parse (text, t)); + } + + template + void testParse (char const* name) + { + beginTestCase (name); + + shouldPass ("0.0.0.0"); + shouldPass ("192.168.0.1"); + shouldPass ("168.127.149.132"); + shouldPass ("168.127.149.132:80"); + shouldPass ("168.127.149.132:54321"); + + shouldFail (""); + shouldFail ("255"); + shouldFail ("512"); + shouldFail ("1.2.3.256"); + shouldFail ("1.2.3:80"); } void runTest () { - testPrint(); - testParse(); - testV4Proxy(); + testAddressV4 (); + testAddressV4Proxy(); + testAddress (); + testEndpoint (); + + testParse ("Parse Endpoint"); } IPAddressTests () : UnitTest ("IPAddress", "beast") @@ -758,3 +397,4 @@ public: static IPAddressTests ipEndpointTests; } +} diff --git a/src/beast/beast/net/impl/IPAddressV4.cpp b/src/beast/beast/net/impl/IPAddressV4.cpp new file mode 100644 index 0000000000..a74daacffb --- /dev/null +++ b/src/beast/beast/net/impl/IPAddressV4.cpp @@ -0,0 +1,177 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../IPAddressV4.h" + +namespace beast { +namespace IP { + +AddressV4::AddressV4 () + : value (0) +{ +} + +AddressV4::AddressV4 (uint32 value_) + : value (value_) +{ +} + +AddressV4::AddressV4 (uint8 a, uint8 b, uint8 c, uint8 d) + : value ((a<<24)|(b<<16)|(c<<8)|d) +{ +} + +std::pair AddressV4::from_string (std::string const& s) +{ + std::stringstream is (s); + AddressV4 addr; + is >> addr; + if (! is.fail() && is.rdbuf()->in_avail() == 0) + return std::make_pair (addr, true); + return std::make_pair (AddressV4 (), false); +} + +AddressV4 AddressV4::broadcast (AddressV4 const& address) +{ + return broadcast (address, netmask (address)); +} + +AddressV4 AddressV4::broadcast ( + AddressV4 const& address, AddressV4 const& mask) +{ + return AddressV4 (address.value | (mask.value ^ 0xffffffff)); +} + +char AddressV4::get_class (AddressV4 const& addr) +{ + static char const* table = "AAAABBCD"; + return table [(addr.value & 0xE0000000) >> 29]; +} + +AddressV4 AddressV4::netmask (char address_class) +{ + switch (address_class) + { + case 'A': return AddressV4 (0xff000000); + case 'B': return AddressV4 (0xffff0000); + case 'C': return AddressV4 (0xffffff00); + case 'D': + default: + break; + } + return AddressV4 (0xffffffff); +} + +AddressV4 AddressV4::netmask (AddressV4 const& addr) +{ + return netmask (get_class (addr)); +} + +AddressV4::Proxy AddressV4::operator[] (std::size_t index) const +{ + switch (index) + { + default: + bassertfalse; + case 0: return Proxy (24, &value); + case 1: return Proxy (16, &value); + case 2: return Proxy ( 8, &value); + case 3: return Proxy ( 0, &value); + }; +}; + +AddressV4::Proxy AddressV4::operator[] (std::size_t index) +{ + switch (index) + { + default: + bassertfalse; + case 0: return Proxy (24, &value); + case 1: return Proxy (16, &value); + case 2: return Proxy ( 8, &value); + case 3: return Proxy ( 0, &value); + }; +}; + +//------------------------------------------------------------------------------ + +bool is_loopback (AddressV4 const& addr) +{ + return (addr.value & 0xff000000) == 0x7f000000; +} + +bool is_unspecified (AddressV4 const& addr) +{ + return addr.value == 0; +} + +bool is_multicast (AddressV4 const& addr) +{ + return (addr.value & 0xf0000000) == 0xe0000000; +} + +bool is_private (AddressV4 const& addr) +{ + return + ((addr.value & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.# + ((addr.value & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.# + ((addr.value & 0xffff0000) == 0xc0a80000) || // Prefix /16 192.168.#.# + is_loopback (addr); +} + +bool is_public (AddressV4 const& addr) +{ + return + ! is_private (addr) && + ! is_multicast (addr) && + (addr != AddressV4::broadcast (addr)); +} + +//------------------------------------------------------------------------------ + +std::string to_string (AddressV4 const& addr) +{ + std::string s; + s.reserve (15); + s = + std::to_string (addr[0]) + "." + + std::to_string (addr[1]) + "." + + std::to_string (addr[2]) + "." + + std::to_string (addr[3]); + return s; +} + +std::istream& operator>> (std::istream& is, AddressV4& addr) +{ + uint8 octet [4]; + is >> IP::detail::integer (octet [0]); + for (int i = 1; i < 4; ++i) + { + if (!is || !IP::detail::expect (is, '.')) + return is; + is >> IP::detail::integer (octet [i]); + if (!is) + return is; + } + addr = AddressV4 (octet[0], octet[1], octet[2], octet[3]); + return is; +} + +} +} diff --git a/src/beast/beast/net/impl/IPAddressV6.cpp b/src/beast/beast/net/impl/IPAddressV6.cpp new file mode 100644 index 0000000000..4c9baa31d4 --- /dev/null +++ b/src/beast/beast/net/impl/IPAddressV6.cpp @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../IPAddressV6.h" + +namespace beast { +namespace IP { + +//------------------------------------------------------------------------------ + +bool is_loopback (AddressV6 const&) +{ + // VFALCO TODO + bassertfalse; + return false; +} + +bool is_unspecified (AddressV6 const&) +{ + // VFALCO TODO + bassertfalse; + return false; +} + +bool is_multicast (AddressV6 const&) +{ + // VFALCO TODO + bassertfalse; + return false; +} + +bool is_private (AddressV6 const&) +{ + // VFALCO TODO + bassertfalse; + return false; +} + +bool is_public (AddressV6 const&) +{ + // VFALCO TODO + bassertfalse; + return false; +} + +//------------------------------------------------------------------------------ + +std::string to_string (AddressV6 const&) +{ + // VFALCO TODO + bassertfalse; + return ""; +} + +std::istream& operator>> (std::istream& is, AddressV6&) +{ + // VFALCO TODO + bassertfalse; + return is; +} + +} +} diff --git a/src/beast/beast/net/impl/IPEndpoint.cpp b/src/beast/beast/net/impl/IPEndpoint.cpp new file mode 100644 index 0000000000..a5815f8d71 --- /dev/null +++ b/src/beast/beast/net/impl/IPEndpoint.cpp @@ -0,0 +1,176 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace beast { +namespace IP { + +Endpoint::Endpoint () + : m_port (0) +{ +} + +Endpoint::Endpoint (Address const& addr, Port port) + : m_addr (addr) + , m_port (port) +{ +} + +std::pair Endpoint::from_string_checked (std::string const& s) +{ + std::stringstream is (s); + Endpoint endpoint; + is >> endpoint; + if (! is.fail() && is.rdbuf()->in_avail() == 0) + return std::make_pair (endpoint, true); + return std::make_pair (Endpoint (), false); +} + +Endpoint Endpoint::from_string (std::string const& s) +{ + std::pair const result ( + from_string_checked (s)); + if (result.second) + return result.first; + return Endpoint(); +} + +// VFALCO NOTE This is a hack to support legacy data format +// +Endpoint Endpoint::from_string_altform (std::string const& s) +{ + // Accept the regular form if it parses + { + Endpoint ep (Endpoint::from_string (s)); + if (! is_unspecified (ep)) + return ep; + } + + // Now try the alt form + std::stringstream is (s); + + AddressV4 v4; + is >> v4; + if (! is.fail()) + { + Endpoint ep (v4); + + if (is.rdbuf()->in_avail()>0) + { + if (! IP::detail::expect (is, ' ')) + return Endpoint(); + + while (is.rdbuf()->in_avail()>0) + { + char c; + is.get(c); + if (c != ' ') + { + is.unget(); + break; + } + } + + Port port; + is >> port; + if (is.fail()) + return Endpoint(); + + return ep.at_port (port); + } + else + { + // Just an address with no port + return ep; + } + } + + // Could be V6 here... + + return Endpoint(); +} + +std::string Endpoint::to_string () const +{ + std::string s (address ().to_string ()); + if (port() != 0) + s = s + ":" + std::to_string (port()); + return s; +} + +bool operator== (Endpoint const& lhs, Endpoint const& rhs) +{ + return lhs.address() == rhs.address() && + lhs.port() == rhs.port(); +} + +bool operator< (Endpoint const& lhs, Endpoint const& rhs) +{ + if (lhs.address() < rhs.address()) + return true; + if (lhs.address() > rhs.address()) + return false; + return lhs.port() < rhs.port(); +} + +//------------------------------------------------------------------------------ + +std::size_t hash_value (Endpoint const& endpoint) +{ + std::size_t seed (hash_value (endpoint.address ())); + // boost::hash_combine() + seed ^= (std::hash () (endpoint.port ())) + + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; +} + +std::istream& operator>> (std::istream& is, Endpoint& endpoint) +{ + // VFALCO TODO Support ipv6! + + Address addr; + is >> addr; + if (is.fail()) + return is; + + if (is.rdbuf()->in_avail()>0) + { + char c; + is.get(c); + if (c != ':') + { + is.unget(); + endpoint = Endpoint (addr); + return is; + } + + Port port; + is >> port; + if (is.fail()) + return is; + + endpoint = Endpoint (addr, port); + return is; + } + + endpoint = Endpoint (addr); + return is; +} + +} +} diff --git a/src/beast/config/BeastConfig.h b/src/beast/config/BeastConfig.h index ca4b091933..40d2da93f9 100644 --- a/src/beast/config/BeastConfig.h +++ b/src/beast/config/BeastConfig.h @@ -146,6 +146,4 @@ //#define BEAST_USE_BOOST_FEATURES 1 #endif -//------------------------------------------------------------------------------ - #endif