PageRenderTime 24ms CodeModel.GetById 10ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/src/contrib/boost/asio/detail/socket_select_interrupter.hpp

http://pythonocc.googlecode.com/
C++ Header | 194 lines | 141 code | 29 blank | 24 comment | 23 complexity | 8010d075b43080f0f5878517056c33ce MD5 | raw file
  1//
  2// socket_select_interrupter.hpp
  3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4//
  5// Copyright (c) 2003-2010 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 BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
 12#define BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
 13
 14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
 15# pragma once
 16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 17
 18#include <boost/asio/detail/push_options.hpp>
 19
 20#include <boost/asio/detail/push_options.hpp>
 21#include <cstdlib>
 22#include <boost/throw_exception.hpp>
 23#include <boost/system/system_error.hpp>
 24#include <boost/asio/detail/pop_options.hpp>
 25
 26#include <boost/asio/error.hpp>
 27#include <boost/asio/detail/socket_holder.hpp>
 28#include <boost/asio/detail/socket_ops.hpp>
 29#include <boost/asio/detail/socket_types.hpp>
 30
 31namespace boost {
 32namespace asio {
 33namespace detail {
 34
 35class socket_select_interrupter
 36{
 37public:
 38  // Constructor.
 39  socket_select_interrupter()
 40  {
 41    boost::system::error_code ec;
 42    socket_holder acceptor(socket_ops::socket(
 43          AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
 44    if (acceptor.get() == invalid_socket)
 45    {
 46      boost::system::system_error e(ec, "socket_select_interrupter");
 47      boost::throw_exception(e);
 48    }
 49
 50    int opt = 1;
 51    socket_ops::setsockopt(acceptor.get(),
 52        SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
 53
 54    using namespace std; // For memset.
 55    sockaddr_in4_type addr;
 56    std::size_t addr_len = sizeof(addr);
 57    memset(&addr, 0, sizeof(addr));
 58    addr.sin_family = AF_INET;
 59    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 60    addr.sin_port = 0;
 61    if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
 62          addr_len, ec) == socket_error_retval)
 63    {
 64      boost::system::system_error e(ec, "socket_select_interrupter");
 65      boost::throw_exception(e);
 66    }
 67
 68    if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
 69          &addr_len, ec) == socket_error_retval)
 70    {
 71      boost::system::system_error e(ec, "socket_select_interrupter");
 72      boost::throw_exception(e);
 73    }
 74
 75    // Some broken firewalls on Windows will intermittently cause getsockname to
 76    // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
 77    // explicitly specify the target address here to work around this problem.
 78    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 79
 80    if (socket_ops::listen(acceptor.get(),
 81          SOMAXCONN, ec) == socket_error_retval)
 82    {
 83      boost::system::system_error e(ec, "socket_select_interrupter");
 84      boost::throw_exception(e);
 85    }
 86
 87    socket_holder client(socket_ops::socket(
 88          AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
 89    if (client.get() == invalid_socket)
 90    {
 91      boost::system::system_error e(ec, "socket_select_interrupter");
 92      boost::throw_exception(e);
 93    }
 94
 95    if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
 96          addr_len, ec) == socket_error_retval)
 97    {
 98      boost::system::system_error e(ec, "socket_select_interrupter");
 99      boost::throw_exception(e);
100    }
101
102    socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
103    if (server.get() == invalid_socket)
104    {
105      boost::system::system_error e(ec, "socket_select_interrupter");
106      boost::throw_exception(e);
107    }
108    
109    ioctl_arg_type non_blocking = 1;
110    if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
111    {
112      boost::system::system_error e(ec, "socket_select_interrupter");
113      boost::throw_exception(e);
114    }
115
116    opt = 1;
117    socket_ops::setsockopt(client.get(),
118        IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
119
120    non_blocking = 1;
121    if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
122    {
123      boost::system::system_error e(ec, "socket_select_interrupter");
124      boost::throw_exception(e);
125    }
126
127    opt = 1;
128    socket_ops::setsockopt(server.get(),
129        IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
130
131    read_descriptor_ = server.release();
132    write_descriptor_ = client.release();
133  }
134
135  // Destructor.
136  ~socket_select_interrupter()
137  {
138    boost::system::error_code ec;
139    if (read_descriptor_ != invalid_socket)
140      socket_ops::close(read_descriptor_, ec);
141    if (write_descriptor_ != invalid_socket)
142      socket_ops::close(write_descriptor_, ec);
143  }
144
145  // Interrupt the select call.
146  void interrupt()
147  {
148    char byte = 0;
149    socket_ops::buf b;
150    socket_ops::init_buf(b, &byte, 1);
151    boost::system::error_code ec;
152    socket_ops::send(write_descriptor_, &b, 1, 0, ec);
153  }
154
155  // Reset the select interrupt. Returns true if the call was interrupted.
156  bool reset()
157  {
158    char data[1024];
159    socket_ops::buf b;
160    socket_ops::init_buf(b, data, sizeof(data));
161    boost::system::error_code ec;
162    int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
163    bool was_interrupted = (bytes_read > 0);
164    while (bytes_read == sizeof(data))
165      bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
166    return was_interrupted;
167  }
168
169  // Get the read descriptor to be passed to select.
170  socket_type read_descriptor() const
171  {
172    return read_descriptor_;
173  }
174
175private:
176  // The read end of a connection used to interrupt the select call. This file
177  // descriptor is passed to select such that when it is time to stop, a single
178  // byte will be written on the other end of the connection and this
179  // descriptor will become readable.
180  socket_type read_descriptor_;
181
182  // The write end of a connection used to interrupt the select call. A single
183  // byte may be written to this to wake up the select which is waiting for the
184  // other end to become readable.
185  socket_type write_descriptor_;
186};
187
188} // namespace detail
189} // namespace asio
190} // namespace boost
191
192#include <boost/asio/detail/pop_options.hpp>
193
194#endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP