Kea: unix_domain_socket.cc Source File

| Kea 2.2.0

unix_domain_socket.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <asiolink/asio_wrapper.h>
10#include <asiolink/unix_domain_socket.h>
11#include <boost/enable_shared_from_this.hpp>
12#include <functional>
13#include <iostream>
14
15using namespace boost::asio::local;
16namespace ph = std::placeholders;
17
18namespace isc {
19namespace asiolink {
20
22 class UnixDomainSocketImpl : public boost::enable_shared_from_this<UnixDomainSocketImpl> {
23public:
24
28 UnixDomainSocketImpl(IOService& io_service)
29 : socket_(io_service.get_io_service()) {
30 }
31
35 ~UnixDomainSocketImpl() {
36 close();
37 }
38
47 void asyncConnect(const stream_protocol::endpoint& endpoint,
48 const UnixDomainSocket::ConnectHandler& handler);
49
62 void connectHandler(const UnixDomainSocket::ConnectHandler& remote_handler,
63 const boost::system::error_code& ec);
64
74 void asyncSend(const void* data, const size_t length,
75 const UnixDomainSocket::Handler& handler);
76
86 void doSend(const boost::asio::const_buffers_1& buffer,
87 const UnixDomainSocket::Handler& handler);
88
89
105 void sendHandler(const UnixDomainSocket::Handler& remote_handler,
106 const boost::asio::const_buffers_1& buffer,
107 const boost::system::error_code& ec,
108 size_t length);
109
119 void asyncReceive(void* data, const size_t length,
120 const UnixDomainSocket::Handler& handler);
121
130 void doReceive(const boost::asio::mutable_buffers_1& buffer,
131 const UnixDomainSocket::Handler& handler);
132
148 void receiveHandler(const UnixDomainSocket::Handler& remote_handler,
149 const boost::asio::mutable_buffers_1& buffer,
150 const boost::system::error_code& ec,
151 size_t length);
152
154 void shutdown();
155
157 void cancel();
158
160 void close();
161
163 stream_protocol::socket socket_;
164};
165
166void
167UnixDomainSocketImpl::asyncConnect(const stream_protocol::endpoint& endpoint,
168 const UnixDomainSocket::ConnectHandler& handler) {
169 auto local_handler = std::bind(&UnixDomainSocketImpl::connectHandler,
170 shared_from_this(),
171 handler, ph::_1);
172 socket_.async_connect(endpoint, local_handler);
173}
174
175void
176UnixDomainSocketImpl::connectHandler(const UnixDomainSocket::ConnectHandler& remote_handler,
177 const boost::system::error_code& ec) {
178 // It was observed on Debian and Fedora that asynchronous connect may result
179 // in EINPROGRESS error. This doesn't really indicate a problem with a
180 // connection. If we continue transmitting data over the socket it will
181 // succeed. So we suppress this error and return 'success' to the user's
182 // handler.
183 if (ec.value() == boost::asio::error::in_progress) {
184 remote_handler(boost::system::error_code());
185 } else {
186 remote_handler(ec);
187 }
188}
189
190void
191UnixDomainSocketImpl::asyncSend(const void* data, const size_t length,
192 const UnixDomainSocket::Handler& handler) {
193 doSend(boost::asio::buffer(data, length), handler);
194}
195
196void
197UnixDomainSocketImpl::doSend(const boost::asio::const_buffers_1& buffer,
198 const UnixDomainSocket::Handler& handler) {
199 auto local_handler = std::bind(&UnixDomainSocketImpl::sendHandler,
200 shared_from_this(),
201 handler, buffer, ph::_1, ph::_2);
202 socket_.async_send(buffer, local_handler);
203}
204
205void
206UnixDomainSocketImpl::sendHandler(const UnixDomainSocket::Handler& remote_handler,
207 const boost::asio::const_buffers_1& buffer,
208 const boost::system::error_code& ec,
209 size_t length) {
210 // The asynchronous send may return EWOULDBLOCK or EAGAIN on some
211 // operating systems. In this case, we simply retry hoping that it
212 // will succeed next time. The user's callback never sees these
213 // errors.
214 if ((ec.value() == boost::asio::error::would_block) ||
215 (ec.value() == boost::asio::error::try_again)) {
216 doSend(buffer, remote_handler);
217
218 } else {
219 remote_handler(ec, length);
220 }
221}
222
223void
224UnixDomainSocketImpl::asyncReceive(void* data, const size_t length,
225 const UnixDomainSocket::Handler& handler) {
226 doReceive(boost::asio::buffer(data, length), handler);
227}
228
229void
230UnixDomainSocketImpl::doReceive(const boost::asio::mutable_buffers_1& buffer,
231 const UnixDomainSocket::Handler& handler) {
232 auto local_handler = std::bind(&UnixDomainSocketImpl::receiveHandler,
233 shared_from_this(),
234 handler, buffer, ph::_1, ph::_2);
235 socket_.async_receive(buffer, 0, local_handler);
236}
237
238void
239UnixDomainSocketImpl::receiveHandler(const UnixDomainSocket::Handler& remote_handler,
240 const boost::asio::mutable_buffers_1& buffer,
241 const boost::system::error_code& ec,
242 size_t length) {
243 // The asynchronous receive may return EWOULDBLOCK or EAGAIN on some
244 // operating systems. In this case, we simply retry hoping that it
245 // will succeed next time. The user's callback never sees these
246 // errors.
247 if ((ec.value() == boost::asio::error::would_block) ||
248 (ec.value() == boost::asio::error::try_again)) {
249 doReceive(buffer, remote_handler);
250
251 } else {
252 remote_handler(ec, length);
253 }
254}
255
256void
257UnixDomainSocketImpl::shutdown() {
258 boost::system::error_code ec;
259 static_cast<void>(socket_.shutdown(stream_protocol::socket::shutdown_both, ec));
260 if (ec) {
261 isc_throw(UnixDomainSocketError, ec.message());
262 }
263}
264
265void
266UnixDomainSocketImpl::cancel() {
267 boost::system::error_code ec;
268 static_cast<void>(socket_.cancel(ec));
269 if (ec) {
270 isc_throw(UnixDomainSocketError, ec.message());
271 }
272}
273
274void
275UnixDomainSocketImpl::close() {
276 boost::system::error_code ec;
277 static_cast<void>(socket_.close(ec));
278 if (ec) {
279 isc_throw(UnixDomainSocketError, ec.message());
280 }
281}
282
283UnixDomainSocket::UnixDomainSocket(IOService& io_service)
284 : impl_(new UnixDomainSocketImpl(io_service)) {
285}
286
287int
288UnixDomainSocket::getNative() const {
289#if BOOST_VERSION < 106600
290 return (impl_->socket_.native());
291#else
292 return (impl_->socket_.native_handle());
293#endif
294}
295
296int
297UnixDomainSocket::getProtocol() const {
298 return (0);
299}
300
301void
302UnixDomainSocket::connect(const std::string& path) {
303 boost::system::error_code ec;
304 impl_->socket_.connect(stream_protocol::endpoint(path.c_str()), ec);
305 if (ec) {
306 isc_throw(UnixDomainSocketError, ec.message());
307 }
308}
309
310void
311UnixDomainSocket::asyncConnect(const std::string& path, const ConnectHandler& handler) {
312 impl_->asyncConnect(stream_protocol::endpoint(path.c_str()), handler);
313}
314
315size_t
316UnixDomainSocket::write(const void* data, size_t length) {
317 boost::system::error_code ec;
318 size_t res = boost::asio::write(impl_->socket_,
319 boost::asio::buffer(data, length),
320 boost::asio::transfer_all(),
321 ec);
322 if (ec) {
323 isc_throw(UnixDomainSocketError, ec.message());
324 }
325 return (res);
326}
327
328void
329UnixDomainSocket::asyncSend(const void* data, const size_t length,
330 const Handler& handler) {
331 impl_->asyncSend(data, length, handler);
332}
333
334size_t
335UnixDomainSocket::receive(void* data, size_t length) {
336 boost::system::error_code ec;
337 size_t res = impl_->socket_.receive(boost::asio::buffer(data, length), 0, ec);
338 if (ec) {
339 isc_throw(UnixDomainSocketError, ec.message());
340 }
341 return (res);
342}
343
344void
345UnixDomainSocket::asyncReceive(void* data, const size_t length,
346 const Handler& handler) {
347 impl_->asyncReceive(data, length, handler);
348}
349
350void
351UnixDomainSocket::shutdown() {
352 impl_->shutdown();
353}
354
355void
356UnixDomainSocket::cancel() {
357 impl_->cancel();
358}
359
360void
361UnixDomainSocket::close() {
362 impl_->close();
363}
364
365boost::asio::local::stream_protocol::socket&
366UnixDomainSocket::getASIOSocket() const {
367 return (impl_->socket_);
368}
369
370} // end of namespace asiolink
371} // end of namespace isc
asio_wrapper.h
isc::asiolink::IOService
The IOService class is a wrapper for the ASIO io_service class.
Definition: io_service.h:33
isc::asiolink::UnixDomainSocketError
Exception thrown upon socket error.
Definition: unix_domain_socket.h:20
isc::asiolink::UnixDomainSocketImpl
Implementation of the unix domain socket.
Definition: unix_domain_socket.cc:22
isc::asiolink::UnixDomainSocketImpl::cancel
void cancel()
Cancels asynchronous operations on the socket.
Definition: unix_domain_socket.cc:266
isc::asiolink::UnixDomainSocketImpl::doSend
void doSend(const boost::asio::const_buffers_1 &buffer, const UnixDomainSocket::Handler &handler)
Asynchronously sends the data over the socket.
Definition: unix_domain_socket.cc:197
isc::asiolink::UnixDomainSocketImpl::socket_
stream_protocol::socket socket_
Instance of the boost asio unix domain socket.
Definition: unix_domain_socket.cc:163
isc::asiolink::UnixDomainSocketImpl::receiveHandler
void receiveHandler(const UnixDomainSocket::Handler &remote_handler, const boost::asio::mutable_buffers_1 &buffer, const boost::system::error_code &ec, size_t length)
Local handler invoked as a result of asynchronous receive.
Definition: unix_domain_socket.cc:239
isc::asiolink::UnixDomainSocketImpl::shutdown
void shutdown()
Disables read and write operations on the socket.
Definition: unix_domain_socket.cc:257
isc::asiolink::UnixDomainSocketImpl::asyncSend
void asyncSend(const void *data, const size_t length, const UnixDomainSocket::Handler &handler)
Asynchronously sends data over the socket.
Definition: unix_domain_socket.cc:191
isc::asiolink::UnixDomainSocketImpl::doReceive
void doReceive(const boost::asio::mutable_buffers_1 &buffer, const UnixDomainSocket::Handler &handler)
Asynchronously receives the data over the socket.
Definition: unix_domain_socket.cc:230
isc::asiolink::UnixDomainSocketImpl::asyncConnect
void asyncConnect(const stream_protocol::endpoint &endpoint, const UnixDomainSocket::ConnectHandler &handler)
Asynchronously connects to an endpoint.
Definition: unix_domain_socket.cc:167
isc::asiolink::UnixDomainSocketImpl::connectHandler
void connectHandler(const UnixDomainSocket::ConnectHandler &remote_handler, const boost::system::error_code &ec)
Local handler invoked as a result of asynchronous connection.
Definition: unix_domain_socket.cc:176
isc::asiolink::UnixDomainSocketImpl::UnixDomainSocketImpl
UnixDomainSocketImpl(IOService &io_service)
Constructor.
Definition: unix_domain_socket.cc:28
isc::asiolink::UnixDomainSocketImpl::sendHandler
void sendHandler(const UnixDomainSocket::Handler &remote_handler, const boost::asio::const_buffers_1 &buffer, const boost::system::error_code &ec, size_t length)
Local handler invoked as a result of asynchronous send.
Definition: unix_domain_socket.cc:206
isc::asiolink::UnixDomainSocketImpl::asyncReceive
void asyncReceive(void *data, const size_t length, const UnixDomainSocket::Handler &handler)
Asynchronously receive data over the socket.
Definition: unix_domain_socket.cc:224
isc::asiolink::UnixDomainSocketImpl::close
void close()
Closes the socket.
Definition: unix_domain_socket.cc:275
isc::asiolink::UnixDomainSocketImpl::~UnixDomainSocketImpl
~UnixDomainSocketImpl()
Destructor.
Definition: unix_domain_socket.cc:35
isc::asiolink::UnixDomainSocket::Handler
std::function< void(const boost::system::error_code &, size_t)> Handler
Callback type used in calls to UnixDomainSocket::asyncSend and UnixDomainSocket::asyncReceive.
Definition: unix_domain_socket.h:38
isc::asiolink::UnixDomainSocket::close
void close()
Closes the socket.
Definition: unix_domain_socket.cc:361
isc::asiolink::UnixDomainSocket::asyncConnect
void asyncConnect(const std::string &path, const ConnectHandler &handler)
Asynchronously connects the socket to the specified endpoint.
Definition: unix_domain_socket.cc:311
isc::asiolink::UnixDomainSocket::asyncSend
void asyncSend(const void *data, const size_t length, const Handler &handler)
Asynchronously sends data over the socket.
Definition: unix_domain_socket.cc:329
isc::asiolink::UnixDomainSocket::write
size_t write(const void *data, size_t length)
Writes specified amount of data to a socket.
Definition: unix_domain_socket.cc:316
isc::asiolink::UnixDomainSocket::shutdown
void shutdown()
Disables read and write operations on the socket.
Definition: unix_domain_socket.cc:351
isc::asiolink::UnixDomainSocket::ConnectHandler
std::function< void(const boost::system::error_code &)> ConnectHandler
Callback type used in call to UnixDomainSocket::asyncConnect.
Definition: unix_domain_socket.h:34
isc::asiolink::UnixDomainSocket::receive
size_t receive(void *data, size_t length)
Receives data from a socket.
Definition: unix_domain_socket.cc:335
isc::asiolink::UnixDomainSocket::asyncReceive
void asyncReceive(void *data, const size_t length, const Handler &handler)
Asynchronously receives data over the socket.
Definition: unix_domain_socket.cc:345
isc::asiolink::UnixDomainSocket::UnixDomainSocket
UnixDomainSocket(IOService &io_service)
Constructor.
Definition: unix_domain_socket.cc:283
isc::asiolink::UnixDomainSocket::getASIOSocket
virtual boost::asio::local::stream_protocol::socket & getASIOSocket() const
Returns reference to the underlying ASIO socket.
Definition: unix_domain_socket.cc:366
isc::asiolink::UnixDomainSocket::getNative
virtual int getNative() const
Returns native socket representation.
Definition: unix_domain_socket.cc:288
isc::asiolink::UnixDomainSocket::getProtocol
virtual int getProtocol() const
Always returns 0.
Definition: unix_domain_socket.cc:297
isc::asiolink::UnixDomainSocket::connect
void connect(const std::string &path)
Connects the socket to the specified endpoint.
Definition: unix_domain_socket.cc:302
isc::asiolink::UnixDomainSocket::cancel
void cancel()
Cancels scheduled asynchronous operations on the socket.
Definition: unix_domain_socket.cc:356
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:210
asiolink
A wrapper interface for the ASIO library.
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
unix_domain_socket.h