Statistics
| Revision:

root / tmp / org.txm.statsengine.r.core.win32 / res / win32 / library / BH / include / boost / asio / detail / impl / win_iocp_socket_service_base.ipp @ 2486

History | View | Annotate | Download (22.6 kB)

1
//
2
// detail/impl/win_iocp_socket_service_base.ipp
3
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
//
5
// Copyright (c) 2003-2015 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_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
12
#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
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 <boost/asio/detail/win_iocp_socket_service_base.hpp>
23

    
24
#include <boost/asio/detail/push_options.hpp>
25

    
26
namespace boost {
27
namespace asio {
28
namespace detail {
29

    
30
win_iocp_socket_service_base::win_iocp_socket_service_base(
31
    boost::asio::io_service& io_service)
32
  : io_service_(io_service),
33
    iocp_service_(use_service<win_iocp_io_service>(io_service)),
34
    reactor_(0),
35
    connect_ex_(0),
36
    mutex_(),
37
    impl_list_(0)
38
{
39
}
40

    
41
void win_iocp_socket_service_base::shutdown_service()
42
{
43
  // Close all implementations, causing all operations to complete.
44
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
45
  base_implementation_type* impl = impl_list_;
46
  while (impl)
47
  {
48
    boost::system::error_code ignored_ec;
49
    close_for_destruction(*impl);
50
    impl = impl->next_;
51
  }
52
}
53

    
54
void win_iocp_socket_service_base::construct(
55
    win_iocp_socket_service_base::base_implementation_type& impl)
56
{
57
  impl.socket_ = invalid_socket;
58
  impl.state_ = 0;
59
  impl.cancel_token_.reset();
60
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
61
  impl.safe_cancellation_thread_id_ = 0;
62
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
63

    
64
  // Insert implementation into linked list of all implementations.
65
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
66
  impl.next_ = impl_list_;
67
  impl.prev_ = 0;
68
  if (impl_list_)
69
    impl_list_->prev_ = &impl;
70
  impl_list_ = &impl;
71
}
72

    
73
void win_iocp_socket_service_base::base_move_construct(
74
    win_iocp_socket_service_base::base_implementation_type& impl,
75
    win_iocp_socket_service_base::base_implementation_type& other_impl)
76
{
77
  impl.socket_ = other_impl.socket_;
78
  other_impl.socket_ = invalid_socket;
79

    
80
  impl.state_ = other_impl.state_;
81
  other_impl.state_ = 0;
82

    
83
  impl.cancel_token_ = other_impl.cancel_token_;
84
  other_impl.cancel_token_.reset();
85

    
86
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
87
  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
88
  other_impl.safe_cancellation_thread_id_ = 0;
89
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
90

    
91
  // Insert implementation into linked list of all implementations.
92
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
93
  impl.next_ = impl_list_;
94
  impl.prev_ = 0;
95
  if (impl_list_)
96
    impl_list_->prev_ = &impl;
97
  impl_list_ = &impl;
98
}
99

    
100
void win_iocp_socket_service_base::base_move_assign(
101
    win_iocp_socket_service_base::base_implementation_type& impl,
102
    win_iocp_socket_service_base& other_service,
103
    win_iocp_socket_service_base::base_implementation_type& other_impl)
104
{
105
  close_for_destruction(impl);
106

    
107
  if (this != &other_service)
108
  {
109
    // Remove implementation from linked list of all implementations.
110
    boost::asio::detail::mutex::scoped_lock lock(mutex_);
111
    if (impl_list_ == &impl)
112
      impl_list_ = impl.next_;
113
    if (impl.prev_)
114
      impl.prev_->next_ = impl.next_;
115
    if (impl.next_)
116
      impl.next_->prev_= impl.prev_;
117
    impl.next_ = 0;
118
    impl.prev_ = 0;
119
  }
120

    
121
  impl.socket_ = other_impl.socket_;
122
  other_impl.socket_ = invalid_socket;
123

    
124
  impl.state_ = other_impl.state_;
125
  other_impl.state_ = 0;
126

    
127
  impl.cancel_token_ = other_impl.cancel_token_;
128
  other_impl.cancel_token_.reset();
129

    
130
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
131
  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
132
  other_impl.safe_cancellation_thread_id_ = 0;
133
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
134

    
135
  if (this != &other_service)
136
  {
137
    // Insert implementation into linked list of all implementations.
138
    boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
139
    impl.next_ = other_service.impl_list_;
140
    impl.prev_ = 0;
141
    if (other_service.impl_list_)
142
      other_service.impl_list_->prev_ = &impl;
143
    other_service.impl_list_ = &impl;
144
  }
145
}
146

    
147
void win_iocp_socket_service_base::destroy(
148
    win_iocp_socket_service_base::base_implementation_type& impl)
149
{
150
  close_for_destruction(impl);
151

    
152
  // Remove implementation from linked list of all implementations.
153
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
154
  if (impl_list_ == &impl)
155
    impl_list_ = impl.next_;
156
  if (impl.prev_)
157
    impl.prev_->next_ = impl.next_;
158
  if (impl.next_)
159
    impl.next_->prev_= impl.prev_;
160
  impl.next_ = 0;
161
  impl.prev_ = 0;
162
}
163

    
164
boost::system::error_code win_iocp_socket_service_base::close(
165
    win_iocp_socket_service_base::base_implementation_type& impl,
166
    boost::system::error_code& ec)
167
{
168
  if (is_open(impl))
169
  {
170
    BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
171

    
172
    // Check if the reactor was created, in which case we need to close the
173
    // socket on the reactor as well to cancel any operations that might be
174
    // running there.
175
    reactor* r = static_cast<reactor*>(
176
          interlocked_compare_exchange_pointer(
177
            reinterpret_cast<void**>(&reactor_), 0, 0));
178
    if (r)
179
      r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
180
  }
181

    
182
  socket_ops::close(impl.socket_, impl.state_, false, ec);
183

    
184
  impl.socket_ = invalid_socket;
185
  impl.state_ = 0;
186
  impl.cancel_token_.reset();
187
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
188
  impl.safe_cancellation_thread_id_ = 0;
189
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
190

    
191
  return ec;
192
}
193

    
194
boost::system::error_code win_iocp_socket_service_base::cancel(
195
    win_iocp_socket_service_base::base_implementation_type& impl,
196
    boost::system::error_code& ec)
197
{
198
  if (!is_open(impl))
199
  {
200
    ec = boost::asio::error::bad_descriptor;
201
    return ec;
202
  }
203

    
204
  BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel"));
205

    
206
  if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
207
        ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
208
  {
209
    // The version of Windows supports cancellation from any thread.
210
    typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
211
    cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
212
    socket_type sock = impl.socket_;
213
    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
214
    if (!cancel_io_ex(sock_as_handle, 0))
215
    {
216
      DWORD last_error = ::GetLastError();
217
      if (last_error == ERROR_NOT_FOUND)
218
      {
219
        // ERROR_NOT_FOUND means that there were no operations to be
220
        // cancelled. We swallow this error to match the behaviour on other
221
        // platforms.
222
        ec = boost::system::error_code();
223
      }
224
      else
225
      {
226
        ec = boost::system::error_code(last_error,
227
            boost::asio::error::get_system_category());
228
      }
229
    }
230
    else
231
    {
232
      ec = boost::system::error_code();
233
    }
234
  }
235
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
236
  else if (impl.safe_cancellation_thread_id_ == 0)
237
  {
238
    // No operations have been started, so there's nothing to cancel.
239
    ec = boost::system::error_code();
240
  }
241
  else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
242
  {
243
    // Asynchronous operations have been started from the current thread only,
244
    // so it is safe to try to cancel them using CancelIo.
245
    socket_type sock = impl.socket_;
246
    HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
247
    if (!::CancelIo(sock_as_handle))
248
    {
249
      DWORD last_error = ::GetLastError();
250
      ec = boost::system::error_code(last_error,
251
          boost::asio::error::get_system_category());
252
    }
253
    else
254
    {
255
      ec = boost::system::error_code();
256
    }
257
  }
258
  else
259
  {
260
    // Asynchronous operations have been started from more than one thread,
261
    // so cancellation is not safe.
262
    ec = boost::asio::error::operation_not_supported;
263
  }
264
#else // defined(BOOST_ASIO_ENABLE_CANCELIO)
265
  else
266
  {
267
    // Cancellation is not supported as CancelIo may not be used.
268
    ec = boost::asio::error::operation_not_supported;
269
  }
270
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
271

    
272
  // Cancel any operations started via the reactor.
273
  if (!ec)
274
  {
275
    reactor* r = static_cast<reactor*>(
276
          interlocked_compare_exchange_pointer(
277
            reinterpret_cast<void**>(&reactor_), 0, 0));
278
    if (r)
279
      r->cancel_ops(impl.socket_, impl.reactor_data_);
280
  }
281

    
282
  return ec;
283
}
284

    
285
boost::system::error_code win_iocp_socket_service_base::do_open(
286
    win_iocp_socket_service_base::base_implementation_type& impl,
287
    int family, int type, int protocol, boost::system::error_code& ec)
288
{
289
  if (is_open(impl))
290
  {
291
    ec = boost::asio::error::already_open;
292
    return ec;
293
  }
294

    
295
  socket_holder sock(socket_ops::socket(family, type, protocol, ec));
296
  if (sock.get() == invalid_socket)
297
    return ec;
298

    
299
  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
300
  if (iocp_service_.register_handle(sock_as_handle, ec))
301
    return ec;
302

    
303
  impl.socket_ = sock.release();
304
  switch (type)
305
  {
306
  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
307
  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
308
  default: impl.state_ = 0; break;
309
  }
310
  impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
311
  ec = boost::system::error_code();
312
  return ec;
313
}
314

    
315
boost::system::error_code win_iocp_socket_service_base::do_assign(
316
    win_iocp_socket_service_base::base_implementation_type& impl,
317
    int type, socket_type native_socket, boost::system::error_code& ec)
318
{
319
  if (is_open(impl))
320
  {
321
    ec = boost::asio::error::already_open;
322
    return ec;
323
  }
324

    
325
  HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
326
  if (iocp_service_.register_handle(sock_as_handle, ec))
327
    return ec;
328

    
329
  impl.socket_ = native_socket;
330
  switch (type)
331
  {
332
  case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
333
  case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
334
  default: impl.state_ = 0; break;
335
  }
336
  impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
337
  ec = boost::system::error_code();
338
  return ec;
339
}
340

    
341
void win_iocp_socket_service_base::start_send_op(
342
    win_iocp_socket_service_base::base_implementation_type& impl,
343
    WSABUF* buffers, std::size_t buffer_count,
344
    socket_base::message_flags flags, bool noop, operation* op)
345
{
346
  update_cancellation_thread_id(impl);
347
  iocp_service_.work_started();
348

    
349
  if (noop)
350
    iocp_service_.on_completion(op);
351
  else if (!is_open(impl))
352
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
353
  else
354
  {
355
    DWORD bytes_transferred = 0;
356
    int result = ::WSASend(impl.socket_, buffers,
357
        static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
358
    DWORD last_error = ::WSAGetLastError();
359
    if (last_error == ERROR_PORT_UNREACHABLE)
360
      last_error = WSAECONNREFUSED;
361
    if (result != 0 && last_error != WSA_IO_PENDING)
362
      iocp_service_.on_completion(op, last_error, bytes_transferred);
363
    else
364
      iocp_service_.on_pending(op);
365
  }
366
}
367

    
368
void win_iocp_socket_service_base::start_send_to_op(
369
    win_iocp_socket_service_base::base_implementation_type& impl,
370
    WSABUF* buffers, std::size_t buffer_count,
371
    const socket_addr_type* addr, int addrlen,
372
    socket_base::message_flags flags, operation* op)
373
{
374
  update_cancellation_thread_id(impl);
375
  iocp_service_.work_started();
376

    
377
  if (!is_open(impl))
378
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
379
  else
380
  {
381
    DWORD bytes_transferred = 0;
382
    int result = ::WSASendTo(impl.socket_, buffers,
383
        static_cast<DWORD>(buffer_count),
384
        &bytes_transferred, flags, addr, addrlen, op, 0);
385
    DWORD last_error = ::WSAGetLastError();
386
    if (last_error == ERROR_PORT_UNREACHABLE)
387
      last_error = WSAECONNREFUSED;
388
    if (result != 0 && last_error != WSA_IO_PENDING)
389
      iocp_service_.on_completion(op, last_error, bytes_transferred);
390
    else
391
      iocp_service_.on_pending(op);
392
  }
393
}
394

    
395
void win_iocp_socket_service_base::start_receive_op(
396
    win_iocp_socket_service_base::base_implementation_type& impl,
397
    WSABUF* buffers, std::size_t buffer_count,
398
    socket_base::message_flags flags, bool noop, operation* op)
399
{
400
  update_cancellation_thread_id(impl);
401
  iocp_service_.work_started();
402

    
403
  if (noop)
404
    iocp_service_.on_completion(op);
405
  else if (!is_open(impl))
406
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
407
  else
408
  {
409
    DWORD bytes_transferred = 0;
410
    DWORD recv_flags = flags;
411
    int result = ::WSARecv(impl.socket_, buffers,
412
        static_cast<DWORD>(buffer_count),
413
        &bytes_transferred, &recv_flags, op, 0);
414
    DWORD last_error = ::WSAGetLastError();
415
    if (last_error == ERROR_NETNAME_DELETED)
416
      last_error = WSAECONNRESET;
417
    else if (last_error == ERROR_PORT_UNREACHABLE)
418
      last_error = WSAECONNREFUSED;
419
    if (result != 0 && last_error != WSA_IO_PENDING)
420
      iocp_service_.on_completion(op, last_error, bytes_transferred);
421
    else
422
      iocp_service_.on_pending(op);
423
  }
424
}
425

    
426
void win_iocp_socket_service_base::start_null_buffers_receive_op(
427
    win_iocp_socket_service_base::base_implementation_type& impl,
428
    socket_base::message_flags flags, reactor_op* op)
429
{
430
  if ((impl.state_ & socket_ops::stream_oriented) != 0)
431
  {
432
    // For stream sockets on Windows, we may issue a 0-byte overlapped
433
    // WSARecv to wait until there is data available on the socket.
434
    ::WSABUF buf = { 0, 0 };
435
    start_receive_op(impl, &buf, 1, flags, false, op);
436
  }
437
  else
438
  {
439
    start_reactor_op(impl,
440
        (flags & socket_base::message_out_of_band)
441
          ? reactor::except_op : reactor::read_op,
442
        op);
443
  }
444
}
445

    
446
void win_iocp_socket_service_base::start_receive_from_op(
447
    win_iocp_socket_service_base::base_implementation_type& impl,
448
    WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
449
    socket_base::message_flags flags, int* addrlen, operation* op)
450
{
451
  update_cancellation_thread_id(impl);
452
  iocp_service_.work_started();
453

    
454
  if (!is_open(impl))
455
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
456
  else
457
  {
458
    DWORD bytes_transferred = 0;
459
    DWORD recv_flags = flags;
460
    int result = ::WSARecvFrom(impl.socket_, buffers,
461
        static_cast<DWORD>(buffer_count),
462
        &bytes_transferred, &recv_flags, addr, addrlen, op, 0);
463
    DWORD last_error = ::WSAGetLastError();
464
    if (last_error == ERROR_PORT_UNREACHABLE)
465
      last_error = WSAECONNREFUSED;
466
    if (result != 0 && last_error != WSA_IO_PENDING)
467
      iocp_service_.on_completion(op, last_error, bytes_transferred);
468
    else
469
      iocp_service_.on_pending(op);
470
  }
471
}
472

    
473
void win_iocp_socket_service_base::start_accept_op(
474
    win_iocp_socket_service_base::base_implementation_type& impl,
475
    bool peer_is_open, socket_holder& new_socket, int family, int type,
476
    int protocol, void* output_buffer, DWORD address_length, operation* op)
477
{
478
  update_cancellation_thread_id(impl);
479
  iocp_service_.work_started();
480

    
481
  if (!is_open(impl))
482
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
483
  else if (peer_is_open)
484
    iocp_service_.on_completion(op, boost::asio::error::already_open);
485
  else
486
  {
487
    boost::system::error_code ec;
488
    new_socket.reset(socket_ops::socket(family, type, protocol, ec));
489
    if (new_socket.get() == invalid_socket)
490
      iocp_service_.on_completion(op, ec);
491
    else
492
    {
493
      DWORD bytes_read = 0;
494
      BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
495
          0, address_length, address_length, &bytes_read, op);
496
      DWORD last_error = ::WSAGetLastError();
497
      if (!result && last_error != WSA_IO_PENDING)
498
        iocp_service_.on_completion(op, last_error);
499
      else
500
        iocp_service_.on_pending(op);
501
    }
502
  }
503
}
504

    
505
void win_iocp_socket_service_base::restart_accept_op(
506
    socket_type s, socket_holder& new_socket, int family, int type,
507
    int protocol, void* output_buffer, DWORD address_length, operation* op)
508
{
509
  new_socket.reset();
510
  iocp_service_.work_started();
511

    
512
  boost::system::error_code ec;
513
  new_socket.reset(socket_ops::socket(family, type, protocol, ec));
514
  if (new_socket.get() == invalid_socket)
515
    iocp_service_.on_completion(op, ec);
516
  else
517
  {
518
    DWORD bytes_read = 0;
519
    BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
520
        0, address_length, address_length, &bytes_read, op);
521
    DWORD last_error = ::WSAGetLastError();
522
    if (!result && last_error != WSA_IO_PENDING)
523
      iocp_service_.on_completion(op, last_error);
524
    else
525
      iocp_service_.on_pending(op);
526
  }
527
}
528

    
529
void win_iocp_socket_service_base::start_reactor_op(
530
    win_iocp_socket_service_base::base_implementation_type& impl,
531
    int op_type, reactor_op* op)
532
{
533
  reactor& r = get_reactor();
534
  update_cancellation_thread_id(impl);
535

    
536
  if (is_open(impl))
537
  {
538
    r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false);
539
    return;
540
  }
541
  else
542
    op->ec_ = boost::asio::error::bad_descriptor;
543

    
544
  iocp_service_.post_immediate_completion(op, false);
545
}
546

    
547
void win_iocp_socket_service_base::start_connect_op(
548
    win_iocp_socket_service_base::base_implementation_type& impl,
549
    int family, int type, const socket_addr_type* addr,
550
    std::size_t addrlen, win_iocp_socket_connect_op_base* op)
551
{
552
  // If ConnectEx is available, use that.
553
  if (family == BOOST_ASIO_OS_DEF(AF_INET)
554
      || family == BOOST_ASIO_OS_DEF(AF_INET6))
555
  {
556
    if (connect_ex_fn connect_ex = get_connect_ex(impl, type))
557
    {
558
      union address_union
559
      {
560
        socket_addr_type base;
561
        sockaddr_in4_type v4;
562
        sockaddr_in6_type v6;
563
      } a;
564

    
565
      using namespace std; // For memset.
566
      memset(&a, 0, sizeof(a));
567
      a.base.sa_family = family;
568

    
569
      socket_ops::bind(impl.socket_, &a.base,
570
          family == BOOST_ASIO_OS_DEF(AF_INET)
571
          ? sizeof(a.v4) : sizeof(a.v6), op->ec_);
572
      if (op->ec_ && op->ec_ != boost::asio::error::invalid_argument)
573
      {
574
        iocp_service_.post_immediate_completion(op, false);
575
        return;
576
      }
577

    
578
      op->connect_ex_ = true;
579
      update_cancellation_thread_id(impl);
580
      iocp_service_.work_started();
581

    
582
      BOOL result = connect_ex(impl.socket_,
583
          addr, static_cast<int>(addrlen), 0, 0, 0, op);
584
      DWORD last_error = ::WSAGetLastError();
585
      if (!result && last_error != WSA_IO_PENDING)
586
        iocp_service_.on_completion(op, last_error);
587
      else
588
        iocp_service_.on_pending(op);
589
      return;
590
    }
591
  }
592

    
593
  // Otherwise, fall back to a reactor-based implementation.
594
  reactor& r = get_reactor();
595
  update_cancellation_thread_id(impl);
596

    
597
  if ((impl.state_ & socket_ops::non_blocking) != 0
598
      || socket_ops::set_internal_non_blocking(
599
        impl.socket_, impl.state_, true, op->ec_))
600
  {
601
    if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
602
    {
603
      if (op->ec_ == boost::asio::error::in_progress
604
          || op->ec_ == boost::asio::error::would_block)
605
      {
606
        op->ec_ = boost::system::error_code();
607
        r.start_op(reactor::connect_op, impl.socket_,
608
            impl.reactor_data_, op, false, false);
609
        return;
610
      }
611
    }
612
  }
613

    
614
  r.post_immediate_completion(op, false);
615
}
616

    
617
void win_iocp_socket_service_base::close_for_destruction(
618
    win_iocp_socket_service_base::base_implementation_type& impl)
619
{
620
  if (is_open(impl))
621
  {
622
    BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
623

    
624
    // Check if the reactor was created, in which case we need to close the
625
    // socket on the reactor as well to cancel any operations that might be
626
    // running there.
627
    reactor* r = static_cast<reactor*>(
628
          interlocked_compare_exchange_pointer(
629
            reinterpret_cast<void**>(&reactor_), 0, 0));
630
    if (r)
631
      r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
632
  }
633

    
634
  boost::system::error_code ignored_ec;
635
  socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
636
  impl.socket_ = invalid_socket;
637
  impl.state_ = 0;
638
  impl.cancel_token_.reset();
639
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
640
  impl.safe_cancellation_thread_id_ = 0;
641
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
642
}
643

    
644
void win_iocp_socket_service_base::update_cancellation_thread_id(
645
    win_iocp_socket_service_base::base_implementation_type& impl)
646
{
647
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
648
  if (impl.safe_cancellation_thread_id_ == 0)
649
    impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
650
  else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
651
    impl.safe_cancellation_thread_id_ = ~DWORD(0);
652
#else // defined(BOOST_ASIO_ENABLE_CANCELIO)
653
  (void)impl;
654
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
655
}
656

    
657
reactor& win_iocp_socket_service_base::get_reactor()
658
{
659
  reactor* r = static_cast<reactor*>(
660
        interlocked_compare_exchange_pointer(
661
          reinterpret_cast<void**>(&reactor_), 0, 0));
662
  if (!r)
663
  {
664
    r = &(use_service<reactor>(io_service_));
665
    interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
666
  }
667
  return *r;
668
}
669

    
670
win_iocp_socket_service_base::connect_ex_fn
671
win_iocp_socket_service_base::get_connect_ex(
672
    win_iocp_socket_service_base::base_implementation_type& impl, int type)
673
{
674
#if defined(BOOST_ASIO_DISABLE_CONNECTEX)
675
  (void)impl;
676
  (void)type;
677
  return 0;
678
#else // defined(BOOST_ASIO_DISABLE_CONNECTEX)
679
  if (type != BOOST_ASIO_OS_DEF(SOCK_STREAM)
680
      && type != BOOST_ASIO_OS_DEF(SOCK_SEQPACKET))
681
    return 0;
682

    
683
  void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0);
684
  if (!ptr)
685
  {
686
    GUID guid = { 0x25a207b9, 0xddf3, 0x4660,
687
      { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } };
688

    
689
    DWORD bytes = 0;
690
    if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
691
          &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0)
692
    {
693
      // Set connect_ex_ to a special value to indicate that ConnectEx is
694
      // unavailable. That way we won't bother trying to look it up again.
695
      ptr = this;
696
    }
697

    
698
    interlocked_exchange_pointer(&connect_ex_, ptr);
699
  }
700

    
701
  return reinterpret_cast<connect_ex_fn>(ptr == this ? 0 : ptr);
702
#endif // defined(BOOST_ASIO_DISABLE_CONNECTEX)
703
}
704

    
705
void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
706
    void** dest, void* exch, void* cmp)
707
{
708
#if defined(_M_IX86)
709
  return reinterpret_cast<void*>(InterlockedCompareExchange(
710
        reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
711
        reinterpret_cast<LONG>(cmp)));
712
#else
713
  return InterlockedCompareExchangePointer(dest, exch, cmp);
714
#endif
715
}
716

    
717
void* win_iocp_socket_service_base::interlocked_exchange_pointer(
718
    void** dest, void* val)
719
{
720
#if defined(_M_IX86)
721
  return reinterpret_cast<void*>(InterlockedExchange(
722
        reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
723
#else
724
  return InterlockedExchangePointer(dest, val);
725
#endif
726
}
727

    
728
} // namespace detail
729
} // namespace asio
730
} // namespace boost
731

    
732
#include <boost/asio/detail/pop_options.hpp>
733

    
734
#endif // defined(BOOST_ASIO_HAS_IOCP)
735

    
736
#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP