Add new network_v4 class.
diff --git a/asio/include/Makefile.am b/asio/include/Makefile.am
index ad3feb1..79ad920 100644
--- a/asio/include/Makefile.am
+++ b/asio/include/Makefile.am
@@ -321,6 +321,8 @@
 	asio/io_service_strand.hpp \
 	asio/io_service.hpp \
 	asio/ip/address.hpp \
+	asio/ip/address_iterator_v4.hpp \
+	asio/ip/address_range_v4.hpp \
 	asio/ip/address_v4.hpp \
 	asio/ip/address_v6.hpp \
 	asio/ip/bad_address_cast.hpp \
@@ -342,7 +344,10 @@
 	asio/ip/impl/address_v6.ipp \
 	asio/ip/impl/basic_endpoint.hpp \
 	asio/ip/impl/host_name.ipp \
+	asio/ip/impl/network_v4.hpp \
+	asio/ip/impl/network_v4.ipp \
 	asio/ip/multicast.hpp \
+	asio/ip/network_v4.hpp \
 	asio/ip/resolver_query_base.hpp \
 	asio/ip/resolver_service.hpp \
 	asio/ip/tcp.hpp \
diff --git a/asio/include/asio.hpp b/asio/include/asio.hpp
index 51deb11..3811c3d 100644
--- a/asio/include/asio.hpp
+++ b/asio/include/asio.hpp
@@ -64,6 +64,8 @@
 #include "asio/io_service.hpp"
 #include "asio/io_service_strand.hpp"
 #include "asio/ip/address.hpp"
+#include "asio/ip/address_iterator_v4.hpp"
+#include "asio/ip/address_range_v4.hpp"
 #include "asio/ip/address_v4.hpp"
 #include "asio/ip/address_v6.hpp"
 #include "asio/ip/bad_address_cast.hpp"
diff --git a/asio/include/asio/impl/src.hpp b/asio/include/asio/impl/src.hpp
index df5f886..3321103 100644
--- a/asio/include/asio/impl/src.hpp
+++ b/asio/include/asio/impl/src.hpp
@@ -73,6 +73,7 @@
 #include "asio/ip/impl/address_v4.ipp"
 #include "asio/ip/impl/address_v6.ipp"
 #include "asio/ip/impl/host_name.ipp"
+#include "asio/ip/impl/network_v4.ipp"
 #include "asio/ip/detail/impl/endpoint.ipp"
 #include "asio/local/detail/impl/endpoint.ipp"
 
diff --git a/asio/include/asio/ip/address_iterator_v4.hpp b/asio/include/asio/ip/address_iterator_v4.hpp
new file mode 100644
index 0000000..aac7ce4
--- /dev/null
+++ b/asio/include/asio/ip/address_iterator_v4.hpp
@@ -0,0 +1,156 @@
+//
+// ip/address_iterator_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_ADDRESS_ITERATOR_V4_HPP
+#define ASIO_IP_ADDRESS_ITERATOR_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An input iterator that can be used for traversing IPv4 addresses.
+/**
+ * In addition to satisfying the input iterator requirements, this iterator
+ * also supports decrement.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+class address_iterator_v4
+{
+public:
+  /// The type of the elements pointed to by the iterator.
+  typedef address_v4 value_type;
+
+  /// Distance between two iterators.
+  typedef std::ptrdiff_t difference_type;
+
+  /// The type of a pointer to an element pointed to by the iterator.
+  typedef const address_v4* pointer;
+
+  /// The type of a reference to an element pointed to by the iterator.
+  typedef const address_v4& reference;
+
+  /// Denotes that the iterator satisfies the input iterator requirements.
+  typedef std::input_iterator_tag iterator_category;
+
+  /// Construct an iterator that points to the specified address.
+  address_iterator_v4(const address_v4& addr) ASIO_NOEXCEPT
+    : address_(addr)
+  {
+  }
+
+  /// Copy constructor.
+  address_iterator_v4(const address_iterator_v4& other) ASIO_NOEXCEPT
+    : address_(other.address_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  address_iterator_v4(address_iterator_v4&& other) ASIO_NOEXCEPT
+    : address_(ASIO_MOVE_CAST(address_v4)(other.address_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assignment operator.
+  address_iterator_v4& operator=(
+      const address_iterator_v4& other) ASIO_NOEXCEPT
+  {
+    address_ = other.address_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move assignment operator.
+  address_iterator_v4& operator=(
+      address_iterator_v4&& other) ASIO_NOEXCEPT
+  {
+    address_ = ASIO_MOVE_CAST(address_v4)(other.address_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Dereference the iterator.
+  const address_v4& operator*() const ASIO_NOEXCEPT
+  {
+    return address_;
+  }
+
+  /// Dereference the iterator.
+  const address_v4* operator->() const ASIO_NOEXCEPT
+  {
+    return &address_;
+  }
+
+  /// Pre-increment operator.
+  address_iterator_v4& operator++() ASIO_NOEXCEPT
+  {
+    address_ = address_v4((address_.to_ulong() + 1) & 0xFFFFFFFF);
+    return *this;
+  }
+
+  /// Post-increment operator.
+  address_iterator_v4 operator++(int) ASIO_NOEXCEPT
+  {
+    address_iterator_v4 tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  /// Pre-decrement operator.
+  address_iterator_v4& operator--() ASIO_NOEXCEPT
+  {
+    address_ = address_v4((address_.to_ulong() - 1) & 0xFFFFFFFF);
+    return *this;
+  }
+
+  /// Post-decrement operator.
+  address_iterator_v4 operator--(int)
+  {
+    address_iterator_v4 tmp(*this);
+    --*this;
+    return tmp;
+  }
+
+  /// Compare two addresses for equality.
+  friend bool operator==(const address_iterator_v4& a,
+      const address_iterator_v4& b)
+  {
+    return a.address_ == b.address_;
+  }
+
+  /// Compare two addresses for inequality.
+  friend bool operator!=(const address_iterator_v4& a,
+      const address_iterator_v4& b)
+  {
+    return a.address_ != b.address_;
+  }
+
+private:
+  address_v4 address_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_ITERATOR_V4_HPP
diff --git a/asio/include/asio/ip/address_range_v4.hpp b/asio/include/asio/ip/address_range_v4.hpp
new file mode 100644
index 0000000..1998a0b
--- /dev/null
+++ b/asio/include/asio/ip/address_range_v4.hpp
@@ -0,0 +1,125 @@
+//
+// ip/address_range_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_ADDRESS_RANGE_V4_HPP
+#define ASIO_IP_ADDRESS_RANGE_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/ip/address_iterator_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Represents a range of IPv4 addresses.
+/**
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+class address_range_v4
+{
+public:
+  /// The type of an iterator that points into the range.
+  typedef address_iterator_v4 iterator;
+
+  /// Construct an empty range.
+  address_range_v4() ASIO_NOEXCEPT;
+
+  /// Construct an range that represents the given range of addresses.
+  explicit address_range_v4(const address_iterator_v4& first,
+      const address_iterator_v4& last) ASIO_NOEXCEPT
+    : begin_(first),
+      end_(last)
+  {
+  }
+
+  /// Copy constructor.
+  address_range_v4(const address_range_v4& other) ASIO_NOEXCEPT
+    : begin_(other.begin_),
+      end_(other.end_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  address_range_v4(address_range_v4&& other) ASIO_NOEXCEPT
+    : begin_(ASIO_MOVE_CAST(address_iterator_v4)(other.begin_)),
+      end_(ASIO_MOVE_CAST(address_iterator_v4)(other.end_))
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assignment operator.
+  address_range_v4& operator=(
+      const address_range_v4& other) ASIO_NOEXCEPT
+  {
+    begin_ = other.begin_;
+    end_ = other.end_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move assignment operator.
+  address_range_v4& operator=(
+      address_range_v4&& other) ASIO_NOEXCEPT
+  {
+    begin_ = ASIO_MOVE_CAST(address_iterator_v4)(other.begin_);
+    end_ = ASIO_MOVE_CAST(address_iterator_v4)(other.end_);
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Obtain an iterator that points to the start of the range.
+  iterator begin() const ASIO_NOEXCEPT
+  {
+    return begin_;
+  }
+
+  /// Obtain an iterator that points to the end of the range.
+  iterator end() const ASIO_NOEXCEPT
+  {
+    return end_;
+  }
+
+  /// Determine whether the range is empty.
+  bool empty() const ASIO_NOEXCEPT
+  {
+    return size() == 0;
+  }
+
+  /// Return the size of the range.
+  std::size_t size() const ASIO_NOEXCEPT
+  {
+    return end_->to_ulong() - begin_->to_ulong();
+  }
+
+  /// Find an address in the range.
+  iterator find(const address_v4& addr) const ASIO_NOEXCEPT
+  {
+    return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_;
+  }
+
+private:
+  address_iterator_v4 begin_;
+  address_iterator_v4 end_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_RANGE_V4_HPP
diff --git a/asio/include/asio/ip/impl/network_v4.hpp b/asio/include/asio/ip/impl/network_v4.hpp
new file mode 100644
index 0000000..762ebbf
--- /dev/null
+++ b/asio/include/asio/ip/impl/network_v4.hpp
@@ -0,0 +1,53 @@
+//
+// ip/impl/network_v4.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_NETWORK_V4_HPP
+#define ASIO_IP_IMPL_NETWORK_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+#include "asio/detail/throw_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const network_v4& addr)
+{
+  asio::error_code ec;
+  std::string s = addr.to_string(ec);
+  if (ec)
+  {
+    if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)
+      asio::detail::throw_error(ec);
+    else
+      os.setstate(std::basic_ostream<Elem, Traits>::failbit);
+  }
+  else
+    for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+      os << os.widen(*i);
+  return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+#endif // ASIO_IP_IMPL_NETWORK_V4_HPP
diff --git a/asio/include/asio/ip/impl/network_v4.ipp b/asio/include/asio/ip/impl/network_v4.ipp
new file mode 100644
index 0000000..7c36ec0
--- /dev/null
+++ b/asio/include/asio/ip/impl/network_v4.ipp
@@ -0,0 +1,190 @@
+//
+// ip/impl/network_v4.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_IMPL_NETWORK_V4_IPP
+#define ASIO_IP_IMPL_NETWORK_V4_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <stdexcept>
+#include "asio/error.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/ip/network_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+network_v4::network_v4(const address_v4& addr, unsigned short prefix_len)
+  : address_(addr),
+    prefix_length_(prefix_len)
+{
+  if (prefix_len > 32)
+  {
+    std::out_of_range ex("prefix length too large");
+    asio::detail::throw_exception(ex);
+  }
+}
+
+network_v4::network_v4(const address_v4& addr, const address_v4& mask)
+  : address_(addr),
+    prefix_length_(0)
+{
+  address_v4::bytes_type mask_bytes = mask.to_bytes();
+  bool finished = false;
+  for (std::size_t i = 0; i < mask_bytes.size(); ++i)
+  {
+    if (finished)
+    {
+      if (mask_bytes[i])
+      {
+        std::invalid_argument ex("non-contiguous netmask");
+        asio::detail::throw_exception(ex);
+      }
+      continue;
+    }
+    else
+    {
+      switch (mask_bytes[i])
+      {
+      case 255:
+        prefix_length_ += 8;
+        break;
+      case 254: // prefix_length_ += 7
+        prefix_length_ += 1;
+      case 252: // prefix_length_ += 6
+        prefix_length_ += 1;
+      case 248: // prefix_length_ += 5
+        prefix_length_ += 1;
+      case 240: // prefix_length_ += 4
+        prefix_length_ += 1;
+      case 224: // prefix_length_ += 3
+        prefix_length_ += 1;
+      case 192: // prefix_length_ += 2
+        prefix_length_ += 1;
+      case 128: // prefix_length_ += 1
+        prefix_length_ += 1;
+      case 0:   // nbits += 0
+        finished = true;
+        break;
+      default:
+        std::out_of_range ex("non-contiguous netmask");
+        asio::detail::throw_exception(ex);
+      }
+    }
+  }
+}
+
+address_v4 network_v4::netmask() const ASIO_NOEXCEPT
+{
+  uint32_t nmbits = 0xffffffff;
+  if (prefix_length_ == 0)
+    nmbits = 0;
+  else
+    nmbits = nmbits << (32 - prefix_length_);
+  return address_v4(nmbits);
+}
+
+address_range_v4 network_v4::hosts() const ASIO_NOEXCEPT
+{
+  return is_host()
+    ? address_range_v4(address_, address_v4(address_.to_ulong() + 1))
+    : address_range_v4(address_v4(network().to_ulong() + 1), broadcast());
+}
+
+bool network_v4::is_subnet_of(const network_v4& other) const
+{
+  if (other.prefix_length_ >= prefix_length_)
+    return false; // Only real subsets are allowed.
+  const network_v4 me(address_, other.prefix_length_);
+  return other.canonical() == me.canonical();
+}
+
+std::string network_v4::to_string() const
+{
+  asio::error_code ec;
+  std::string addr = to_string(ec);
+  asio::detail::throw_error(ec);
+  return addr;
+}
+
+std::string network_v4::to_string(asio::error_code& ec) const
+{
+  ec = asio::error_code();
+  char prefix_len[16];
+#if defined(ASIO_HAS_SECURE_RTL)
+  sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_);
+#else // defined(ASIO_HAS_SECURE_RTL)
+  sprintf(prefix_len, "/%u", prefix_length_);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+  return address_.to_string() + prefix_len;
+}
+
+network_v4 make_network_v4(const char* str)
+{
+  return make_network_v4(std::string(str));
+}
+
+network_v4 make_network_v4(const char* str, asio::error_code& ec)
+{
+  return make_network_v4(std::string(str), ec);
+}
+
+network_v4 make_network_v4(const std::string& str)
+{
+  asio::error_code ec;
+  network_v4 net = make_network_v4(str, ec);
+  asio::detail::throw_error(ec);
+  return net;
+}
+
+network_v4 make_network_v4(const std::string& str,
+    asio::error_code& ec)
+{
+  std::string::size_type pos = str.find_first_of("/");
+
+  if (pos == std::string::npos)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  if (pos == str.size() - 1)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  std::string::size_type end = str.find_first_not_of("0123456789", pos+1);
+  if (end != std::string::npos)
+  {
+    ec = asio::error::invalid_argument;
+    return network_v4();
+  }
+
+  return network_v4(make_address_v4(str.substr(0, pos)),
+      std::atoi(str.substr(pos + 1).c_str()));
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_IMPL_NETWORK_V4_IPP
diff --git a/asio/include/asio/ip/network_v4.hpp b/asio/include/asio/ip/network_v4.hpp
new file mode 100644
index 0000000..e4efd8f
--- /dev/null
+++ b/asio/include/asio/ip/network_v4.hpp
@@ -0,0 +1,236 @@
+//
+// ip/network_v4.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_NETWORK_V4_HPP
+#define ASIO_IP_NETWORK_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <string>
+#include "asio/error_code.hpp"
+#include "asio/ip/address_range_v4.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Represents an IPv4 network.
+/**
+ * The asio::ip::network_v4 class provides the ability to use and
+ * manipulate IP version 4 networks.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+class network_v4
+{
+public:
+  /// Default constructor.
+  network_v4() ASIO_NOEXCEPT
+    : address_(),
+      prefix_length_(0)
+  {
+  }
+  
+  /// Construct a network based on the specified address and prefix length.
+  ASIO_DECL network_v4(const address_v4& addr,
+      unsigned short prefix_len);
+  
+  /// Construct network based on the specified address and netmask.
+  ASIO_DECL network_v4(const address_v4& addr,
+      const address_v4& mask);
+  
+  /// Copy constructor.
+  network_v4(const network_v4& other) ASIO_NOEXCEPT
+    : address_(other.address_),
+      prefix_length_(other.prefix_length_)
+  {
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move constructor.
+  network_v4(network_v4&& other) ASIO_NOEXCEPT
+    : address_(ASIO_MOVE_CAST(address_v4)(other.address_)),
+      prefix_length_(other.prefix_length_)
+  {
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Assign from another network.
+  network_v4& operator=(const network_v4& other) ASIO_NOEXCEPT
+  {
+    address_ = other.address_;
+    prefix_length_ = other.prefix_length_;
+    return *this;
+  }
+
+#if defined(ASIO_HAS_MOVE)
+  /// Move-assign from another network.
+  network_v4& operator=(network_v4&& other) ASIO_NOEXCEPT
+  {
+    address_ = ASIO_MOVE_CAST(address_v4)(other.address_);
+    prefix_length_ = other.prefix_length_;
+    return *this;
+  }
+#endif // defined(ASIO_HAS_MOVE)
+
+  /// Obtain the address object specified when the network object was created.
+  address_v4 address() const ASIO_NOEXCEPT
+  {
+    return address_;
+  }
+
+  /// Obtain the prefix length that was specified when the network object was
+  /// created.
+  unsigned short prefix_length() const ASIO_NOEXCEPT
+  {
+    return prefix_length_;
+  }
+
+  /// Obtain the netmask that was specified when the network object was created.
+  ASIO_DECL address_v4 netmask() const ASIO_NOEXCEPT;
+
+  /// Obtain an address object that represents the network address.
+  address_v4 network() const ASIO_NOEXCEPT
+  {
+    return address_v4(address_.to_ulong() & netmask().to_ulong());
+  }
+  
+  /// Obtain an address object that represents the network's broadcast address.
+  address_v4 broadcast() const ASIO_NOEXCEPT
+  {
+    return address_v4::broadcast(network(), netmask());
+  }
+
+  /// Obtain an address range corresponding to the hosts in the network.
+  ASIO_DECL address_range_v4 hosts() const ASIO_NOEXCEPT;
+
+  /// Obtain the true network address, omitting any host bits.
+  network_v4 canonical() const ASIO_NOEXCEPT
+  {
+    return network_v4(network(), netmask());
+  }
+
+  /// Test if network is a valid host address.
+  bool is_host() const ASIO_NOEXCEPT
+  {
+    return prefix_length_ == 32;
+  }
+
+  /// Test if a network is a real subnet of another network.
+  ASIO_DECL bool is_subnet_of(const network_v4& other) const;
+  
+  /// Get the network as an address in dotted decimal format.
+  ASIO_DECL std::string to_string() const;
+
+  /// Get the network as an address in dotted decimal format.
+  ASIO_DECL std::string to_string(asio::error_code& ec) const;
+
+  /// Compare two networks for equality.
+  friend bool operator==(const network_v4& a, const network_v4& b)
+  {
+    return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;
+  }
+  
+  /// Compare two networks for inequality.
+  friend bool operator!=(const network_v4& a, const network_v4& b)
+  {
+    return !(a == b);
+  }
+
+private:
+  address_v4 address_;
+  unsigned short prefix_length_;
+};
+
+/// Create an IPv4 network from an address and prefix length.
+/**
+ * @relates address_v4
+ */
+inline network_v4 make_network_v4(
+    const address_v4& addr, unsigned short prefix_len)
+{
+  return network_v4(addr, prefix_len);
+}
+
+/// Create an IPv4 network from an address and netmask.
+/**
+ * @relates address_v4
+ */
+inline network_v4 make_network_v4(
+    const address_v4& addr, const address_v4& mask)
+{
+  return network_v4(addr, mask);
+}
+
+/// Create an IPv4 network from a string containing IP address and prefix
+/// length.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(const char* str);
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(
+    const char* str, asio::error_code& ec);
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(const std::string& str);
+
+/// Create an IPv4 address from an IP address string in dotted decimal form.
+/**
+ * @relates network_v4
+ */
+ASIO_DECL network_v4 make_network_v4(
+    const std::string& str, asio::error_code& ec);
+
+#if !defined(ASIO_NO_IOSTREAM)
+
+/// Output a network as a string.
+/**
+ * Used to output a human-readable string for a specified network.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param net The network to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::address_v4
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+    std::basic_ostream<Elem, Traits>& os, const network_v4& net);
+
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/impl/network_v4.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/ip/impl/network_v4.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_IP_NETWORK_V4_HPP
diff --git a/asio/src/tests/Makefile.am b/asio/src/tests/Makefile.am
index 8fa3035..ca57965 100644
--- a/asio/src/tests/Makefile.am
+++ b/asio/src/tests/Makefile.am
@@ -40,6 +40,8 @@
 	unit/high_resolution_timer \
 	unit/io_service \
 	unit/ip/address \
+	unit/ip/address_iterator_v4 \
+	unit/ip/address_range_v4 \
 	unit/ip/address_v4 \
 	unit/ip/address_v6 \
 	unit/ip/basic_endpoint \
@@ -50,6 +52,7 @@
 	unit/ip/host_name \
 	unit/ip/icmp \
 	unit/ip/multicast \
+	unit/ip/network_v4 \
 	unit/ip/resolver_query_base \
 	unit/ip/resolver_service \
 	unit/ip/tcp \
@@ -147,6 +150,8 @@
 	unit/high_resolution_timer \
 	unit/io_service \
 	unit/ip/address \
+	unit/ip/address_iterator_v4 \
+	unit/ip/address_range_v4 \
 	unit/ip/address_v4 \
 	unit/ip/address_v6 \
 	unit/ip/basic_endpoint \
@@ -157,6 +162,7 @@
 	unit/ip/host_name \
 	unit/ip/icmp \
 	unit/ip/multicast \
+	unit/ip/network_v4 \
 	unit/ip/resolver_query_base \
 	unit/ip/resolver_service \
 	unit/ip/tcp \
@@ -267,6 +273,8 @@
 unit_high_resolution_timer_SOURCES = unit/high_resolution_timer.cpp unit/unit_test.cpp
 unit_io_service_SOURCES = unit/io_service.cpp unit/unit_test.cpp
 unit_ip_address_SOURCES = unit/ip/address.cpp unit/unit_test.cpp
+unit_ip_address_iterator_v4_SOURCES = unit/ip/address_iterator_v4.cpp unit/unit_test.cpp
+unit_ip_address_range_v4_SOURCES = unit/ip/address_range_v4.cpp unit/unit_test.cpp
 unit_ip_address_v4_SOURCES = unit/ip/address_v4.cpp unit/unit_test.cpp
 unit_ip_address_v6_SOURCES = unit/ip/address_v6.cpp unit/unit_test.cpp
 unit_ip_basic_endpoint_SOURCES = unit/ip/basic_endpoint.cpp unit/unit_test.cpp
@@ -277,6 +285,7 @@
 unit_ip_host_name_SOURCES = unit/ip/host_name.cpp unit/unit_test.cpp
 unit_ip_icmp_SOURCES = unit/ip/icmp.cpp unit/unit_test.cpp
 unit_ip_multicast_SOURCES = unit/ip/multicast.cpp unit/unit_test.cpp
+unit_ip_network_v4_SOURCES = unit/ip/network_v4.cpp unit/unit_test.cpp
 unit_ip_resolver_query_base_SOURCES = unit/ip/resolver_query_base.cpp unit/unit_test.cpp
 unit_ip_resolver_service_SOURCES = unit/ip/resolver_service.cpp unit/unit_test.cpp
 unit_ip_tcp_SOURCES = unit/ip/tcp.cpp unit/unit_test.cpp
diff --git a/asio/src/tests/unit/ip/.gitignore b/asio/src/tests/unit/ip/.gitignore
index b1b2e7b..c999d72 100644
--- a/asio/src/tests/unit/ip/.gitignore
+++ b/asio/src/tests/unit/ip/.gitignore
@@ -8,8 +8,8 @@
 *.pdb
 *.tds
 address
-address_v4
-address_v6
+address*_v4
+address*_v6
 basic_endpoint
 basic_resolver
 basic_resolver_entry
@@ -18,6 +18,7 @@
 host_name
 icmp
 multicast
+network_v4
 resolver_query_base
 resolver_service
 tcp
diff --git a/asio/src/tests/unit/ip/address_iterator_v4.cpp b/asio/src/tests/unit/ip/address_iterator_v4.cpp
new file mode 100644
index 0000000..931c085
--- /dev/null
+++ b/asio/src/tests/unit/ip/address_iterator_v4.cpp
@@ -0,0 +1,27 @@
+//
+// address_iterator_v4.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include "asio/ip/address_iterator_v4.hpp"
+
+#include "../unit_test.hpp"
+
+//------------------------------------------------------------------------------
+
+ASIO_TEST_SUITE
+(
+  "ip/address_iterator_v4",
+  ASIO_TEST_CASE(null_test)
+)
diff --git a/asio/src/tests/unit/ip/address_range_v4.cpp b/asio/src/tests/unit/ip/address_range_v4.cpp
new file mode 100644
index 0000000..2c90877
--- /dev/null
+++ b/asio/src/tests/unit/ip/address_range_v4.cpp
@@ -0,0 +1,27 @@
+//
+// address_range_v4.cpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include "asio/ip/address_range_v4.hpp"
+
+#include "../unit_test.hpp"
+
+//------------------------------------------------------------------------------
+
+ASIO_TEST_SUITE
+(
+  "ip/address_range_v4",
+  ASIO_TEST_CASE(null_test)
+)
diff --git a/asio/src/tests/unit/ip/network_v4.cpp b/asio/src/tests/unit/ip/network_v4.cpp
new file mode 100644
index 0000000..9502374
--- /dev/null
+++ b/asio/src/tests/unit/ip/network_v4.cpp
@@ -0,0 +1,274 @@
+//
+// network_v4.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include "asio/ip/network_v4.hpp"
+
+#include "../unit_test.hpp"
+
+//------------------------------------------------------------------------------
+
+// ip_network_v4_compile test
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The following test checks that all public member functions on the class
+// ip::network_v4 compile and link correctly. Runtime failures are ignored.
+
+namespace ip_network_v4_compile {
+
+void test()
+{
+  using namespace asio;
+  namespace ip = asio::ip;
+
+  try
+  {
+    asio::error_code ec;
+
+    // network_v4 constructors.
+
+    ip::network_v4 net1(ip::make_address_v4("192.168.1.0"), 32);
+    ip::network_v4 net2(ip::make_address_v4("192.168.1.0"),
+        ip::make_address_v4("255.255.255.0"));
+
+    // network_v4 functions.
+
+    ip::address_v4 addr1 = net1.address();
+    (void)addr1;
+
+    unsigned short prefix_len = net1.prefix_length();
+    (void)prefix_len;
+
+    ip::address_v4 addr2 = net1.netmask();
+    (void)addr2;
+
+    ip::address_v4 addr3 = net1.network();
+    (void)addr3;
+
+    ip::address_v4 addr4 = net1.broadcast();
+    (void)addr4;
+
+    ip::address_range_v4 hosts = net1.hosts();
+    (void)hosts;
+
+    ip::network_v4 net3 = net1.canonical();
+    (void)net3;
+
+    bool b1 = net1.is_host();
+    (void)b1;
+
+    bool b2 = net1.is_subnet_of(net2);
+    (void)b2;
+
+    std::string s1 = net1.to_string();
+    (void)s1;
+
+    std::string s2 = net1.to_string(ec);
+    (void)s2;
+
+    // network_v4 comparisons.
+
+    bool b3 = (net1 == net2);
+    (void)b3;
+
+    bool b4 = (net1 != net2);
+    (void)b4;
+
+  }
+  catch (std::exception&)
+  {
+  }
+}
+
+} // namespace ip_network_v4_compile
+
+//------------------------------------------------------------------------------
+
+// ip_network_v4_runtime test
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The following test checks that the various public member functions meet the
+// necessary postconditions.
+
+namespace ip_network_v4_runtime {
+
+void test()
+{
+  using asio::ip::address_v4;
+  using asio::ip::make_address_v4;
+  using asio::ip::network_v4;
+  using asio::ip::make_network_v4;
+
+  address_v4 addr = make_address_v4("1.2.3.4");
+
+  // calculate prefix length
+
+  network_v4 net1(addr, make_address_v4("255.255.255.0"));
+  ASIO_CHECK(net1.prefix_length() == 24);
+
+  network_v4 net2(addr, make_address_v4("255.255.255.192"));
+  ASIO_CHECK(net2.prefix_length() == 26);
+
+  network_v4 net3(addr, make_address_v4("128.0.0.0"));
+  ASIO_CHECK(net3.prefix_length() == 1);
+
+  std::string msg;
+  try
+  {
+    make_network_v4(addr, make_address_v4("255.255.255.1"));
+  }
+  catch(std::exception& ex)
+  {
+    msg = ex.what();
+  }
+  ASIO_CHECK(msg == std::string("non-contiguous netmask"));
+
+  msg.clear();
+  try
+  {
+    make_network_v4(addr, make_address_v4("0.255.255.0"));
+  }
+  catch(std::exception& ex)
+  {
+    msg = ex.what();
+  }
+  ASIO_CHECK(msg == std::string("non-contiguous netmask"));
+
+  // calculate netmask
+
+  network_v4 net4(addr, 23);
+  ASIO_CHECK(net4.netmask() == make_address_v4("255.255.254.0"));
+
+  network_v4 net5(addr, 12);
+  ASIO_CHECK(net5.netmask() == make_address_v4("255.240.0.0"));
+
+  network_v4 net6(addr, 24);
+  ASIO_CHECK(net6.netmask() == make_address_v4("255.255.255.0"));
+
+  network_v4 net7(addr, 16);
+  ASIO_CHECK(net7.netmask() == make_address_v4("255.255.0.0"));
+
+  network_v4 net8(addr, 8);
+  ASIO_CHECK(net8.netmask() == make_address_v4("255.0.0.0"));
+
+  network_v4 net9(addr, 32);
+  ASIO_CHECK(net9.netmask() == make_address_v4("255.255.255.255"));
+
+  network_v4 net10(addr, 1);
+  ASIO_CHECK(net10.netmask() == make_address_v4("128.0.0.0"));
+
+  network_v4 net11(addr, 0);
+  ASIO_CHECK(net11.netmask() == make_address_v4("0.0.0.0"));
+
+  msg.clear();
+  try
+  {
+    make_network_v4(addr, 33);
+  }
+  catch(std::out_of_range& ex)
+  {
+    msg = ex.what();
+  }
+  ASIO_CHECK(msg == std::string("prefix length too large"));
+
+#if 0
+  // construct address range from address and prefix length
+  ASIO_CHECK(network_v4(address_v4::from_string("192.168.77.100"), 32).network() == address_v4::from_string("192.168.77.100"));
+  ASIO_CHECK(network_v4(address_v4::from_string("192.168.77.100"), 24).network() == address_v4::from_string("192.168.77.0"));
+  ASIO_CHECK(network_v4(address_v4::from_string("192.168.77.128"), 25).network() == address_v4::from_string("192.168.77.128"));
+
+  // construct address range from string in CIDR notation
+  ASIO_CHECK(network_v4::from_string("192.168.77.100/32").network() == address_v4::from_string("192.168.77.100"));
+  ASIO_CHECK(network_v4::from_string("192.168.77.100/24").network() == address_v4::from_string("192.168.77.0"));
+  ASIO_CHECK(network_v4::from_string("192.168.77.128/25").network() == address_v4::from_string("192.168.77.128"));
+
+  // prefix length
+  ASIO_CHECK(network_v4::from_string("193.99.144.80/24").prefix_length() == 24);
+  ASIO_CHECK(network_v4(address_v4::from_string("193.99.144.80"), 24).prefix_length() == 24);
+  ASIO_CHECK(network_v4(address_v4::from_string("192.168.77.0"), address_v4::from_string("255.255.255.0")).prefix_length() == 24);
+
+  // to string
+  std::string a("192.168.77.0/32");
+  ASIO_CHECK(network_v4::from_string(a.c_str()).to_string() == a);
+  ASIO_CHECK(network_v4(address_v4::from_string("192.168.77.10"), 24).to_string() == std::string("192.168.77.10/24"));
+
+  // return host part
+  ASIO_CHECK(network_v4::from_string("192.168.77.11/24").host() == address_v4::from_string("192.168.77.11"));
+
+  // return host in CIDR notation
+  ASIO_CHECK(network_v4::from_string("192.168.78.30/20").host_cidr().to_string() == "192.168.78.30/32");
+
+  // return network in CIDR notation
+  ASIO_CHECK(network_v4::from_string("192.168.78.30/20").network_cidr().to_string() == "192.168.64.0/20");
+
+  // is host
+  ASIO_CHECK(network_v4::from_string("192.168.77.0/32").is_host());
+  ASIO_CHECK(!network_v4::from_string("192.168.77.0/31").is_host());
+
+  // is real subnet of
+  ASIO_CHECK(network_v4::from_string("192.168.0.192/24").is_subnet_of(network_v4::from_string("192.168.0.0/16")));
+  ASIO_CHECK(network_v4::from_string("192.168.0.0/24").is_subnet_of(network_v4::from_string("192.168.192.168/16")));
+  ASIO_CHECK(network_v4::from_string("192.168.0.192/24").is_subnet_of(network_v4::from_string("192.168.192.168/16")));
+  ASIO_CHECK(network_v4::from_string("192.168.0.0/24").is_subnet_of(network_v4::from_string("192.168.0.0/16")));
+  ASIO_CHECK(network_v4::from_string("192.168.0.0/24").is_subnet_of(network_v4::from_string("192.168.0.0/23")));
+  ASIO_CHECK(network_v4::from_string("192.168.0.0/24").is_subnet_of(network_v4::from_string("192.168.0.0/0")));
+  ASIO_CHECK(network_v4::from_string("192.168.0.0/32").is_subnet_of(network_v4::from_string("192.168.0.0/24")));
+
+  ASIO_CHECK(!network_v4::from_string("192.168.0.0/32").is_subnet_of(network_v4::from_string("192.168.0.0/32")));
+  ASIO_CHECK(!network_v4::from_string("192.168.0.0/24").is_subnet_of(network_v4::from_string("192.168.1.0/24")));
+  ASIO_CHECK(!network_v4::from_string("192.168.0.0/16").is_subnet_of(network_v4::from_string("192.168.1.0/24")));
+
+  network_v4 r(network_v4::from_string("192.168.0.0/24"));
+  ASIO_CHECK(!r.is_subnet_of(r));
+
+  network_v4 addr1(network_v4::from_string("192.168.0.2/24"));
+  network_v4 addr2(network_v4::from_string("192.168.1.1/28"));
+  network_v4 addr3(network_v4::from_string("192.168.1.21/28"));
+  // network
+  ASIO_CHECK(addr1.network() == address_v4::from_string("192.168.0.0"));
+  ASIO_CHECK(addr2.network() == address_v4::from_string("192.168.1.0"));
+  ASIO_CHECK(addr3.network() == address_v4::from_string("192.168.1.16"));
+  // netmask
+  ASIO_CHECK(addr1.netmask() == address_v4::from_string("255.255.255.0"));
+  ASIO_CHECK(addr2.netmask() == address_v4::from_string("255.255.255.240"));
+  ASIO_CHECK(addr3.netmask() == address_v4::from_string("255.255.255.240"));
+  // broadcast
+  ASIO_CHECK(addr1.broadcast() == address_v4::from_string("192.168.0.255"));
+  ASIO_CHECK(addr2.broadcast() == address_v4::from_string("192.168.1.15"));
+  ASIO_CHECK(addr3.broadcast() == address_v4::from_string("192.168.1.31"));
+  // iterator
+  ASIO_CHECK(std::distance(addr1.begin(),addr1.end()) == 254);
+  ASIO_CHECK(*addr1.begin() == address_v4::from_string("192.168.0.1"));
+  ASIO_CHECK(addr1.end() != addr1.find(address_v4::from_string("192.168.0.10")));
+  ASIO_CHECK(addr1.end() == addr1.find(address_v4::from_string("192.168.1.10")));
+  ASIO_CHECK(std::distance(addr2.begin(),addr2.end()) == 14);
+  ASIO_CHECK(*addr2.begin() == address_v4::from_string("192.168.1.1"));
+  ASIO_CHECK(addr2.end() != addr2.find(address_v4::from_string("192.168.1.14")));
+  ASIO_CHECK(addr2.end() == addr2.find(address_v4::from_string("192.168.1.15")));
+  ASIO_CHECK(std::distance(addr3.begin(),addr3.end()) == 14);
+  ASIO_CHECK(*addr3.begin() == address_v4::from_string("192.168.1.17"));
+  ASIO_CHECK(addr3.end() != addr3.find(address_v4::from_string("192.168.1.30")));
+  ASIO_CHECK(addr3.end() == addr3.find(address_v4::from_string("192.168.1.31")));
+#endif
+}
+
+} // namespace ip_network_v4_runtime
+
+//------------------------------------------------------------------------------
+
+ASIO_TEST_SUITE
+(
+  "ip/network_v4",
+  ASIO_TEST_CASE(ip_network_v4_compile::test)
+  ASIO_TEST_CASE(ip_network_v4_runtime::test)
+)