1//
2// detail/socket_option.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2015 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_DETAIL_SOCKET_OPTION_HPP
12#define ASIO_DETAIL_SOCKET_OPTION_HPP
13
14
15#include "asio/detail/config.hpp"
16#include <cstddef>
17#include <stdexcept>
18#include "asio/detail/socket_types.hpp"
19#include "asio/detail/throw_exception.hpp"
20
21#include "asio/detail/push_options.hpp"
22
23namespace asio {
24namespace detail {
25namespace socket_option {
26
27// Helper template for implementing boolean-based options.
28template <int Level, int Name>
29class boolean
30{
31public:
32  // Default constructor.
33  boolean()
34    : value_(0)
35  {
36  }
37
38  // Construct with a specific option value.
39  explicit boolean(bool v)
40    : value_(v ? 1 : 0)
41  {
42  }
43
44  // Set the current value of the boolean.
45  boolean& operator=(bool v)
46  {
47    value_ = v ? 1 : 0;
48    return *this;
49  }
50
51  // Get the current value of the boolean.
52  bool value() const
53  {
54    return !!value_;
55  }
56
57  // Convert to bool.
58  operator bool() const
59  {
60    return !!value_;
61  }
62
63  // Test for false.
64  bool operator!() const
65  {
66    return !value_;
67  }
68
69  // Get the level of the socket option.
70  template <typename Protocol>
71  int level(const Protocol&) const
72  {
73    return Level;
74  }
75
76  // Get the name of the socket option.
77  template <typename Protocol>
78  int name(const Protocol&) const
79  {
80    return Name;
81  }
82
83  // Get the address of the boolean data.
84  template <typename Protocol>
85  int* data(const Protocol&)
86  {
87    return &value_;
88  }
89
90  // Get the address of the boolean data.
91  template <typename Protocol>
92  const int* data(const Protocol&) const
93  {
94    return &value_;
95  }
96
97  // Get the size of the boolean data.
98  template <typename Protocol>
99  std::size_t size(const Protocol&) const
100  {
101    return sizeof(value_);
102  }
103
104  // Set the size of the boolean data.
105  template <typename Protocol>
106  void resize(const Protocol&, std::size_t s)
107  {
108    // On some platforms (e.g. Windows Vista), the getsockopt function will
109    // return the size of a boolean socket option as one byte, even though a
110    // four byte integer was passed in.
111    switch (s)
112    {
113    case sizeof(char):
114      value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0;
115      break;
116    case sizeof(value_):
117      break;
118    default:
119      {
120        std::length_error ex("boolean socket option resize");
121        asio::detail::throw_exception(ex);
122      }
123    }
124  }
125
126private:
127  int value_;
128};
129
130// Helper template for implementing integer options.
131template <int Level, int Name>
132class integer
133{
134public:
135  // Default constructor.
136  integer()
137    : value_(0)
138  {
139  }
140
141  // Construct with a specific option value.
142  explicit integer(int v)
143    : value_(v)
144  {
145  }
146
147  // Set the value of the int option.
148  integer& operator=(int v)
149  {
150    value_ = v;
151    return *this;
152  }
153
154  // Get the current value of the int option.
155  int value() const
156  {
157    return value_;
158  }
159
160  // Get the level of the socket option.
161  template <typename Protocol>
162  int level(const Protocol&) const
163  {
164    return Level;
165  }
166
167  // Get the name of the socket option.
168  template <typename Protocol>
169  int name(const Protocol&) const
170  {
171    return Name;
172  }
173
174  // Get the address of the int data.
175  template <typename Protocol>
176  int* data(const Protocol&)
177  {
178    return &value_;
179  }
180
181  // Get the address of the int data.
182  template <typename Protocol>
183  const int* data(const Protocol&) const
184  {
185    return &value_;
186  }
187
188  // Get the size of the int data.
189  template <typename Protocol>
190  std::size_t size(const Protocol&) const
191  {
192    return sizeof(value_);
193  }
194
195  // Set the size of the int data.
196  template <typename Protocol>
197  void resize(const Protocol&, std::size_t s)
198  {
199    if (s != sizeof(value_))
200    {
201      std::length_error ex("integer socket option resize");
202      asio::detail::throw_exception(ex);
203    }
204  }
205
206private:
207  int value_;
208};
209
210// Helper template for implementing linger options.
211template <int Level, int Name>
212class linger
213{
214public:
215  // Default constructor.
216  linger()
217  {
218    value_.l_onoff = 0;
219    value_.l_linger = 0;
220  }
221
222  // Construct with specific option values.
223  linger(bool e, int t)
224  {
225    enabled(e);
226    timeout ASIO_PREVENT_MACRO_SUBSTITUTION(t);
227  }
228
229  // Set the value for whether linger is enabled.
230  void enabled(bool value)
231  {
232    value_.l_onoff = value ? 1 : 0;
233  }
234
235  // Get the value for whether linger is enabled.
236  bool enabled() const
237  {
238    return value_.l_onoff != 0;
239  }
240
241  // Set the value for the linger timeout.
242  void timeout ASIO_PREVENT_MACRO_SUBSTITUTION(int value)
243  {
244    value_.l_linger = value;
245  }
246
247  // Get the value for the linger timeout.
248  int timeout ASIO_PREVENT_MACRO_SUBSTITUTION() const
249  {
250    return static_cast<int>(value_.l_linger);
251  }
252
253  // Get the level of the socket option.
254  template <typename Protocol>
255  int level(const Protocol&) const
256  {
257    return Level;
258  }
259
260  // Get the name of the socket option.
261  template <typename Protocol>
262  int name(const Protocol&) const
263  {
264    return Name;
265  }
266
267  // Get the address of the linger data.
268  template <typename Protocol>
269  detail::linger_type* data(const Protocol&)
270  {
271    return &value_;
272  }
273
274  // Get the address of the linger data.
275  template <typename Protocol>
276  const detail::linger_type* data(const Protocol&) const
277  {
278    return &value_;
279  }
280
281  // Get the size of the linger data.
282  template <typename Protocol>
283  std::size_t size(const Protocol&) const
284  {
285    return sizeof(value_);
286  }
287
288  // Set the size of the int data.
289  template <typename Protocol>
290  void resize(const Protocol&, std::size_t s)
291  {
292    if (s != sizeof(value_))
293    {
294      std::length_error ex("linger socket option resize");
295      asio::detail::throw_exception(ex);
296    }
297  }
298
299private:
300  detail::linger_type value_;
301};
302
303} // namespace socket_option
304} // namespace detail
305} // namespace asio
306
307#include "asio/detail/pop_options.hpp"
308
309#endif // ASIO_DETAIL_SOCKET_OPTION_HPP
310