Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:35

0001 //
0002 // detail/impl/socket_select_interrupter.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
0012 #define BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0021 
0022 #if defined(BOOST_ASIO_WINDOWS) \
0023   || defined(__CYGWIN__) \
0024   || defined(__SYMBIAN32__)
0025 
0026 #include <cstdlib>
0027 #include <boost/asio/detail/socket_holder.hpp>
0028 #include <boost/asio/detail/socket_ops.hpp>
0029 #include <boost/asio/detail/socket_select_interrupter.hpp>
0030 #include <boost/asio/detail/throw_error.hpp>
0031 #include <boost/asio/error.hpp>
0032 
0033 #include <boost/asio/detail/push_options.hpp>
0034 
0035 namespace boost {
0036 namespace asio {
0037 namespace detail {
0038 
0039 socket_select_interrupter::socket_select_interrupter()
0040 {
0041   open_descriptors();
0042 }
0043 
0044 void socket_select_interrupter::open_descriptors()
0045 {
0046   boost::system::error_code ec;
0047   socket_holder acceptor(socket_ops::socket(
0048         AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
0049   if (acceptor.get() == invalid_socket)
0050     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0051 
0052   int opt = 1;
0053   socket_ops::state_type acceptor_state = 0;
0054   socket_ops::setsockopt(acceptor.get(), acceptor_state,
0055       SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
0056 
0057   using namespace std; // For memset.
0058   sockaddr_in4_type addr;
0059   std::size_t addr_len = sizeof(addr);
0060   memset(&addr, 0, sizeof(addr));
0061   addr.sin_family = AF_INET;
0062   addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
0063   addr.sin_port = 0;
0064   if (socket_ops::bind(acceptor.get(), &addr,
0065         addr_len, ec) == socket_error_retval)
0066     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0067 
0068   if (socket_ops::getsockname(acceptor.get(), &addr,
0069         &addr_len, ec) == socket_error_retval)
0070     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0071 
0072   // Some broken firewalls on Windows will intermittently cause getsockname to
0073   // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
0074   // explicitly specify the target address here to work around this problem.
0075   if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY))
0076     addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
0077 
0078   if (socket_ops::listen(acceptor.get(),
0079         SOMAXCONN, ec) == socket_error_retval)
0080     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0081 
0082   socket_holder client(socket_ops::socket(
0083         AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
0084   if (client.get() == invalid_socket)
0085     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0086 
0087   if (socket_ops::connect(client.get(), &addr,
0088         addr_len, ec) == socket_error_retval)
0089     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0090 
0091   socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
0092   if (server.get() == invalid_socket)
0093     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0094   
0095   ioctl_arg_type non_blocking = 1;
0096   socket_ops::state_type client_state = 0;
0097   if (socket_ops::ioctl(client.get(), client_state,
0098         FIONBIO, &non_blocking, ec))
0099     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0100 
0101   opt = 1;
0102   socket_ops::setsockopt(client.get(), client_state,
0103       IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
0104 
0105   non_blocking = 1;
0106   socket_ops::state_type server_state = 0;
0107   if (socket_ops::ioctl(server.get(), server_state,
0108         FIONBIO, &non_blocking, ec))
0109     boost::asio::detail::throw_error(ec, "socket_select_interrupter");
0110 
0111   opt = 1;
0112   socket_ops::setsockopt(server.get(), server_state,
0113       IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
0114 
0115   read_descriptor_ = server.release();
0116   write_descriptor_ = client.release();
0117 }
0118 
0119 socket_select_interrupter::~socket_select_interrupter()
0120 {
0121   close_descriptors();
0122 }
0123 
0124 void socket_select_interrupter::close_descriptors()
0125 {
0126   boost::system::error_code ec;
0127   socket_ops::state_type state = socket_ops::internal_non_blocking;
0128   if (read_descriptor_ != invalid_socket)
0129     socket_ops::close(read_descriptor_, state, true, ec);
0130   if (write_descriptor_ != invalid_socket)
0131     socket_ops::close(write_descriptor_, state, true, ec);
0132 }
0133 
0134 void socket_select_interrupter::recreate()
0135 {
0136   close_descriptors();
0137 
0138   write_descriptor_ = invalid_socket;
0139   read_descriptor_ = invalid_socket;
0140 
0141   open_descriptors();
0142 }
0143 
0144 void socket_select_interrupter::interrupt()
0145 {
0146   char byte = 0;
0147   socket_ops::buf b;
0148   socket_ops::init_buf(b, &byte, 1);
0149   boost::system::error_code ec;
0150   socket_ops::send(write_descriptor_, &b, 1, 0, ec);
0151 }
0152 
0153 bool socket_select_interrupter::reset()
0154 {
0155   char data[1024];
0156   socket_ops::buf b;
0157   socket_ops::init_buf(b, data, sizeof(data));
0158   boost::system::error_code ec;
0159   for (;;)
0160   {
0161     int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
0162     if (bytes_read == sizeof(data))
0163       continue;
0164     if (bytes_read > 0)
0165       return true;
0166     if (bytes_read == 0)
0167       return false;
0168     if (ec == boost::asio::error::would_block
0169         || ec == boost::asio::error::try_again)
0170       return true;
0171     return false;
0172   }
0173 }
0174 
0175 } // namespace detail
0176 } // namespace asio
0177 } // namespace boost
0178 
0179 #include <boost/asio/detail/pop_options.hpp>
0180 
0181 #endif // defined(BOOST_ASIO_WINDOWS)
0182        // || defined(__CYGWIN__)
0183        // || defined(__SYMBIAN32__)
0184 
0185 #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0186 
0187 #endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP