]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // stream_socket_service.hpp | |
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 SERVICES_STREAM_SOCKET_SERVICE_HPP | |
12 | #define SERVICES_STREAM_SOCKET_SERVICE_HPP | |
13 | ||
14 | #include <boost/asio.hpp> | |
15 | #include <boost/noncopyable.hpp> | |
16 | #include <boost/lexical_cast.hpp> | |
17 | #include "logger.hpp" | |
18 | ||
19 | namespace services { | |
20 | ||
21 | /// Debugging stream socket service that wraps the normal stream socket service. | |
22 | template <typename Protocol> | |
23 | class stream_socket_service | |
24 | : public boost::asio::io_service::service | |
25 | { | |
26 | private: | |
27 | /// The type of the wrapped stream socket service. | |
28 | typedef boost::asio::stream_socket_service<Protocol> service_impl_type; | |
29 | ||
30 | public: | |
31 | /// The unique service identifier. | |
32 | static boost::asio::io_service::id id; | |
33 | ||
34 | /// The protocol type. | |
35 | typedef Protocol protocol_type; | |
36 | ||
37 | /// The endpoint type. | |
38 | typedef typename Protocol::endpoint endpoint_type; | |
39 | ||
40 | /// The implementation type of a stream socket. | |
41 | typedef typename service_impl_type::implementation_type implementation_type; | |
42 | ||
43 | /// The native type of a stream socket. | |
44 | typedef typename service_impl_type::native_handle_type native_handle_type; | |
45 | ||
46 | /// Construct a new stream socket service for the specified io_service. | |
47 | explicit stream_socket_service(boost::asio::io_service& io_service) | |
48 | : boost::asio::io_service::service(io_service), | |
49 | service_impl_(boost::asio::use_service<service_impl_type>(io_service)), | |
50 | logger_(io_service, "stream_socket") | |
51 | { | |
52 | } | |
53 | ||
54 | /// Destroy all user-defined handler objects owned by the service. | |
55 | void shutdown_service() | |
56 | { | |
57 | } | |
58 | ||
59 | /// Construct a new stream socket implementation. | |
60 | void construct(implementation_type& impl) | |
61 | { | |
62 | service_impl_.construct(impl); | |
63 | } | |
64 | ||
65 | /// Destroy a stream socket implementation. | |
66 | void destroy(implementation_type& impl) | |
67 | { | |
68 | service_impl_.destroy(impl); | |
69 | } | |
70 | ||
71 | /// Open a new stream socket implementation. | |
72 | boost::system::error_code open(implementation_type& impl, | |
73 | const protocol_type& protocol, boost::system::error_code& ec) | |
74 | { | |
75 | logger_.log("Opening new socket"); | |
76 | return service_impl_.open(impl, protocol, ec); | |
77 | } | |
78 | ||
79 | /// Open a stream socket from an existing native socket. | |
80 | boost::system::error_code assign(implementation_type& impl, | |
81 | const protocol_type& protocol, const native_handle_type& native_socket, | |
82 | boost::system::error_code& ec) | |
83 | { | |
84 | logger_.log("Assigning from a native socket"); | |
85 | return service_impl_.assign(impl, protocol, native_socket, ec); | |
86 | } | |
87 | ||
88 | /// Determine whether the socket is open. | |
89 | bool is_open(const implementation_type& impl) const | |
90 | { | |
91 | logger_.log("Checking if socket is open"); | |
92 | return service_impl_.is_open(impl); | |
93 | } | |
94 | ||
95 | /// Close a stream socket implementation. | |
96 | boost::system::error_code close(implementation_type& impl, | |
97 | boost::system::error_code& ec) | |
98 | { | |
99 | logger_.log("Closing socket"); | |
100 | return service_impl_.close(impl, ec); | |
101 | } | |
102 | ||
103 | /// Determine whether the socket is at the out-of-band data mark. | |
104 | bool at_mark(const implementation_type& impl, | |
105 | boost::system::error_code& ec) const | |
106 | { | |
107 | logger_.log("Checking if socket is at out-of-band data mark"); | |
108 | return service_impl_.at_mark(impl, ec); | |
109 | } | |
110 | ||
111 | /// Determine the number of bytes available for reading. | |
112 | std::size_t available(const implementation_type& impl, | |
113 | boost::system::error_code& ec) const | |
114 | { | |
115 | logger_.log("Determining number of bytes available for reading"); | |
116 | return service_impl_.available(impl, ec); | |
117 | } | |
118 | ||
119 | /// Bind the stream socket to the specified local endpoint. | |
120 | boost::system::error_code bind(implementation_type& impl, | |
121 | const endpoint_type& endpoint, boost::system::error_code& ec) | |
122 | { | |
123 | logger_.log("Binding socket"); | |
124 | return service_impl_.bind(impl, endpoint, ec); | |
125 | } | |
126 | ||
127 | /// Connect the stream socket to the specified endpoint. | |
128 | boost::system::error_code connect(implementation_type& impl, | |
129 | const endpoint_type& peer_endpoint, boost::system::error_code& ec) | |
130 | { | |
131 | logger_.log("Connecting socket to " + | |
132 | boost::lexical_cast<std::string>(peer_endpoint)); | |
133 | return service_impl_.connect(impl, peer_endpoint, ec); | |
134 | } | |
135 | ||
136 | /// Handler to wrap asynchronous connect completion. | |
137 | template <typename Handler> | |
138 | class connect_handler | |
139 | { | |
140 | public: | |
141 | connect_handler(Handler h, logger& l) | |
142 | : handler_(h), | |
143 | logger_(l) | |
144 | { | |
145 | } | |
146 | ||
147 | void operator()(const boost::system::error_code& e) | |
148 | { | |
149 | if (e) | |
150 | { | |
151 | std::string msg = "Asynchronous connect failed: "; | |
152 | msg += e.message(); | |
153 | logger_.log(msg); | |
154 | } | |
155 | else | |
156 | { | |
157 | logger_.log("Asynchronous connect succeeded"); | |
158 | } | |
159 | ||
160 | handler_(e); | |
161 | } | |
162 | ||
163 | private: | |
164 | Handler handler_; | |
165 | logger& logger_; | |
166 | }; | |
167 | ||
168 | /// Start an asynchronous connect. | |
169 | template <typename Handler> | |
170 | void async_connect(implementation_type& impl, | |
171 | const endpoint_type& peer_endpoint, Handler handler) | |
172 | { | |
173 | logger_.log("Starting asynchronous connect to " + | |
174 | boost::lexical_cast<std::string>(peer_endpoint)); | |
175 | service_impl_.async_connect(impl, peer_endpoint, | |
176 | connect_handler<Handler>(handler, logger_)); | |
177 | } | |
178 | ||
179 | /// Set a socket option. | |
180 | template <typename Option> | |
181 | boost::system::error_code set_option(implementation_type& impl, | |
182 | const Option& option, boost::system::error_code& ec) | |
183 | { | |
184 | logger_.log("Setting socket option"); | |
185 | return service_impl_.set_option(impl, option, ec); | |
186 | } | |
187 | ||
188 | /// Get a socket option. | |
189 | template <typename Option> | |
190 | boost::system::error_code get_option(const implementation_type& impl, | |
191 | Option& option, boost::system::error_code& ec) const | |
192 | { | |
193 | logger_.log("Getting socket option"); | |
194 | return service_impl_.get_option(impl, option, ec); | |
195 | } | |
196 | ||
197 | /// Perform an IO control command on the socket. | |
198 | template <typename IO_Control_Command> | |
199 | boost::system::error_code io_control(implementation_type& impl, | |
200 | IO_Control_Command& command, boost::system::error_code& ec) | |
201 | { | |
202 | logger_.log("Performing IO control command on socket"); | |
203 | return service_impl_.io_control(impl, command, ec); | |
204 | } | |
205 | ||
206 | /// Get the local endpoint. | |
207 | endpoint_type local_endpoint(const implementation_type& impl, | |
208 | boost::system::error_code& ec) const | |
209 | { | |
210 | logger_.log("Getting socket's local endpoint"); | |
211 | return service_impl_.local_endpoint(impl, ec); | |
212 | } | |
213 | ||
214 | /// Get the remote endpoint. | |
215 | endpoint_type remote_endpoint(const implementation_type& impl, | |
216 | boost::system::error_code& ec) const | |
217 | { | |
218 | logger_.log("Getting socket's remote endpoint"); | |
219 | return service_impl_.remote_endpoint(impl, ec); | |
220 | } | |
221 | ||
222 | /// Disable sends or receives on the socket. | |
223 | boost::system::error_code shutdown(implementation_type& impl, | |
224 | boost::asio::socket_base::shutdown_type what, | |
225 | boost::system::error_code& ec) | |
226 | { | |
227 | logger_.log("Shutting down socket"); | |
228 | return service_impl_.shutdown(impl, what, ec); | |
229 | } | |
230 | ||
231 | /// Send the given data to the peer. | |
232 | template <typename Const_Buffers> | |
233 | std::size_t send(implementation_type& impl, const Const_Buffers& buffers, | |
234 | boost::asio::socket_base::message_flags flags, | |
235 | boost::system::error_code& ec) | |
236 | { | |
237 | logger_.log("Sending data on socket"); | |
238 | return service_impl_.send(impl, buffers, flags, ec); | |
239 | } | |
240 | ||
241 | /// Handler to wrap asynchronous send completion. | |
242 | template <typename Handler> | |
243 | class send_handler | |
244 | { | |
245 | public: | |
246 | send_handler(Handler h, logger& l) | |
247 | : handler_(h), | |
248 | logger_(l) | |
249 | { | |
250 | } | |
251 | ||
252 | void operator()(const boost::system::error_code& e, | |
253 | std::size_t bytes_transferred) | |
254 | { | |
255 | if (e) | |
256 | { | |
257 | std::string msg = "Asynchronous send failed: "; | |
258 | msg += e.message(); | |
259 | logger_.log(msg); | |
260 | } | |
261 | else | |
262 | { | |
263 | logger_.log("Asynchronous send succeeded"); | |
264 | } | |
265 | ||
266 | handler_(e, bytes_transferred); | |
267 | } | |
268 | ||
269 | private: | |
270 | Handler handler_; | |
271 | logger& logger_; | |
272 | }; | |
273 | ||
274 | /// Start an asynchronous send. | |
275 | template <typename Const_Buffers, typename Handler> | |
276 | void async_send(implementation_type& impl, const Const_Buffers& buffers, | |
277 | boost::asio::socket_base::message_flags flags, Handler handler) | |
278 | { | |
279 | logger_.log("Starting asynchronous send"); | |
280 | service_impl_.async_send(impl, buffers, flags, | |
281 | send_handler<Handler>(handler, logger_)); | |
282 | } | |
283 | ||
284 | /// Receive some data from the peer. | |
285 | template <typename Mutable_Buffers> | |
286 | std::size_t receive(implementation_type& impl, | |
287 | const Mutable_Buffers& buffers, | |
288 | boost::asio::socket_base::message_flags flags, | |
289 | boost::system::error_code& ec) | |
290 | { | |
291 | logger_.log("Receiving data on socket"); | |
292 | return service_impl_.receive(impl, buffers, flags, ec); | |
293 | } | |
294 | ||
295 | /// Handler to wrap asynchronous receive completion. | |
296 | template <typename Handler> | |
297 | class receive_handler | |
298 | { | |
299 | public: | |
300 | receive_handler(Handler h, logger& l) | |
301 | : handler_(h), | |
302 | logger_(l) | |
303 | { | |
304 | } | |
305 | ||
306 | void operator()(const boost::system::error_code& e, | |
307 | std::size_t bytes_transferred) | |
308 | { | |
309 | if (e) | |
310 | { | |
311 | std::string msg = "Asynchronous receive failed: "; | |
312 | msg += e.message(); | |
313 | logger_.log(msg); | |
314 | } | |
315 | else | |
316 | { | |
317 | logger_.log("Asynchronous receive succeeded"); | |
318 | } | |
319 | ||
320 | handler_(e, bytes_transferred); | |
321 | } | |
322 | ||
323 | private: | |
324 | Handler handler_; | |
325 | logger& logger_; | |
326 | }; | |
327 | ||
328 | /// Start an asynchronous receive. | |
329 | template <typename Mutable_Buffers, typename Handler> | |
330 | void async_receive(implementation_type& impl, const Mutable_Buffers& buffers, | |
331 | boost::asio::socket_base::message_flags flags, Handler handler) | |
332 | { | |
333 | logger_.log("Starting asynchronous receive"); | |
334 | service_impl_.async_receive(impl, buffers, flags, | |
335 | receive_handler<Handler>(handler, logger_)); | |
336 | } | |
337 | ||
338 | private: | |
339 | /// The wrapped stream socket service. | |
340 | service_impl_type& service_impl_; | |
341 | ||
342 | /// The logger used for writing debug messages. | |
343 | mutable logger logger_; | |
344 | }; | |
345 | ||
346 | template <typename Protocol> | |
347 | boost::asio::io_service::id stream_socket_service<Protocol>::id; | |
348 | ||
349 | } // namespace services | |
350 | ||
351 | #endif // SERVICES_STREAM_SOCKET_SERVICE_HPP |