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 
23 namespace asio {
24 namespace detail {
25 namespace socket_option {
26 
27 // Helper template for implementing boolean-based options.
28 template <int Level, int Name>
29 class boolean
30 {
31 public:
32   // Default constructor.
boolean()33   boolean()
34     : value_(0)
35   {
36   }
37 
38   // Construct with a specific option value.
boolean(bool v)39   explicit boolean(bool v)
40     : value_(v ? 1 : 0)
41   {
42   }
43 
44   // Set the current value of the boolean.
operator =(bool v)45   boolean& operator=(bool v)
46   {
47     value_ = v ? 1 : 0;
48     return *this;
49   }
50 
51   // Get the current value of the boolean.
value() const52   bool value() const
53   {
54     return !!value_;
55   }
56 
57   // Convert to bool.
operator bool() const58   operator bool() const
59   {
60     return !!value_;
61   }
62 
63   // Test for false.
operator !() const64   bool operator!() const
65   {
66     return !value_;
67   }
68 
69   // Get the level of the socket option.
70   template <typename Protocol>
level(const Protocol &) const71   int level(const Protocol&) const
72   {
73     return Level;
74   }
75 
76   // Get the name of the socket option.
77   template <typename Protocol>
name(const Protocol &) const78   int name(const Protocol&) const
79   {
80     return Name;
81   }
82 
83   // Get the address of the boolean data.
84   template <typename Protocol>
data(const Protocol &)85   int* data(const Protocol&)
86   {
87     return &value_;
88   }
89 
90   // Get the address of the boolean data.
91   template <typename Protocol>
data(const Protocol &) const92   const int* data(const Protocol&) const
93   {
94     return &value_;
95   }
96 
97   // Get the size of the boolean data.
98   template <typename Protocol>
size(const Protocol &) const99   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>
resize(const Protocol &,std::size_t s)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 
126 private:
127   int value_;
128 };
129 
130 // Helper template for implementing integer options.
131 template <int Level, int Name>
132 class integer
133 {
134 public:
135   // Default constructor.
integer()136   integer()
137     : value_(0)
138   {
139   }
140 
141   // Construct with a specific option value.
integer(int v)142   explicit integer(int v)
143     : value_(v)
144   {
145   }
146 
147   // Set the value of the int option.
operator =(int v)148   integer& operator=(int v)
149   {
150     value_ = v;
151     return *this;
152   }
153 
154   // Get the current value of the int option.
value() const155   int value() const
156   {
157     return value_;
158   }
159 
160   // Get the level of the socket option.
161   template <typename Protocol>
level(const Protocol &) const162   int level(const Protocol&) const
163   {
164     return Level;
165   }
166 
167   // Get the name of the socket option.
168   template <typename Protocol>
name(const Protocol &) const169   int name(const Protocol&) const
170   {
171     return Name;
172   }
173 
174   // Get the address of the int data.
175   template <typename Protocol>
data(const Protocol &)176   int* data(const Protocol&)
177   {
178     return &value_;
179   }
180 
181   // Get the address of the int data.
182   template <typename Protocol>
data(const Protocol &) const183   const int* data(const Protocol&) const
184   {
185     return &value_;
186   }
187 
188   // Get the size of the int data.
189   template <typename Protocol>
size(const Protocol &) const190   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>
resize(const Protocol &,std::size_t s)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 
206 private:
207   int value_;
208 };
209 
210 // Helper template for implementing linger options.
211 template <int Level, int Name>
212 class linger
213 {
214 public:
215   // Default constructor.
linger()216   linger()
217   {
218     value_.l_onoff = 0;
219     value_.l_linger = 0;
220   }
221 
222   // Construct with specific option values.
linger(bool e,int t)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.
enabled(bool value)230   void enabled(bool value)
231   {
232     value_.l_onoff = value ? 1 : 0;
233   }
234 
235   // Get the value for whether linger is enabled.
enabled() const236   bool enabled() const
237   {
238     return value_.l_onoff != 0;
239   }
240 
241   // Set the value for the linger timeout.
ASIO_PREVENT_MACRO_SUBSTITUTION(int value)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.
ASIO_PREVENT_MACRO_SUBSTITUTION() const248   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>
level(const Protocol &) const255   int level(const Protocol&) const
256   {
257     return Level;
258   }
259 
260   // Get the name of the socket option.
261   template <typename Protocol>
name(const Protocol &) const262   int name(const Protocol&) const
263   {
264     return Name;
265   }
266 
267   // Get the address of the linger data.
268   template <typename Protocol>
data(const 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>
data(const Protocol &) const276   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>
size(const Protocol &) const283   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>
resize(const Protocol &,std::size_t s)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 
299 private:
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