socket_select_interrupter.hpp
Go to the documentation of this file.
00001 //
00002 // socket_select_interrupter.hpp
00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00004 //
00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
00006 //
00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00009 //
00010 
00011 #ifndef ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
00012 #define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
00013 
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017 
00018 #include "asio/detail/push_options.hpp"
00019 
00020 #include "asio/detail/push_options.hpp"
00021 #include <cstdlib>
00022 #include <boost/throw_exception.hpp>
00023 #include "asio/detail/pop_options.hpp"
00024 
00025 #include "asio/error.hpp"
00026 #include "asio/system_error.hpp"
00027 #include "asio/detail/socket_holder.hpp"
00028 #include "asio/detail/socket_ops.hpp"
00029 #include "asio/detail/socket_types.hpp"
00030 
00031 namespace asio {
00032 namespace detail {
00033 
00034 class socket_select_interrupter
00035 {
00036 public:
00037   // Constructor.
00038   socket_select_interrupter()
00039   {
00040     asio::error_code ec;
00041     socket_holder acceptor(socket_ops::socket(
00042           AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
00043     if (acceptor.get() == invalid_socket)
00044     {
00045       asio::system_error e(ec, "socket_select_interrupter");
00046       boost::throw_exception(e);
00047     }
00048 
00049     int opt = 1;
00050     socket_ops::setsockopt(acceptor.get(),
00051         SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
00052 
00053     using namespace std; // For memset.
00054     sockaddr_in4_type addr;
00055     std::size_t addr_len = sizeof(addr);
00056     memset(&addr, 0, sizeof(addr));
00057     addr.sin_family = AF_INET;
00058     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
00059     addr.sin_port = 0;
00060     if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
00061           addr_len, ec) == socket_error_retval)
00062     {
00063       asio::system_error e(ec, "socket_select_interrupter");
00064       boost::throw_exception(e);
00065     }
00066 
00067     if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
00068           &addr_len, ec) == socket_error_retval)
00069     {
00070       asio::system_error e(ec, "socket_select_interrupter");
00071       boost::throw_exception(e);
00072     }
00073 
00074     if (socket_ops::listen(acceptor.get(),
00075           SOMAXCONN, ec) == socket_error_retval)
00076     {
00077       asio::system_error e(ec, "socket_select_interrupter");
00078       boost::throw_exception(e);
00079     }
00080 
00081     socket_holder client(socket_ops::socket(
00082           AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
00083     if (client.get() == invalid_socket)
00084     {
00085       asio::system_error e(ec, "socket_select_interrupter");
00086       boost::throw_exception(e);
00087     }
00088 
00089     if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
00090           addr_len, ec) == socket_error_retval)
00091     {
00092       asio::system_error e(ec, "socket_select_interrupter");
00093       boost::throw_exception(e);
00094     }
00095 
00096     socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
00097     if (server.get() == invalid_socket)
00098     {
00099       asio::system_error e(ec, "socket_select_interrupter");
00100       boost::throw_exception(e);
00101     }
00102     
00103     ioctl_arg_type non_blocking = 1;
00104     if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
00105     {
00106       asio::system_error e(ec, "socket_select_interrupter");
00107       boost::throw_exception(e);
00108     }
00109 
00110     opt = 1;
00111     socket_ops::setsockopt(client.get(),
00112         IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
00113 
00114     non_blocking = 1;
00115     if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
00116     {
00117       asio::system_error e(ec, "socket_select_interrupter");
00118       boost::throw_exception(e);
00119     }
00120 
00121     opt = 1;
00122     socket_ops::setsockopt(server.get(),
00123         IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
00124 
00125     read_descriptor_ = server.release();
00126     write_descriptor_ = client.release();
00127   }
00128 
00129   // Destructor.
00130   ~socket_select_interrupter()
00131   {
00132     asio::error_code ec;
00133     if (read_descriptor_ != invalid_socket)
00134       socket_ops::close(read_descriptor_, ec);
00135     if (write_descriptor_ != invalid_socket)
00136       socket_ops::close(write_descriptor_, ec);
00137   }
00138 
00139   // Interrupt the select call.
00140   void interrupt()
00141   {
00142     char byte = 0;
00143     socket_ops::buf b;
00144     socket_ops::init_buf(b, &byte, 1);
00145     asio::error_code ec;
00146     socket_ops::send(write_descriptor_, &b, 1, 0, ec);
00147   }
00148 
00149   // Reset the select interrupt. Returns true if the call was interrupted.
00150   bool reset()
00151   {
00152     char data[1024];
00153     socket_ops::buf b;
00154     socket_ops::init_buf(b, data, sizeof(data));
00155     asio::error_code ec;
00156     int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
00157     bool was_interrupted = (bytes_read > 0);
00158     while (bytes_read == sizeof(data))
00159       bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
00160     return was_interrupted;
00161   }
00162 
00163   // Get the read descriptor to be passed to select.
00164   socket_type read_descriptor() const
00165   {
00166     return read_descriptor_;
00167   }
00168 
00169 private:
00170   // The read end of a connection used to interrupt the select call. This file
00171   // descriptor is passed to select such that when it is time to stop, a single
00172   // byte will be written on the other end of the connection and this
00173   // descriptor will become readable.
00174   socket_type read_descriptor_;
00175 
00176   // The write end of a connection used to interrupt the select call. A single
00177   // byte may be written to this to wake up the select which is waiting for the
00178   // other end to become readable.
00179   socket_type write_descriptor_;
00180 };
00181 
00182 } // namespace detail
00183 } // namespace asio
00184 
00185 #include "asio/detail/pop_options.hpp"
00186 
00187 #endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39