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