PageRenderTime 51ms CodeModel.GetById 10ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/asio/detail/win_iocp_socket_service.hpp

http://hadesmem.googlecode.com/
C++ Header | 509 lines | 373 code | 78 blank | 58 comment | 13 complexity | 45175a9fd187b2fb9c28d1d547faea56 MD5 | raw file
  1//
  2// detail/win_iocp_socket_service.hpp
  3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4//
  5// Copyright (c) 2003-2011 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_WIN_IOCP_SOCKET_SERVICE_HPP
 12#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_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/config.hpp>
 19
 20#if defined(BOOST_ASIO_HAS_IOCP)
 21
 22#include <cstring>
 23#include <boost/utility/addressof.hpp>
 24#include <boost/asio/error.hpp>
 25#include <boost/asio/io_service.hpp>
 26#include <boost/asio/socket_base.hpp>
 27#include <boost/asio/detail/bind_handler.hpp>
 28#include <boost/asio/detail/buffer_sequence_adapter.hpp>
 29#include <boost/asio/detail/fenced_block.hpp>
 30#include <boost/asio/detail/handler_alloc_helpers.hpp>
 31#include <boost/asio/detail/handler_invoke_helpers.hpp>
 32#include <boost/asio/detail/mutex.hpp>
 33#include <boost/asio/detail/operation.hpp>
 34#include <boost/asio/detail/reactive_socket_connect_op.hpp>
 35#include <boost/asio/detail/reactor.hpp>
 36#include <boost/asio/detail/reactor_op.hpp>
 37#include <boost/asio/detail/socket_holder.hpp>
 38#include <boost/asio/detail/socket_ops.hpp>
 39#include <boost/asio/detail/socket_types.hpp>
 40#include <boost/asio/detail/win_iocp_io_service.hpp>
 41#include <boost/asio/detail/win_iocp_null_buffers_op.hpp>
 42#include <boost/asio/detail/win_iocp_socket_accept_op.hpp>
 43#include <boost/asio/detail/win_iocp_socket_recvfrom_op.hpp>
 44#include <boost/asio/detail/win_iocp_socket_send_op.hpp>
 45#include <boost/asio/detail/win_iocp_socket_service_base.hpp>
 46
 47#include <boost/asio/detail/push_options.hpp>
 48
 49namespace boost {
 50namespace asio {
 51namespace detail {
 52
 53template <typename Protocol>
 54class win_iocp_socket_service : public win_iocp_socket_service_base
 55{
 56public:
 57  // The protocol type.
 58  typedef Protocol protocol_type;
 59
 60  // The endpoint type.
 61  typedef typename Protocol::endpoint endpoint_type;
 62
 63  // The native type of a socket.
 64  class native_handle_type
 65  {
 66  public:
 67    native_handle_type(socket_type s)
 68      : socket_(s),
 69        have_remote_endpoint_(false)
 70    {
 71    }
 72
 73    native_handle_type(socket_type s, const endpoint_type& ep)
 74      : socket_(s),
 75        have_remote_endpoint_(true),
 76        remote_endpoint_(ep)
 77    {
 78    }
 79
 80    void operator=(socket_type s)
 81    {
 82      socket_ = s;
 83      have_remote_endpoint_ = false;
 84      remote_endpoint_ = endpoint_type();
 85    }
 86
 87    operator socket_type() const
 88    {
 89      return socket_;
 90    }
 91
 92    bool have_remote_endpoint() const
 93    {
 94      return have_remote_endpoint_;
 95    }
 96
 97    endpoint_type remote_endpoint() const
 98    {
 99      return remote_endpoint_;
100    }
101
102  private:
103    socket_type socket_;
104    bool have_remote_endpoint_;
105    endpoint_type remote_endpoint_;
106  };
107
108  // The implementation type of the socket.
109  struct implementation_type :
110    win_iocp_socket_service_base::base_implementation_type
111  {
112    // Default constructor.
113    implementation_type()
114      : protocol_(endpoint_type().protocol()),
115        have_remote_endpoint_(false),
116        remote_endpoint_()
117    {
118    }
119
120    // The protocol associated with the socket.
121    protocol_type protocol_;
122
123    // Whether we have a cached remote endpoint.
124    bool have_remote_endpoint_;
125
126    // A cached remote endpoint.
127    endpoint_type remote_endpoint_;
128  };
129
130  // Constructor.
131  win_iocp_socket_service(boost::asio::io_service& io_service)
132    : win_iocp_socket_service_base(io_service)
133  {
134  }
135
136  // Move-construct a new socket implementation.
137  void move_construct(implementation_type& impl,
138      implementation_type& other_impl)
139  {
140    this->base_move_construct(impl, other_impl);
141
142    impl.protocol_ = other_impl.protocol_;
143    other_impl.protocol_ = endpoint_type().protocol();
144
145    impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
146    other_impl.have_remote_endpoint_ = false;
147
148    impl.remote_endpoint_ = other_impl.remote_endpoint_;
149    other_impl.remote_endpoint_ = endpoint_type();
150  }
151
152  // Move-assign from another socket implementation.
153  void move_assign(implementation_type& impl,
154      win_iocp_socket_service_base& other_service,
155      implementation_type& other_impl)
156  {
157    this->base_move_assign(impl, other_service, other_impl);
158
159    impl.protocol_ = other_impl.protocol_;
160    other_impl.protocol_ = endpoint_type().protocol();
161
162    impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
163    other_impl.have_remote_endpoint_ = false;
164
165    impl.remote_endpoint_ = other_impl.remote_endpoint_;
166    other_impl.remote_endpoint_ = endpoint_type();
167  }
168
169  // Open a new socket implementation.
170  boost::system::error_code open(implementation_type& impl,
171      const protocol_type& protocol, boost::system::error_code& ec)
172  {
173    if (!do_open(impl, protocol.family(),
174          protocol.type(), protocol.protocol(), ec))
175    {
176      impl.protocol_ = protocol;
177      impl.have_remote_endpoint_ = false;
178      impl.remote_endpoint_ = endpoint_type();
179    }
180    return ec;
181  }
182
183  // Assign a native socket to a socket implementation.
184  boost::system::error_code assign(implementation_type& impl,
185      const protocol_type& protocol, const native_handle_type& native_socket,
186      boost::system::error_code& ec)
187  {
188    if (!do_assign(impl, protocol.type(), native_socket, ec))
189    {
190      impl.protocol_ = protocol;
191      impl.have_remote_endpoint_ = native_socket.have_remote_endpoint();
192      impl.remote_endpoint_ = native_socket.remote_endpoint();
193    }
194    return ec;
195  }
196
197  // Get the native socket representation.
198  native_handle_type native_handle(implementation_type& impl)
199  {
200    if (impl.have_remote_endpoint_)
201      return native_handle_type(impl.socket_, impl.remote_endpoint_);
202    return native_handle_type(impl.socket_);
203  }
204
205  // Bind the socket to the specified local endpoint.
206  boost::system::error_code bind(implementation_type& impl,
207      const endpoint_type& endpoint, boost::system::error_code& ec)
208  {
209    socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
210    return ec;
211  }
212
213  // Set a socket option.
214  template <typename Option>
215  boost::system::error_code set_option(implementation_type& impl,
216      const Option& option, boost::system::error_code& ec)
217  {
218    socket_ops::setsockopt(impl.socket_, impl.state_,
219        option.level(impl.protocol_), option.name(impl.protocol_),
220        option.data(impl.protocol_), option.size(impl.protocol_), ec);
221    return ec;
222  }
223
224  // Set a socket option.
225  template <typename Option>
226  boost::system::error_code get_option(const implementation_type& impl,
227      Option& option, boost::system::error_code& ec) const
228  {
229    std::size_t size = option.size(impl.protocol_);
230    socket_ops::getsockopt(impl.socket_, impl.state_,
231        option.level(impl.protocol_), option.name(impl.protocol_),
232        option.data(impl.protocol_), &size, ec);
233    if (!ec)
234      option.resize(impl.protocol_, size);
235    return ec;
236  }
237
238  // Get the local endpoint.
239  endpoint_type local_endpoint(const implementation_type& impl,
240      boost::system::error_code& ec) const
241  {
242    endpoint_type endpoint;
243    std::size_t addr_len = endpoint.capacity();
244    if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
245      return endpoint_type();
246    endpoint.resize(addr_len);
247    return endpoint;
248  }
249
250  // Get the remote endpoint.
251  endpoint_type remote_endpoint(const implementation_type& impl,
252      boost::system::error_code& ec) const
253  {
254    endpoint_type endpoint = impl.remote_endpoint_;
255    std::size_t addr_len = endpoint.capacity();
256    if (socket_ops::getpeername(impl.socket_, endpoint.data(),
257          &addr_len, impl.have_remote_endpoint_, ec))
258      return endpoint_type();
259    endpoint.resize(addr_len);
260    return endpoint;
261  }
262
263  // Send a datagram to the specified endpoint. Returns the number of bytes
264  // sent.
265  template <typename ConstBufferSequence>
266  size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
267      const endpoint_type& destination, socket_base::message_flags flags,
268      boost::system::error_code& ec)
269  {
270    buffer_sequence_adapter<boost::asio::const_buffer,
271        ConstBufferSequence> bufs(buffers);
272
273    return socket_ops::sync_sendto(impl.socket_, impl.state_,
274        bufs.buffers(), bufs.count(), flags,
275        destination.data(), destination.size(), ec);
276  }
277
278  // Wait until data can be sent without blocking.
279  size_t send_to(implementation_type& impl, const null_buffers&,
280      const endpoint_type&, socket_base::message_flags,
281      boost::system::error_code& ec)
282  {
283    // Wait for socket to become ready.
284    socket_ops::poll_write(impl.socket_, ec);
285
286    return 0;
287  }
288
289  // Start an asynchronous send. The data being sent must be valid for the
290  // lifetime of the asynchronous operation.
291  template <typename ConstBufferSequence, typename Handler>
292  void async_send_to(implementation_type& impl,
293      const ConstBufferSequence& buffers, const endpoint_type& destination,
294      socket_base::message_flags flags, Handler handler)
295  {
296    // Allocate and construct an operation to wrap the handler.
297    typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
298    typename op::ptr p = { boost::addressof(handler),
299      boost_asio_handler_alloc_helpers::allocate(
300        sizeof(op), handler), 0 };
301    p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
302
303    BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to"));
304
305    buffer_sequence_adapter<boost::asio::const_buffer,
306        ConstBufferSequence> bufs(buffers);
307
308    start_send_to_op(impl, bufs.buffers(), bufs.count(),
309        destination.data(), static_cast<int>(destination.size()),
310        flags, p.p);
311    p.v = p.p = 0;
312  }
313
314  // Start an asynchronous wait until data can be sent without blocking.
315  template <typename Handler>
316  void async_send_to(implementation_type& impl, const null_buffers&,
317      const endpoint_type&, socket_base::message_flags, Handler handler)
318  {
319    // Allocate and construct an operation to wrap the handler.
320    typedef win_iocp_null_buffers_op<Handler> op;
321    typename op::ptr p = { boost::addressof(handler),
322      boost_asio_handler_alloc_helpers::allocate(
323        sizeof(op), handler), 0 };
324    p.p = new (p.v) op(impl.cancel_token_, handler);
325
326    BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
327          &impl, "async_send_to(null_buffers)"));
328
329    start_reactor_op(impl, reactor::write_op, p.p);
330    p.v = p.p = 0;
331  }
332
333  // Receive a datagram with the endpoint of the sender. Returns the number of
334  // bytes received.
335  template <typename MutableBufferSequence>
336  size_t receive_from(implementation_type& impl,
337      const MutableBufferSequence& buffers,
338      endpoint_type& sender_endpoint, socket_base::message_flags flags,
339      boost::system::error_code& ec)
340  {
341    buffer_sequence_adapter<boost::asio::mutable_buffer,
342        MutableBufferSequence> bufs(buffers);
343
344    std::size_t addr_len = sender_endpoint.capacity();
345    std::size_t bytes_recvd = socket_ops::sync_recvfrom(
346        impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
347        flags, sender_endpoint.data(), &addr_len, ec);
348
349    if (!ec)
350      sender_endpoint.resize(addr_len);
351
352    return bytes_recvd;
353  }
354
355  // Wait until data can be received without blocking.
356  size_t receive_from(implementation_type& impl,
357      const null_buffers&, endpoint_type& sender_endpoint,
358      socket_base::message_flags, boost::system::error_code& ec)
359  {
360    // Wait for socket to become ready.
361    socket_ops::poll_read(impl.socket_, ec);
362
363    // Reset endpoint since it can be given no sensible value at this time.
364    sender_endpoint = endpoint_type();
365
366    return 0;
367  }
368
369  // Start an asynchronous receive. The buffer for the data being received and
370  // the sender_endpoint object must both be valid for the lifetime of the
371  // asynchronous operation.
372  template <typename MutableBufferSequence, typename Handler>
373  void async_receive_from(implementation_type& impl,
374      const MutableBufferSequence& buffers, endpoint_type& sender_endp,
375      socket_base::message_flags flags, Handler handler)
376  {
377    // Allocate and construct an operation to wrap the handler.
378    typedef win_iocp_socket_recvfrom_op<
379      MutableBufferSequence, endpoint_type, Handler> op;
380    typename op::ptr p = { boost::addressof(handler),
381      boost_asio_handler_alloc_helpers::allocate(
382        sizeof(op), handler), 0 };
383    p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler);
384
385    BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive_from"));
386
387    buffer_sequence_adapter<boost::asio::mutable_buffer,
388        MutableBufferSequence> bufs(buffers);
389
390    start_receive_from_op(impl, bufs.buffers(), bufs.count(),
391        sender_endp.data(), flags, &p.p->endpoint_size(), p.p);
392    p.v = p.p = 0;
393  }
394
395  // Wait until data can be received without blocking.
396  template <typename Handler>
397  void async_receive_from(implementation_type& impl,
398      const null_buffers&, endpoint_type& sender_endpoint,
399      socket_base::message_flags flags, Handler handler)
400  {
401    // Allocate and construct an operation to wrap the handler.
402    typedef win_iocp_null_buffers_op<Handler> op;
403    typename op::ptr p = { boost::addressof(handler),
404      boost_asio_handler_alloc_helpers::allocate(
405        sizeof(op), handler), 0 };
406    p.p = new (p.v) op(impl.cancel_token_, handler);
407
408    BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl,
409          "async_receive_from(null_buffers)"));
410
411    // Reset endpoint since it can be given no sensible value at this time.
412    sender_endpoint = endpoint_type();
413
414    start_null_buffers_receive_op(impl, flags, p.p);
415    p.v = p.p = 0;
416  }
417
418  // Accept a new connection.
419  template <typename Socket>
420  boost::system::error_code accept(implementation_type& impl, Socket& peer,
421      endpoint_type* peer_endpoint, boost::system::error_code& ec)
422  {
423    // We cannot accept a socket that is already open.
424    if (peer.is_open())
425    {
426      ec = boost::asio::error::already_open;
427      return ec;
428    }
429
430    std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
431    socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
432          impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
433          peer_endpoint ? &addr_len : 0, ec));
434
435    // On success, assign new connection to peer socket object.
436    if (new_socket.get() >= 0)
437    {
438      if (peer_endpoint)
439        peer_endpoint->resize(addr_len);
440      if (!peer.assign(impl.protocol_, new_socket.get(), ec))
441        new_socket.release();
442    }
443
444    return ec;
445  }
446
447  // Start an asynchronous accept. The peer and peer_endpoint objects
448  // must be valid until the accept's handler is invoked.
449  template <typename Socket, typename Handler>
450  void async_accept(implementation_type& impl, Socket& peer,
451      endpoint_type* peer_endpoint, Handler handler)
452  {
453    // Allocate and construct an operation to wrap the handler.
454    typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op;
455    typename op::ptr p = { boost::addressof(handler),
456      boost_asio_handler_alloc_helpers::allocate(
457        sizeof(op), handler), 0 };
458    bool enable_connection_aborted =
459      (impl.state_ & socket_ops::enable_connection_aborted) != 0;
460    p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,
461        peer_endpoint, enable_connection_aborted, handler);
462
463    BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept"));
464
465    start_accept_op(impl, peer.is_open(), p.p->new_socket(),
466        impl.protocol_.family(), impl.protocol_.type(),
467        impl.protocol_.protocol(), p.p->output_buffer(),
468        p.p->address_length(), p.p);
469    p.v = p.p = 0;
470  }
471
472  // Connect the socket to the specified endpoint.
473  boost::system::error_code connect(implementation_type& impl,
474      const endpoint_type& peer_endpoint, boost::system::error_code& ec)
475  {
476    socket_ops::sync_connect(impl.socket_,
477        peer_endpoint.data(), peer_endpoint.size(), ec);
478    return ec;
479  }
480
481  // Start an asynchronous connect.
482  template <typename Handler>
483  void async_connect(implementation_type& impl,
484      const endpoint_type& peer_endpoint, Handler handler)
485  {
486    // Allocate and construct an operation to wrap the handler.
487    typedef reactive_socket_connect_op<Handler> op;
488    typename op::ptr p = { boost::addressof(handler),
489      boost_asio_handler_alloc_helpers::allocate(
490        sizeof(op), handler), 0 };
491    p.p = new (p.v) op(impl.socket_, handler);
492
493    BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
494
495    start_connect_op(impl, p.p, peer_endpoint.data(),
496        static_cast<int>(peer_endpoint.size()));
497    p.v = p.p = 0;
498  }
499};
500
501} // namespace detail
502} // namespace asio
503} // namespace boost
504
505#include <boost/asio/detail/pop_options.hpp>
506
507#endif // defined(BOOST_ASIO_HAS_IOCP)
508
509#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP