Files
boost_beast/beast/net/impl/IPAddress.cpp
T

717 lines
15 KiB
C++
Raw Normal View History

2013-09-19 00:00:34 -07:00
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
2013-10-18 15:30:13 -07:00
#include "../IPAddress.h"
2013-09-19 00:00:34 -07:00
2013-10-18 15:30:13 -07:00
namespace beast {
2013-09-19 00:00:34 -07:00
2013-10-18 15:30:13 -07:00
IPAddress::V4::V4 ()
2013-09-19 12:06:03 -07:00
: value (0)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::V4::V4 (uint32 value_)
2013-09-19 12:06:03 -07:00
: value (value_)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::V4::V4 (uint8 a, uint8 b, uint8 c, uint8 d)
2013-09-19 12:06:03 -07:00
: value ((a<<24)|(b<<16)|(c<<8)|d)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::V4::V4 (V4 const& other)
2013-09-19 12:06:03 -07:00
: value (other.value)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::V4& IPAddress::V4::operator= (V4 const& other)
2013-09-19 12:06:03 -07:00
{
value = other.value;
return *this;
}
2013-10-18 15:30:13 -07:00
IPAddress::V4 IPAddress::V4::localBroadcastAddress ()
2013-09-19 12:06:03 -07:00
{
return V4 (0xffffffff);
}
2013-10-18 15:30:13 -07:00
IPAddress::V4 IPAddress::V4::broadcastAddress () const
2013-09-19 12:06:03 -07:00
{
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();
}
2013-10-18 15:30:13 -07:00
char IPAddress::V4::getClass () const
2013-09-19 12:06:03 -07:00
{
static char const* table = "AAAABBCD";
return table[(value&0xE0000000)>>29];
}
2013-10-18 15:30:13 -07:00
bool IPAddress::V4::isPublic () const
2013-09-19 12:06:03 -07:00
{
return !isPrivate() && !isBroadcast() && !isMulticast();
}
2013-10-18 15:30:13 -07:00
bool IPAddress::V4::isPrivate () const
2013-09-19 12:06:03 -07:00
{
return
((value&0xff000000)==0x0a000000) || // Prefix /8, 10.##.#.#
((value&0xfff00000)==0xac100000) || // Prefix /12 172.16.#.# - 172.31.#.#
((value&0xffff0000)==0xc0a80000) || // Prefix /16 192.168.#.#
isLoopback();
}
2013-10-18 15:30:13 -07:00
bool IPAddress::V4::isBroadcast () const
2013-09-19 12:06:03 -07:00
{
return (value == broadcastAddress().value);
}
2013-10-18 15:30:13 -07:00
bool IPAddress::V4::isMulticast () const
2013-09-19 12:06:03 -07:00
{
return getClass() == 'D';
}
2013-10-18 15:30:13 -07:00
bool IPAddress::V4::isLoopback () const
2013-09-19 12:06:03 -07:00
{
return (value&0xff000000)==0x7f000000;
}
2013-10-18 15:30:13 -07:00
IPAddress::V4::Proxy <true> IPAddress::V4::operator[] (std::size_t index) const
2013-09-19 12:06:03 -07:00
{
switch (index)
{
default:
bassertfalse;
case 0: return Proxy <true> (24, &value);
case 1: return Proxy <true> (16, &value);
case 2: return Proxy <true> ( 8, &value);
case 3: return Proxy <true> ( 0, &value);
};
};
2013-10-18 15:30:13 -07:00
IPAddress::V4::Proxy <false> IPAddress::V4::operator[] (std::size_t index)
2013-09-19 12:06:03 -07:00
{
switch (index)
{
default:
bassertfalse;
case 0: return Proxy <false> (24, &value);
case 1: return Proxy <false> (16, &value);
case 2: return Proxy <false> ( 8, &value);
case 3: return Proxy <false> ( 0, &value);
};
};
2013-10-18 15:30:13 -07:00
std::string IPAddress::V4::to_string () const
2013-09-19 12:06:03 -07:00
{
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;
}
2013-10-18 15:30:13 -07:00
IPAddress::V4::operator std::string () const
2013-09-19 12:06:03 -07:00
{
return to_string();
}
//------------------------------------------------------------------------------
2013-10-18 15:30:13 -07:00
IPAddress::IPAddress ()
2013-09-19 12:06:03 -07:00
: m_type (none)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::IPAddress (V4 const& v4, uint16 port)
2013-09-19 12:06:03 -07:00
: m_type (ipv4)
, m_port (port)
, m_v4 (v4)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::IPAddress (V6 const& v6, uint16 port)
2013-09-19 12:06:03 -07:00
: m_type (ipv6)
, m_port (port)
, m_v6 (v6)
{
}
2013-10-18 15:30:13 -07:00
IPAddress::IPAddress (IPAddress const& other)
2013-09-19 12:06:03 -07:00
: 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;
};
}
2013-10-18 15:30:13 -07:00
IPAddress& IPAddress::operator= (IPAddress const& other)
2013-09-19 12:06:03 -07:00
{
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;
}
2013-10-18 15:30:13 -07:00
IPAddress IPAddress::from_string (std::string const& s)
2013-09-21 20:45:25 -07:00
{
2013-09-30 09:35:22 -07:00
std::stringstream is (s);
2013-10-18 15:30:13 -07:00
IPAddress ep;
2013-09-30 09:35:22 -07:00
is >> ep;
if (! is.fail() && is.rdbuf()->in_avail() == 0)
2013-09-21 20:45:25 -07:00
return ep;
2013-10-18 15:30:13 -07:00
return IPAddress();
2013-09-21 20:45:25 -07:00
}
2013-10-18 15:30:13 -07:00
IPAddress& IPAddress::operator= (V4 const& address)
2013-09-19 12:06:03 -07:00
{
m_type = ipv4;
m_port = 0;
m_v4 = address;
return *this;
}
2013-10-18 15:30:13 -07:00
IPAddress& IPAddress::operator= (V6 const& address)
2013-09-19 12:06:03 -07:00
{
m_type = ipv6;
m_port = 0;
m_v6 = address;
return *this;
}
2013-10-18 15:30:13 -07:00
IPAddress IPAddress::withPort (uint16 port) const
2013-09-19 12:06:03 -07:00
{
switch (m_type)
{
2013-10-18 15:30:13 -07:00
case ipv4: return IPAddress (m_v4, port);
case ipv6: return IPAddress (m_v6, port);
2013-09-19 12:06:03 -07:00
default:
case none:
bassertfalse;
break;
};
2013-10-18 15:30:13 -07:00
return IPAddress();
2013-09-19 12:06:03 -07:00
}
2013-10-18 15:30:13 -07:00
bool IPAddress::empty () const
2013-09-19 12:06:03 -07:00
{
return m_type == none;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isNull () const
2013-09-19 12:06:03 -07:00
{
return empty ();
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isNotNull () const
2013-09-19 12:06:03 -07:00
{
return ! empty ();
}
2013-10-18 15:30:13 -07:00
IPAddress::Type IPAddress::type () const
2013-09-19 12:06:03 -07:00
{
return m_type;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isV4 () const
2013-09-19 12:06:03 -07:00
{
return m_type == ipv4;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isV6 () const
2013-09-19 12:06:03 -07:00
{
return m_type == ipv6;
}
2013-10-18 15:30:13 -07:00
IPAddress::V4 const& IPAddress::v4 () const
2013-09-19 12:06:03 -07:00
{
return m_v4;
}
2013-10-18 15:30:13 -07:00
IPAddress::V6 const& IPAddress::v6 () const
2013-09-19 12:06:03 -07:00
{
return m_v6;
}
2013-10-18 15:30:13 -07:00
uint16 IPAddress::port () const
2013-09-19 12:06:03 -07:00
{
return m_port;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isPublic () const
2013-09-19 12:06:03 -07:00
{
switch (m_type)
{
case ipv4: return m_v4.isPublic();
case ipv6: return m_v6.isPublic();
default:
bassertfalse;
case none:
break;
};
return false;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isPrivate () const
2013-09-19 12:06:03 -07:00
{
switch (m_type)
{
case ipv4: return m_v4.isPrivate();
case ipv6: return m_v6.isPrivate();
default:
bassertfalse;
case none:
break;
};
return false;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isBroadcast () const
2013-09-19 12:06:03 -07:00
{
switch (m_type)
{
case ipv4: return m_v4.isBroadcast();
case ipv6: return m_v6.isBroadcast();
default:
bassertfalse;
case none:
break;
};
return false;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isMulticast () const
2013-09-19 12:06:03 -07:00
{
switch (m_type)
{
case ipv4: return m_v4.isMulticast();
case ipv6: return m_v6.isMulticast();
default:
bassertfalse;
case none:
break;
};
return false;
}
2013-10-18 15:30:13 -07:00
bool IPAddress::isLoopback () const
2013-09-19 12:06:03 -07:00
{
switch (m_type)
{
case ipv4: return m_v4.isLoopback();
case ipv6: return m_v6.isLoopback();
default:
bassertfalse;
case none:
break;
};
return false;
}
2013-10-18 15:30:13 -07:00
std::string IPAddress::to_string () const
2013-09-19 12:06:03 -07:00
{
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();
}
2013-10-18 15:30:13 -07:00
IPAddress::operator std::string () const
2013-09-19 12:06:03 -07:00
{
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 <typename IntType>
struct integer_holder
{
IntType* pi;
explicit integer_holder (IntType& i)
: pi (&i)
{
}
template <typename OtherIntType>
IntType& operator= (OtherIntType o) const
{
*pi = o;
return *pi;
}
};
/** Parse 8-bit unsigned integer. */
std::istream& operator>> (std::istream& is, integer_holder <uint8> 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 <typename IntType>
detail::integer_holder <IntType> integer (IntType& i)
{
return detail::integer_holder <IntType> (i);
}
}
/** Parse IPv4 address. */
2013-10-18 15:30:13 -07:00
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;
}
2013-10-18 15:30:13 -07:00
addr = IPAddress::V4 (octets[0], octets[1], octets[2], octets[3]);
return is;
}
2013-10-18 15:30:13 -07:00
/** Parse an IPAddress.
@note Currently only IPv4 addresses are supported.
*/
2013-10-18 15:30:13 -07:00
std::istream& operator>> (std::istream &is, IPAddress& ep)
{
2013-10-18 15:30:13 -07:00
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();
2013-10-18 15:30:13 -07:00
ep = IPAddress (v4);
return is;
}
uint16 port;
is >> port;
if (is.fail())
return is;
2013-10-18 15:30:13 -07:00
ep = IPAddress (v4, port);
}
else
{
2013-10-18 15:30:13 -07:00
ep = IPAddress (v4);
}
return is;
}
//------------------------------------------------------------------------------
2013-10-18 15:30:13 -07:00
IPAddress IPAddress::from_string_altform (std::string const& s)
{
// Accept the regular form if it parses
{
2013-10-18 15:30:13 -07:00
IPAddress ep (IPAddress::from_string (s));
if (! ep.empty())
return ep;
}
// Now try the alt form
std::stringstream is (s);
2013-10-18 15:30:13 -07:00
IPAddress::V4 v4;
is >> v4;
if (! is.fail())
{
2013-10-18 15:30:13 -07:00
IPAddress ep (v4);
if (is.rdbuf()->in_avail()>0)
{
if (! parse::expect (is, ' '))
2013-10-18 15:30:13 -07:00
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())
2013-10-18 15:30:13 -07:00
return IPAddress();
return ep.withPort (port);
}
else
{
// Just an address with no port
return ep;
}
}
// Could be V6 here...
2013-10-18 15:30:13 -07:00
return IPAddress();
}
//------------------------------------------------------------------------------
2013-10-18 15:30:13 -07:00
int compare (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs)
2013-09-21 20:45:25 -07:00
{
if (lhs.value < rhs.value)
return -1;
else if (lhs.value > rhs.value)
return 1;
return 0;
}
2013-10-18 15:30:13 -07:00
bool operator== (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) { return compare (lhs, rhs) == 0; }
bool operator!= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) { return compare (lhs, rhs) != 0; }
bool operator< (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) { return compare (lhs, rhs) < 0; }
bool operator<= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) { return compare (lhs, rhs) <= 0; }
bool operator> (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) { return compare (lhs, rhs) > 0; }
bool operator>= (IPAddress::V4 const& lhs, IPAddress::V4 const& rhs) { return compare (lhs, rhs) >= 0; }
2013-09-21 20:45:25 -07:00
2013-10-18 15:30:13 -07:00
static int type_compare (IPAddress const& lhs, IPAddress const& rhs)
2013-09-21 20:45:25 -07:00
{
if (lhs.type() < rhs.type())
return -1;
else if (lhs.type() > rhs.type())
return 1;
return 0;
}
2013-10-18 15:30:13 -07:00
int compare (IPAddress const& lhs, IPAddress const& rhs)
2013-09-21 20:45:25 -07:00
{
int const tc (type_compare (lhs, rhs));
if (tc < 0)
return -1;
else if (tc > 0)
return 1;
switch (lhs.type())
{
2013-10-18 15:30:13 -07:00
case IPAddress::none: return 0;
case IPAddress::ipv4: return compare (lhs.v4(), rhs.v4());
2013-09-21 20:45:25 -07:00
default:
2013-10-18 15:30:13 -07:00
case IPAddress::ipv6:
2013-09-21 20:45:25 -07:00
break;
};
bassertfalse;
return 0;
}
2013-10-18 15:30:13 -07:00
bool operator== (IPAddress const& lhs, IPAddress const& rhs) { return compare (lhs, rhs) == 0; }
bool operator!= (IPAddress const& lhs, IPAddress const& rhs) { return compare (lhs, rhs) != 0; }
bool operator< (IPAddress const& lhs, IPAddress const& rhs) { return compare (lhs, rhs) < 0; }
bool operator<= (IPAddress const& lhs, IPAddress const& rhs) { return compare (lhs, rhs) <= 0; }
bool operator> (IPAddress const& lhs, IPAddress const& rhs) { return compare (lhs, rhs) > 0; }
bool operator>= (IPAddress const& lhs, IPAddress const& rhs) { return compare (lhs, rhs) >= 0; }
2013-09-21 20:45:25 -07:00
2013-10-18 15:30:13 -07:00
std::ostream& operator<< (std::ostream &os, IPAddress::V4 const& addr)
2013-09-21 20:45:25 -07:00
{
os << addr.to_string();
return os;
}
2013-10-18 15:30:13 -07:00
std::ostream& operator<< (std::ostream &os, IPAddress::V6 const& addr)
2013-09-21 20:45:25 -07:00
{
os << addr.to_string();
return os;
}
2013-10-18 15:30:13 -07:00
std::ostream& operator<< (std::ostream &os, IPAddress const& ep)
2013-09-21 20:45:25 -07:00
{
os << ep.to_string();
return os;
}
//------------------------------------------------------------------------------
2013-10-18 15:30:13 -07:00
class IPAddressTests : public UnitTest
2013-09-19 00:00:34 -07:00
{
public:
2013-10-18 15:30:13 -07:00
bool parse (char const* text, IPAddress& ep)
{
std::string input (text);
std::istringstream stream (input);
stream >> ep;
return !stream.fail();
}
void shouldPass (char const* text)
{
2013-10-18 15:30:13 -07:00
IPAddress ep;
expect (parse (text, ep));
expect (ep.to_string() == std::string(text));
}
void shouldFail (char const* text)
{
2013-10-18 15:30:13 -07:00
IPAddress ep;
unexpected (parse (text, ep));
}
void testParse ()
{
beginTestCase ("parse");
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");
}
2013-09-19 00:00:34 -07:00
void testPrint ()
{
beginTestCase ("addresses");
2013-10-18 15:30:13 -07:00
IPAddress ep;
2013-09-19 00:00:34 -07:00
2013-10-18 15:30:13 -07:00
ep = IPAddress(IPAddress::V4(127,0,0,1)).withPort (80);
2013-09-19 00:00:34 -07:00
expect (!ep.isPublic());
expect ( ep.isPrivate());
expect (!ep.isBroadcast());
expect (!ep.isMulticast());
expect ( ep.isLoopback());
2013-09-19 00:00:34 -07:00
expect (ep.to_string() == "127.0.0.1:80");
2013-10-18 15:30:13 -07:00
ep = IPAddress::V4(10,0,0,1);
2013-09-19 00:00:34 -07:00
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");
2013-10-18 15:30:13 -07:00
ep = IPAddress::V4(166,78,151,147);
2013-09-19 00:00:34 -07:00
expect ( ep.isPublic());
expect (!ep.isPrivate());
expect (!ep.isBroadcast());
expect (!ep.isMulticast());
expect (!ep.isLoopback());
expect (ep.to_string() == "166.78.151.147");
}
void runTest ()
{
testPrint();
testParse();
2013-09-19 00:00:34 -07:00
}
2013-10-18 15:30:13 -07:00
IPAddressTests () : UnitTest ("IPAddress", "beast")
2013-09-19 00:00:34 -07:00
{
}
};
2013-10-18 15:30:13 -07:00
static IPAddressTests ipEndpointTests;
2013-09-19 00:00:34 -07:00
}