1//
2// ip/detail/impl/endpoint.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
12#define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include "asio/detail/config.hpp"
19#include <cstring>
20#if !defined(ASIO_NO_IOSTREAM)
21# include <sstream>
22#endif // !defined(ASIO_NO_IOSTREAM)
23#include "asio/detail/socket_ops.hpp"
24#include "asio/detail/throw_error.hpp"
25#include "asio/error.hpp"
26#include "asio/ip/detail/endpoint.hpp"
27
28#include "asio/detail/push_options.hpp"
29
30namespace asio {
31namespace ip {
32namespace detail {
33
34endpoint::endpoint()
35  : data_()
36{
37  data_.v4.sin_family = ASIO_OS_DEF(AF_INET);
38  data_.v4.sin_port = 0;
39  data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY);
40}
41
42endpoint::endpoint(int family, unsigned short port_num)
43  : data_()
44{
45  using namespace std; // For memcpy.
46  if (family == ASIO_OS_DEF(AF_INET))
47  {
48    data_.v4.sin_family = ASIO_OS_DEF(AF_INET);
49    data_.v4.sin_port =
50      asio::detail::socket_ops::host_to_network_short(port_num);
51    data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY);
52  }
53  else
54  {
55    data_.v6.sin6_family = ASIO_OS_DEF(AF_INET6);
56    data_.v6.sin6_port =
57      asio::detail::socket_ops::host_to_network_short(port_num);
58    data_.v6.sin6_flowinfo = 0;
59    data_.v6.sin6_addr.s6_addr[0] = 0; data_.v6.sin6_addr.s6_addr[1] = 0;
60    data_.v6.sin6_addr.s6_addr[2] = 0, data_.v6.sin6_addr.s6_addr[3] = 0;
61    data_.v6.sin6_addr.s6_addr[4] = 0, data_.v6.sin6_addr.s6_addr[5] = 0;
62    data_.v6.sin6_addr.s6_addr[6] = 0, data_.v6.sin6_addr.s6_addr[7] = 0;
63    data_.v6.sin6_addr.s6_addr[8] = 0, data_.v6.sin6_addr.s6_addr[9] = 0;
64    data_.v6.sin6_addr.s6_addr[10] = 0, data_.v6.sin6_addr.s6_addr[11] = 0;
65    data_.v6.sin6_addr.s6_addr[12] = 0, data_.v6.sin6_addr.s6_addr[13] = 0;
66    data_.v6.sin6_addr.s6_addr[14] = 0, data_.v6.sin6_addr.s6_addr[15] = 0;
67    data_.v6.sin6_scope_id = 0;
68  }
69}
70
71endpoint::endpoint(const asio::ip::address& addr,
72    unsigned short port_num)
73  : data_()
74{
75  using namespace std; // For memcpy.
76  if (addr.is_v4())
77  {
78    data_.v4.sin_family = ASIO_OS_DEF(AF_INET);
79    data_.v4.sin_port =
80      asio::detail::socket_ops::host_to_network_short(port_num);
81    data_.v4.sin_addr.s_addr =
82      asio::detail::socket_ops::host_to_network_long(
83        addr.to_v4().to_uint());
84  }
85  else
86  {
87    data_.v6.sin6_family = ASIO_OS_DEF(AF_INET6);
88    data_.v6.sin6_port =
89      asio::detail::socket_ops::host_to_network_short(port_num);
90    data_.v6.sin6_flowinfo = 0;
91    asio::ip::address_v6 v6_addr = addr.to_v6();
92    asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
93    memcpy(data_.v6.sin6_addr.s6_addr, bytes.data(), 16);
94    data_.v6.sin6_scope_id =
95      static_cast<asio::detail::u_long_type>(
96        v6_addr.scope_id());
97  }
98}
99
100void endpoint::resize(std::size_t new_size)
101{
102  if (new_size > sizeof(asio::detail::sockaddr_storage_type))
103  {
104    asio::error_code ec(asio::error::invalid_argument);
105    asio::detail::throw_error(ec);
106  }
107}
108
109unsigned short endpoint::port() const
110{
111  if (is_v4())
112  {
113    return asio::detail::socket_ops::network_to_host_short(
114        data_.v4.sin_port);
115  }
116  else
117  {
118    return asio::detail::socket_ops::network_to_host_short(
119        data_.v6.sin6_port);
120  }
121}
122
123void endpoint::port(unsigned short port_num)
124{
125  if (is_v4())
126  {
127    data_.v4.sin_port
128      = asio::detail::socket_ops::host_to_network_short(port_num);
129  }
130  else
131  {
132    data_.v6.sin6_port
133      = asio::detail::socket_ops::host_to_network_short(port_num);
134  }
135}
136
137asio::ip::address endpoint::address() const
138{
139  using namespace std; // For memcpy.
140  if (is_v4())
141  {
142    return asio::ip::address_v4(
143        asio::detail::socket_ops::network_to_host_long(
144          data_.v4.sin_addr.s_addr));
145  }
146  else
147  {
148    asio::ip::address_v6::bytes_type bytes;
149#if defined(ASIO_HAS_STD_ARRAY)
150    memcpy(bytes.data(), data_.v6.sin6_addr.s6_addr, 16);
151#else // defined(ASIO_HAS_STD_ARRAY)
152    memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
153#endif // defined(ASIO_HAS_STD_ARRAY)
154    return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
155  }
156}
157
158void endpoint::address(const asio::ip::address& addr)
159{
160  endpoint tmp_endpoint(addr, port());
161  data_ = tmp_endpoint.data_;
162}
163
164bool operator==(const endpoint& e1, const endpoint& e2)
165{
166  return e1.address() == e2.address() && e1.port() == e2.port();
167}
168
169bool operator<(const endpoint& e1, const endpoint& e2)
170{
171  if (e1.address() < e2.address())
172    return true;
173  if (e1.address() != e2.address())
174    return false;
175  return e1.port() < e2.port();
176}
177
178#if !defined(ASIO_NO_IOSTREAM)
179std::string endpoint::to_string() const
180{
181  std::ostringstream tmp_os;
182  tmp_os.imbue(std::locale::classic());
183  if (is_v4())
184    tmp_os << address();
185  else
186    tmp_os << '[' << address() << ']';
187  tmp_os << ':' << port();
188
189  return tmp_os.str();
190}
191#endif // !defined(ASIO_NO_IOSTREAM)
192
193} // namespace detail
194} // namespace ip
195} // namespace asio
196
197#include "asio/detail/pop_options.hpp"
198
199#endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
200