2 // stream_socket_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef SERVICES_STREAM_SOCKET_SERVICE_HPP
12 #define SERVICES_STREAM_SOCKET_SERVICE_HPP
14 #include <boost/asio.hpp>
15 #include <boost/noncopyable.hpp>
16 #include <boost/lexical_cast.hpp>
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
27 /// The type of the wrapped stream socket service.
28 typedef boost::asio::stream_socket_service<Protocol> service_impl_type;
31 /// The unique service identifier.
32 static boost::asio::io_service::id id;
34 /// The protocol type.
35 typedef Protocol protocol_type;
37 /// The endpoint type.
38 typedef typename Protocol::endpoint endpoint_type;
40 /// The implementation type of a stream socket.
41 typedef typename service_impl_type::implementation_type implementation_type;
43 /// The native type of a stream socket.
44 typedef typename service_impl_type::native_handle_type native_handle_type;
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")
54 /// Destroy all user-defined handler objects owned by the service.
55 void shutdown_service()
59 /// Construct a new stream socket implementation.
60 void construct(implementation_type& impl)
62 service_impl_.construct(impl);
65 /// Destroy a stream socket implementation.
66 void destroy(implementation_type& impl)
68 service_impl_.destroy(impl);
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)
75 logger_.log("Opening new socket");
76 return service_impl_.open(impl, protocol, ec);
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)
84 logger_.log("Assigning from a native socket");
85 return service_impl_.assign(impl, protocol, native_socket, ec);
88 /// Determine whether the socket is open.
89 bool is_open(const implementation_type& impl) const
91 logger_.log("Checking if socket is open");
92 return service_impl_.is_open(impl);
95 /// Close a stream socket implementation.
96 boost::system::error_code close(implementation_type& impl,
97 boost::system::error_code& ec)
99 logger_.log("Closing socket");
100 return service_impl_.close(impl, ec);
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
107 logger_.log("Checking if socket is at out-of-band data mark");
108 return service_impl_.at_mark(impl, ec);
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
115 logger_.log("Determining number of bytes available for reading");
116 return service_impl_.available(impl, ec);
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)
123 logger_.log("Binding socket");
124 return service_impl_.bind(impl, endpoint, ec);
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)
131 logger_.log("Connecting socket to " +
132 boost::lexical_cast<std::string>(peer_endpoint));
133 return service_impl_.connect(impl, peer_endpoint, ec);
136 /// Handler to wrap asynchronous connect completion.
137 template <typename Handler>
138 class connect_handler
141 connect_handler(Handler h, logger& l)
147 void operator()(const boost::system::error_code& e)
151 std::string msg = "Asynchronous connect failed: ";
157 logger_.log("Asynchronous connect succeeded");
168 /// Start an asynchronous connect.
169 template <typename Handler>
170 void async_connect(implementation_type& impl,
171 const endpoint_type& peer_endpoint, Handler handler)
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_));
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)
184 logger_.log("Setting socket option");
185 return service_impl_.set_option(impl, option, ec);
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
193 logger_.log("Getting socket option");
194 return service_impl_.get_option(impl, option, ec);
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)
202 logger_.log("Performing IO control command on socket");
203 return service_impl_.io_control(impl, command, ec);
206 /// Get the local endpoint.
207 endpoint_type local_endpoint(const implementation_type& impl,
208 boost::system::error_code& ec) const
210 logger_.log("Getting socket's local endpoint");
211 return service_impl_.local_endpoint(impl, ec);
214 /// Get the remote endpoint.
215 endpoint_type remote_endpoint(const implementation_type& impl,
216 boost::system::error_code& ec) const
218 logger_.log("Getting socket's remote endpoint");
219 return service_impl_.remote_endpoint(impl, ec);
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)
227 logger_.log("Shutting down socket");
228 return service_impl_.shutdown(impl, what, ec);
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)
237 logger_.log("Sending data on socket");
238 return service_impl_.send(impl, buffers, flags, ec);
241 /// Handler to wrap asynchronous send completion.
242 template <typename Handler>
246 send_handler(Handler h, logger& l)
252 void operator()(const boost::system::error_code& e,
253 std::size_t bytes_transferred)
257 std::string msg = "Asynchronous send failed: ";
263 logger_.log("Asynchronous send succeeded");
266 handler_(e, bytes_transferred);
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)
279 logger_.log("Starting asynchronous send");
280 service_impl_.async_send(impl, buffers, flags,
281 send_handler<Handler>(handler, logger_));
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)
291 logger_.log("Receiving data on socket");
292 return service_impl_.receive(impl, buffers, flags, ec);
295 /// Handler to wrap asynchronous receive completion.
296 template <typename Handler>
297 class receive_handler
300 receive_handler(Handler h, logger& l)
306 void operator()(const boost::system::error_code& e,
307 std::size_t bytes_transferred)
311 std::string msg = "Asynchronous receive failed: ";
317 logger_.log("Asynchronous receive succeeded");
320 handler_(e, bytes_transferred);
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)
333 logger_.log("Starting asynchronous receive");
334 service_impl_.async_receive(impl, buffers, flags,
335 receive_handler<Handler>(handler, logger_));
339 /// The wrapped stream socket service.
340 service_impl_type& service_impl_;
342 /// The logger used for writing debug messages.
343 mutable logger logger_;
346 template <typename Protocol>
347 boost::asio::io_service::id stream_socket_service<Protocol>::id;
349 } // namespace services
351 #endif // SERVICES_STREAM_SOCKET_SERVICE_HPP