diff options
Diffstat (limited to 'ext')
296 files changed, 20964 insertions, 13033 deletions
diff --git a/ext/asio/README b/ext/asio/README index c581e8e90c..9b919aa9c0 100644 --- a/ext/asio/README +++ b/ext/asio/README @@ -1,5 +1,5 @@ ASIO library header files -Version 1.4.5 (2010-05-12) +Version 1.4.8 (2011-04-19) Downloaded from http://sourceforge.net/projects/asio/files Project page: http://think-async.com/Asio No local modifications. diff --git a/ext/asio/asio.hpp b/ext/asio/asio.hpp index d8acd5859e..b0ebc96b00 100644 --- a/ext/asio/asio.hpp +++ b/ext/asio/asio.hpp @@ -2,7 +2,7 @@ // asio.hpp // ~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/ext/asio/asio/basic_datagram_socket.hpp b/ext/asio/asio/basic_datagram_socket.hpp index cb149f9835..2cbb3544a0 100644 --- a/ext/asio/asio/basic_datagram_socket.hpp +++ b/ext/asio/asio/basic_datagram_socket.hpp @@ -2,7 +2,7 @@ // basic_datagram_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_socket.hpp" #include "asio/datagram_socket_service.hpp" -#include "asio/error.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_deadline_timer.hpp b/ext/asio/asio/basic_deadline_timer.hpp index 0d183f76ca..27781e7bd4 100644 --- a/ext/asio/asio/basic_deadline_timer.hpp +++ b/ext/asio/asio/basic_deadline_timer.hpp @@ -2,7 +2,7 @@ // basic_deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_io_object.hpp" #include "asio/deadline_timer_service.hpp" -#include "asio/error.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_io_object.hpp b/ext/asio/asio/basic_io_object.hpp index 092170df94..da35462024 100644 --- a/ext/asio/asio/basic_io_object.hpp +++ b/ext/asio/asio/basic_io_object.hpp @@ -2,7 +2,7 @@ // basic_io_object.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/io_service.hpp" +#include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/io_service.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_raw_socket.hpp b/ext/asio/asio/basic_raw_socket.hpp index 9d93b97f14..7a55c4a49c 100644 --- a/ext/asio/asio/basic_raw_socket.hpp +++ b/ext/asio/asio/basic_raw_socket.hpp @@ -2,7 +2,7 @@ // basic_raw_socket.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_socket.hpp" -#include "asio/raw_socket_service.hpp" -#include "asio/error.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/raw_socket_service.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_serial_port.hpp b/ext/asio/asio/basic_serial_port.hpp index edb7bb07a0..38fe5e99fa 100644 --- a/ext/asio/asio/basic_serial_port.hpp +++ b/ext/asio/asio/basic_serial_port.hpp @@ -2,7 +2,7 @@ // basic_serial_port.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,21 +16,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <string> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) +#include <string> #include "asio/basic_io_object.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/serial_port_base.hpp" #include "asio/serial_port_service.hpp" -#include "asio/detail/throw_error.hpp" -#if defined(ASIO_HAS_SERIAL_PORT) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { @@ -614,9 +612,9 @@ public: } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_BASIC_SERIAL_PORT_HPP diff --git a/ext/asio/asio/basic_socket.hpp b/ext/asio/asio/basic_socket.hpp index 8b3f1d7f6b..5c66b4ad22 100644 --- a/ext/asio/asio/basic_socket.hpp +++ b/ext/asio/asio/basic_socket.hpp @@ -2,7 +2,7 @@ // basic_socket.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/basic_io_object.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/socket_base.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_socket_acceptor.hpp b/ext/asio/asio/basic_socket_acceptor.hpp index 97fa56b776..15f9220dca 100644 --- a/ext/asio/asio/basic_socket_acceptor.hpp +++ b/ext/asio/asio/basic_socket_acceptor.hpp @@ -2,7 +2,7 @@ // basic_socket_acceptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/basic_io_object.hpp" #include "asio/basic_socket.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/socket_acceptor_service.hpp" #include "asio/socket_base.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_socket_iostream.hpp b/ext/asio/asio/basic_socket_iostream.hpp index 361ecb82cd..efcd51e94b 100644 --- a/ext/asio/asio/basic_socket_iostream.hpp +++ b/ext/asio/asio/basic_socket_iostream.hpp @@ -2,7 +2,7 @@ // basic_socket_iostream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,22 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/push_options.hpp" #include <boost/preprocessor/arithmetic/inc.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/utility/base_from_member.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_socket_streambuf.hpp" #include "asio/stream_socket_service.hpp" @@ -79,6 +72,8 @@ } \ /**/ +#include "asio/detail/push_options.hpp" + namespace asio { /// Iostream interface for a socket. @@ -146,11 +141,11 @@ public: } // namespace asio +#include "asio/detail/pop_options.hpp" + #undef ASIO_PRIVATE_CTR_DEF #undef ASIO_PRIVATE_CONNECT_DEF #endif // defined(BOOST_NO_IOSTREAM) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/ext/asio/asio/basic_socket_streambuf.hpp b/ext/asio/asio/basic_socket_streambuf.hpp index ae0264e3ea..05fc86591d 100644 --- a/ext/asio/asio/basic_socket_streambuf.hpp +++ b/ext/asio/asio/basic_socket_streambuf.hpp @@ -2,7 +2,7 @@ // basic_socket_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/push_options.hpp" #include <streambuf> #include <boost/array.hpp> #include <boost/preprocessor/arithmetic/inc.hpp> @@ -31,12 +26,10 @@ #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/utility/base_from_member.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_socket.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/io_service.hpp" #include "asio/stream_socket_service.hpp" -#include "asio/detail/throw_error.hpp" #if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY) #define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 @@ -74,6 +67,8 @@ } \ /**/ +#include "asio/detail/push_options.hpp" + namespace asio { /// Iostream streambuf for a socket. @@ -286,10 +281,10 @@ private: } // namespace asio +#include "asio/detail/pop_options.hpp" + #undef ASIO_PRIVATE_CONNECT_DEF #endif // !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/ext/asio/asio/basic_stream_socket.hpp b/ext/asio/asio/basic_stream_socket.hpp index b7b4f065fa..41543fc189 100644 --- a/ext/asio/asio/basic_stream_socket.hpp +++ b/ext/asio/asio/basic_stream_socket.hpp @@ -2,7 +2,7 @@ // basic_stream_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_socket.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/stream_socket_service.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/basic_streambuf.hpp b/ext/asio/asio/basic_streambuf.hpp index b34b3fecf7..17157da89f 100644 --- a/ext/asio/asio/basic_streambuf.hpp +++ b/ext/asio/asio/basic_streambuf.hpp @@ -2,7 +2,7 @@ // basic_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,28 +15,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/push_options.hpp" #include <algorithm> #include <cstring> -#include <memory> #include <stdexcept> #include <streambuf> #include <vector> #include <boost/limits.hpp> #include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/basic_streambuf_fwd.hpp" #include "asio/buffer.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /// Automatically resizable buffer class based on std::streambuf. @@ -107,7 +102,11 @@ namespace asio { * is >> s; * @endcode */ +#if defined(GENERATING_DOCUMENTATION) template <typename Allocator = std::allocator<char> > +#else +template <typename Allocator> +#endif class basic_streambuf : public std::streambuf, private noncopyable @@ -337,8 +336,27 @@ protected: private: std::size_t max_size_; std::vector<char_type, Allocator> buffer_; + + // Helper function to get the preferred size for reading data. + friend std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) + { + return std::min<std::size_t>( + std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()), + std::min<std::size_t>(max_size, sb.max_size() - sb.size())); + } }; +// Helper function to get the preferred size for reading data. Used for any +// user-provided specialisations of basic_streambuf. +template <typename Allocator> +inline std::size_t read_size_helper( + basic_streambuf<Allocator>& sb, std::size_t max_size) +{ + return std::min<std::size_t>(512, + std::min<std::size_t>(max_size, sb.max_size() - sb.size())); +} + } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/ext/asio/asio/basic_streambuf_fwd.hpp b/ext/asio/asio/basic_streambuf_fwd.hpp new file mode 100644 index 0000000000..e1d81ac5e3 --- /dev/null +++ b/ext/asio/asio/basic_streambuf_fwd.hpp @@ -0,0 +1,33 @@ +// +// basic_streambuf_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_STREAMBUF_FWD_HPP +#define ASIO_BASIC_STREAMBUF_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(BOOST_NO_IOSTREAM) + +#include <memory> + +namespace asio { + +template <typename Allocator = std::allocator<char> > +class basic_streambuf; + +} // namespace asio + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // ASIO_BASIC_STREAMBUF_FWD_HPP diff --git a/ext/asio/asio/buffer.hpp b/ext/asio/asio/buffer.hpp index 43b475c5be..6810fca644 100644 --- a/ext/asio/asio/buffer.hpp +++ b/ext/asio/asio/buffer.hpp @@ -2,7 +2,7 @@ // buffer.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include <boost/array.hpp> -#include <boost/type_traits/is_const.hpp> #include <string> #include <vector> -#include "asio/detail/pop_options.hpp" +#include <boost/detail/workaround.hpp> +#include "asio/detail/array_fwd.hpp" #if defined(BOOST_MSVC) # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) @@ -43,11 +39,17 @@ #endif // defined(__GNUC__) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) -# include "asio/detail/push_options.hpp" # include <boost/function.hpp> -# include "asio/detail/pop_options.hpp" #endif // ASIO_ENABLE_BUFFER_DEBUGGING +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# include <boost/type_traits/is_const.hpp> +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + +#include "asio/detail/push_options.hpp" + namespace asio { class mutable_buffer; diff --git a/ext/asio/asio/buffered_read_stream.hpp b/ext/asio/asio/buffered_read_stream.hpp index afd22cec86..d9dc31160f 100644 --- a/ext/asio/asio/buffered_read_stream.hpp +++ b/ext/asio/asio/buffered_read_stream.hpp @@ -2,7 +2,7 @@ // buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <cstring> -#include <boost/config.hpp> #include <boost/type_traits/remove_reference.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/buffered_read_stream_fwd.hpp" #include "asio/buffer.hpp" -#include "asio/error.hpp" -#include "asio/io_service.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_resize_guard.hpp" #include "asio/detail/buffered_stream_storage.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/error.hpp" +#include "asio/io_service.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/buffered_read_stream_fwd.hpp b/ext/asio/asio/buffered_read_stream_fwd.hpp index 5078775d11..0e8495a04a 100644 --- a/ext/asio/asio/buffered_read_stream_fwd.hpp +++ b/ext/asio/asio/buffered_read_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_read_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { template <typename Stream> @@ -24,6 +22,4 @@ class buffered_read_stream; } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP diff --git a/ext/asio/asio/buffered_stream.hpp b/ext/asio/asio/buffered_stream.hpp index 23dc9c33f9..11b99f6484 100644 --- a/ext/asio/asio/buffered_stream.hpp +++ b/ext/asio/asio/buffered_stream.hpp @@ -2,7 +2,7 @@ // buffered_stream.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,19 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/buffered_read_stream.hpp" #include "asio/buffered_write_stream.hpp" #include "asio/buffered_stream_fwd.hpp" +#include "asio/detail/noncopyable.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/buffered_stream_fwd.hpp b/ext/asio/asio/buffered_stream_fwd.hpp index f26cd43c2d..a8e958e0c2 100644 --- a/ext/asio/asio/buffered_stream_fwd.hpp +++ b/ext/asio/asio/buffered_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { template <typename Stream> @@ -24,6 +22,4 @@ class buffered_stream; } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_BUFFERED_STREAM_FWD_HPP diff --git a/ext/asio/asio/buffered_write_stream.hpp b/ext/asio/asio/buffered_write_stream.hpp index 30a92ce658..ee0ec7764a 100644 --- a/ext/asio/asio/buffered_write_stream.hpp +++ b/ext/asio/asio/buffered_write_stream.hpp @@ -2,7 +2,7 @@ // buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,24 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <cstring> -#include <boost/config.hpp> #include <boost/type_traits/remove_reference.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/buffered_write_stream_fwd.hpp" #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" -#include "asio/error.hpp" -#include "asio/io_service.hpp" -#include "asio/write.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffered_stream_storage.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/write.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/buffered_write_stream_fwd.hpp b/ext/asio/asio/buffered_write_stream_fwd.hpp index dc0e014732..cb09fe8be4 100644 --- a/ext/asio/asio/buffered_write_stream_fwd.hpp +++ b/ext/asio/asio/buffered_write_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_write_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { template <typename Stream> @@ -24,6 +22,4 @@ class buffered_write_stream; } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP diff --git a/ext/asio/asio/buffers_iterator.hpp b/ext/asio/asio/buffers_iterator.hpp index 7da55f2f34..dcca2d37d0 100644 --- a/ext/asio/asio/buffers_iterator.hpp +++ b/ext/asio/asio/buffers_iterator.hpp @@ -2,7 +2,7 @@ // buffers_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,20 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <boost/assert.hpp> -#include <boost/config.hpp> #include <boost/detail/workaround.hpp> #include <boost/iterator.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/add_const.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/buffer.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail @@ -210,6 +207,15 @@ public: return tmp; } + /// Addition operator. + friend buffers_iterator operator+(std::ptrdiff_t difference, + const buffers_iterator& iter) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + /// Subtraction operator. friend buffers_iterator operator-(const buffers_iterator& iter, std::ptrdiff_t difference) diff --git a/ext/asio/asio/completion_condition.hpp b/ext/asio/asio/completion_condition.hpp index d4e631d035..dd1fb274fd 100644 --- a/ext/asio/asio/completion_condition.hpp +++ b/ext/asio/asio/completion_condition.hpp @@ -2,7 +2,7 @@ // completion_condition.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <cstddef> #include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { diff --git a/ext/asio/asio/datagram_socket_service.hpp b/ext/asio/asio/datagram_socket_service.hpp index 7d135eed7c..87821c377c 100644 --- a/ext/asio/asio/datagram_socket_service.hpp +++ b/ext/asio/asio/datagram_socket_service.hpp @@ -2,7 +2,7 @@ // datagram_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" @@ -32,6 +26,8 @@ # include "asio/detail/reactive_socket_service.hpp" #endif +#include "asio/detail/push_options.hpp" + namespace asio { /// Default service implementation for a datagram socket. diff --git a/ext/asio/asio/deadline_timer.hpp b/ext/asio/asio/deadline_timer.hpp index e0905f289d..fd0d5dc7c2 100644 --- a/ext/asio/asio/deadline_timer.hpp +++ b/ext/asio/asio/deadline_timer.hpp @@ -2,7 +2,7 @@ // deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/socket_types.hpp" // Must come before posix_time. +#include "asio/basic_deadline_timer.hpp" #include "asio/detail/push_options.hpp" #include <boost/date_time/posix_time/posix_time_types.hpp> #include "asio/detail/pop_options.hpp" -#include "asio/basic_deadline_timer.hpp" - namespace asio { /// Typedef for the typical usage of timer. Uses a UTC clock. @@ -32,6 +30,4 @@ typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer; } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DEADLINE_TIMER_HPP diff --git a/ext/asio/asio/deadline_timer_service.hpp b/ext/asio/asio/deadline_timer_service.hpp index 284a690ffb..60d898b2b6 100644 --- a/ext/asio/asio/deadline_timer_service.hpp +++ b/ext/asio/asio/deadline_timer_service.hpp @@ -2,7 +2,7 @@ // deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/deadline_timer_service.hpp" #include "asio/io_service.hpp" #include "asio/time_traits.hpp" -#include "asio/detail/deadline_timer_service.hpp" -#include "asio/detail/service_base.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/detail/array_fwd.hpp b/ext/asio/asio/detail/array_fwd.hpp new file mode 100644 index 0000000000..12c295cde8 --- /dev/null +++ b/ext/asio/asio/detail/array_fwd.hpp @@ -0,0 +1,25 @@ +// +// detail/array_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_ARRAY_FWD_HPP +#define ASIO_DETAIL_ARRAY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace boost { + +template<class T, std::size_t N> +class array; + +} // namespace boost + +#endif // ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/ext/asio/asio/detail/base_from_completion_cond.hpp b/ext/asio/asio/detail/base_from_completion_cond.hpp index 90a11f9900..93cc8c45ff 100644 --- a/ext/asio/asio/detail/base_from_completion_cond.hpp +++ b/ext/asio/asio/detail/base_from_completion_cond.hpp @@ -1,8 +1,8 @@ // -// base_from_completion_cond.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/completion_condition.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -31,7 +32,8 @@ protected: { } - std::size_t check(const asio::error_code& ec, + std::size_t check_for_completion( + const asio::error_code& ec, std::size_t total_transferred) { return detail::adapt_completion_condition_result( @@ -50,7 +52,8 @@ protected: { } - static std::size_t check(const asio::error_code& ec, + static std::size_t check_for_completion( + const asio::error_code& ec, std::size_t total_transferred) { return transfer_all_t()(ec, total_transferred); diff --git a/ext/asio/asio/detail/bind_handler.hpp b/ext/asio/asio/detail/bind_handler.hpp index 5d9eb004ae..f663a5bab2 100644 --- a/ext/asio/asio/detail/bind_handler.hpp +++ b/ext/asio/asio/detail/bind_handler.hpp @@ -1,8 +1,8 @@ // -// bind_handler.hpp -// ~~~~~~~~~~~~~~~~ +// detail/bind_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -35,7 +36,7 @@ public: void operator()() { - handler_(arg1_); + handler_(static_cast<const Arg1&>(arg1_)); } void operator()() const @@ -92,7 +93,8 @@ public: void operator()() { - handler_(arg1_, arg2_); + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_)); } void operator()() const @@ -152,7 +154,9 @@ public: void operator()() { - handler_(arg1_, arg2_, arg3_); + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), + static_cast<const Arg3&>(arg3_)); } void operator()() const @@ -216,7 +220,10 @@ public: void operator()() { - handler_(arg1_, arg2_, arg3_, arg4_); + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), + static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_)); } void operator()() const @@ -287,7 +294,11 @@ public: void operator()() { - handler_(arg1_, arg2_, arg3_, arg4_, arg5_); + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), + static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_), + static_cast<const Arg5&>(arg5_)); } void operator()() const diff --git a/ext/asio/asio/detail/buffer_resize_guard.hpp b/ext/asio/asio/detail/buffer_resize_guard.hpp index 368de323fe..4bf6a8ed89 100644 --- a/ext/asio/asio/detail/buffer_resize_guard.hpp +++ b/ext/asio/asio/detail/buffer_resize_guard.hpp @@ -1,8 +1,8 @@ // -// buffer_resize_guard.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <boost/limits.hpp> #include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <boost/limits.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/buffer_sequence_adapter.hpp b/ext/asio/asio/detail/buffer_sequence_adapter.hpp index 6269d6ae28..17044b7920 100644 --- a/ext/asio/asio/detail/buffer_sequence_adapter.hpp +++ b/ext/asio/asio/detail/buffer_sequence_adapter.hpp @@ -1,8 +1,8 @@ // -// buffer_sequence_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,9 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/buffer.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -32,14 +34,14 @@ protected: const asio::mutable_buffer& buffer) { buf.buf = asio::buffer_cast<char*>(buffer); - buf.len = asio::buffer_size(buffer); + buf.len = static_cast<ULONG>(asio::buffer_size(buffer)); } static void init_native_buffer(WSABUF& buf, const asio::const_buffer& buffer) { buf.buf = const_cast<char*>(asio::buffer_cast<const char*>(buffer)); - buf.len = asio::buffer_size(buffer); + buf.len = static_cast<ULONG>(asio::buffer_size(buffer)); } #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef iovec native_buffer_type; @@ -158,7 +160,7 @@ public: explicit buffer_sequence_adapter( const asio::mutable_buffers_1& buffers) { - init_native_buffer(buffer_, buffers); + init_native_buffer(buffer_, Buffer(buffers)); total_buffer_size_ = asio::buffer_size(buffers); } @@ -205,7 +207,7 @@ public: explicit buffer_sequence_adapter( const asio::const_buffers_1& buffers) { - init_native_buffer(buffer_, buffers); + init_native_buffer(buffer_, Buffer(buffers)); total_buffer_size_ = asio::buffer_size(buffers); } diff --git a/ext/asio/asio/detail/buffered_stream_storage.hpp b/ext/asio/asio/detail/buffered_stream_storage.hpp index 51f6556fcb..7e1b7467a9 100644 --- a/ext/asio/asio/detail/buffered_stream_storage.hpp +++ b/ext/asio/asio/detail/buffered_stream_storage.hpp @@ -1,8 +1,8 @@ // -// buffered_stream_storage.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <cassert> #include <cstddef> #include <cstring> #include <vector> -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/call_stack.hpp b/ext/asio/asio/detail/call_stack.hpp index 0e9ddafaa3..7ad5dc5588 100644 --- a/ext/asio/asio/detail/call_stack.hpp +++ b/ext/asio/asio/detail/call_stack.hpp @@ -1,8 +1,8 @@ // -// call_stack.hpp -// ~~~~~~~~~~~~~~ +// detail/call_stack.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/tss_ptr.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/completion_handler.hpp b/ext/asio/asio/detail/completion_handler.hpp index 16167dfbe2..0224d7e83d 100644 --- a/ext/asio/asio/detail/completion_handler.hpp +++ b/ext/asio/asio/detail/completion_handler.hpp @@ -1,8 +1,8 @@ // -// completion_handler.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -29,6 +30,8 @@ template <typename Handler> class completion_handler : public operation { public: + ASIO_DEFINE_HANDLER_PTR(completion_handler); + completion_handler(Handler h) : operation(&completion_handler::do_complete), handler_(h) @@ -40,20 +43,21 @@ public: { // Take ownership of the handler object. completion_handler* h(static_cast<completion_handler*>(base)); - typedef handler_alloc_traits<Handler, completion_handler> alloc_traits; - handler_ptr<alloc_traits> ptr(h->handler_, h); + ptr p = { boost::addressof(h->handler_), h, h }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + Handler handler(h->handler_); + p.h = boost::addressof(handler); + p.reset(); // Make the upcall if required. if (owner) { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - Handler handler(h->handler_); - ptr.reset(); asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); } diff --git a/ext/asio/asio/detail/config.hpp b/ext/asio/asio/detail/config.hpp new file mode 100644 index 0000000000..8328d7661c --- /dev/null +++ b/ext/asio/asio/detail/config.hpp @@ -0,0 +1,205 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CONFIG_HPP +#define ASIO_DETAIL_CONFIG_HPP + +#include <boost/config.hpp> + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either ASIO_SEPARATE_COMPILATION or +// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(ASIO_HEADER_ONLY) +# if !defined(ASIO_SEPARATE_COMPILATION) +# if !defined(ASIO_DYN_LINK) +# define ASIO_HEADER_ONLY +# endif // !defined(ASIO_DYN_LINK) +# endif // !defined(ASIO_SEPARATE_COMPILATION) +#endif // !defined(ASIO_HEADER_ONLY) + +#if defined(ASIO_HEADER_ONLY) +# define ASIO_DECL inline +#else // defined(ASIO_HEADER_ONLY) +# if defined(BOOST_HAS_DECLSPEC) +// We need to import/export our code only if the user has specifically asked +// for it by defining ASIO_DYN_LINK. +# if defined(ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(ASIO_SOURCE) +# define ASIO_DECL __declspec(dllexport) +# else // defined(ASIO_SOURCE) +# define ASIO_DECL __declspec(dllimport) +# endif // defined(ASIO_SOURCE) +# endif // defined(ASIO_DYN_LINK) +# endif // defined(BOOST_HAS_DECLSPEC) +#endif // defined(ASIO_HEADER_ONLY) + +// If ASIO_DECL isn't defined yet define it now. +#if !defined(ASIO_DECL) +# define ASIO_DECL +#endif // !defined(ASIO_DECL) + +// Windows: target OS version. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || defined(__BORLANDC__) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") +# else // defined(_MSC_VER) || defined(__BORLANDC__) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# define _WIN32_WINNT 0x0501 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(ASIO_NO_NOMINMAX) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) +# if !defined(ASIO_DISABLE_IOCP) +# define ASIO_HAS_IOCP 1 +# endif // !defined(ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include <linux/version.h> +# if !defined(ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(ASIO_DISABLE_EVENTFD) +# if !defined(ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(ASIO_DISABLE_EVENTFD) +# if defined(ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(ASIO_HAS_EPOLL) +#endif // defined(__linux__) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(ASIO_DISABLE_KQUEUE) +# define ASIO_HAS_KQUEUE 1 +# endif // !defined(ASIO_DISABLE_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(ASIO_DISABLE_DEV_POLL) +# define ASIO_HAS_DEV_POLL 1 +# endif // !defined(ASIO_DISABLE_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if defined(ASIO_HAS_IOCP) \ + || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(ASIO_DISABLE_SERIAL_PORT) +# define ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +#endif // defined(ASIO_HAS_IOCP) + // || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +// Windows: stream handles. +#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(ASIO_HAS_IOCP) +#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(ASIO_HAS_IOCP) +#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(ASIO_HAS_IOCP) +#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS) + +#endif // ASIO_DETAIL_CONFIG_HPP diff --git a/ext/asio/asio/detail/consuming_buffers.hpp b/ext/asio/asio/detail/consuming_buffers.hpp index 80b6a8e803..8969ae4d98 100644 --- a/ext/asio/asio/detail/consuming_buffers.hpp +++ b/ext/asio/asio/detail/consuming_buffers.hpp @@ -1,8 +1,8 @@ // -// consuming_buffers.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,18 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <algorithm> +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> #include <boost/iterator.hpp> #include <boost/limits.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/buffer.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -156,12 +152,14 @@ public: consuming_buffers(const Buffers& buffers) : buffers_(buffers), at_end_(buffers_.begin() == buffers_.end()), - first_(*buffers_.begin()), begin_remainder_(buffers_.begin()), max_size_((std::numeric_limits<std::size_t>::max)()) { if (!at_end_) + { + first_ = *buffers_.begin(); ++begin_remainder_; + } } // Copy constructor. diff --git a/ext/asio/asio/detail/deadline_timer_service.hpp b/ext/asio/asio/detail/deadline_timer_service.hpp index 6daf7acb35..782f5c3b4c 100644 --- a/ext/asio/asio/detail/deadline_timer_service.hpp +++ b/ext/asio/asio/detail/deadline_timer_service.hpp @@ -1,8 +1,8 @@ // -// deadline_timer_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include <boost/date_time/posix_time/posix_time_types.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/bind_handler.hpp" @@ -33,6 +27,13 @@ #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue.hpp" #include "asio/detail/timer_scheduler.hpp" +#include "asio/detail/wait_handler.hpp" + +#include "asio/detail/push_options.hpp" +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -54,6 +55,7 @@ public: { time_type expiry; bool might_have_pending_waits; + typename timer_queue<Time_Traits>::per_timer_data timer_data; }; // Constructor. @@ -97,7 +99,7 @@ public: ec = asio::error_code(); return 0; } - std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl); + std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); impl.might_have_pending_waits = false; ec = asio::error_code(); return count; @@ -151,59 +153,21 @@ public: ec = asio::error_code(); } - template <typename Handler> - class wait_handler : public timer_op - { - public: - wait_handler(Handler handler) - : timer_op(&wait_handler::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - wait_handler* h(static_cast<wait_handler*>(base)); - typedef handler_alloc_traits<Handler, wait_handler> alloc_traits; - handler_ptr<alloc_traits> ptr(h->handler_, h); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder1<Handler, asio::error_code> - handler(h->handler_, h->ec_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous wait on the timer. template <typename Handler> void async_wait(implementation_type& impl, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef wait_handler<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); + typedef wait_handler<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); impl.might_have_pending_waits = true; - scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl); - ptr.release(); + scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); + p.v = p.p = 0; } private: diff --git a/ext/asio/asio/detail/descriptor_ops.hpp b/ext/asio/asio/detail/descriptor_ops.hpp index ea3731e7ac..5cac91dc4b 100644 --- a/ext/asio/asio/detail/descriptor_ops.hpp +++ b/ext/asio/asio/detail/descriptor_ops.hpp @@ -1,8 +1,8 @@ // -// descriptor_ops.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,27 +15,34 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <cerrno> -#include "asio/detail/pop_options.hpp" +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include "asio/error.hpp" +#include <cstddef> +#include "asio/error_code.hpp" #include "asio/detail/socket_types.hpp" -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace descriptor_ops { -inline void clear_error(asio::error_code& ec) +// Descriptor state bits. +enum { - errno = 0; - ec = asio::error_code(); -} + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking +}; + +typedef unsigned char state_type; template <typename ReturnType> inline ReturnType error_wrapper(ReturnType return_value, @@ -46,131 +53,53 @@ inline ReturnType error_wrapper(ReturnType return_value, return return_value; } -inline int open(const char* path, int flags, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::open(path, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL int open(const char* path, int flags, + asio::error_code& ec); -inline int close(int d, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::close(d), ec); - if (result == 0) - clear_error(ec); - return result; -} +ASIO_DECL int close(int d, state_type& state, + asio::error_code& ec); -inline void init_buf_iov_base(void*& base, void* addr) -{ - base = addr; -} - -template <typename T> -inline void init_buf_iov_base(T& base, void* addr) -{ - base = static_cast<T>(addr); -} +ASIO_DECL bool set_internal_non_blocking(int d, + state_type& state, asio::error_code& ec); typedef iovec buf; -inline void init_buf(buf& b, void* data, size_t size) -{ - init_buf_iov_base(b.iov_base, data); - b.iov_len = size; -} +ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec); -inline void init_buf(buf& b, const void* data, size_t size) -{ - init_buf_iov_base(b.iov_base, const_cast<void*>(data)); - b.iov_len = size; -} +ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); -inline int scatter_read(int d, buf* bufs, size_t count, - asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec); - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL std::size_t sync_write(int d, state_type state, + const buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec); -inline int gather_write(int d, const buf* bufs, size_t count, - asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec); - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL bool non_blocking_write(int d, + const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); -inline int ioctl(int d, long cmd, ioctl_arg_type* arg, - asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::ioctl(d, cmd, arg), ec); - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, asio::error_code& ec); -inline int fcntl(int d, long cmd, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::fcntl(d, cmd), ec); - if (result != -1) - clear_error(ec); - return result; -} +ASIO_DECL int fcntl(int d, long cmd, asio::error_code& ec); -inline int fcntl(int d, long cmd, long arg, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::fcntl(d, cmd, arg), ec); - if (result != -1) - clear_error(ec); - return result; -} +ASIO_DECL int fcntl(int d, long cmd, + long arg, asio::error_code& ec); -inline int poll_read(int d, asio::error_code& ec) -{ - clear_error(ec); - pollfd fds; - fds.fd = d; - fds.events = POLLIN; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL int poll_read(int d, asio::error_code& ec); -inline int poll_write(int d, asio::error_code& ec) -{ - clear_error(ec); - pollfd fds; - fds.fd = d; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL int poll_write(int d, asio::error_code& ec); } // namespace descriptor_ops } // namespace detail } // namespace asio -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/descriptor_ops.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/ext/asio/asio/detail/descriptor_read_op.hpp b/ext/asio/asio/detail/descriptor_read_op.hpp new file mode 100644 index 0000000000..0d4516721c --- /dev/null +++ b/ext/asio/asio/detail/descriptor_read_op.hpp @@ -0,0 +1,114 @@ +// +// detail/descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP +#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class descriptor_read_op_base : public reactor_op +{ +public: + descriptor_read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static bool do_perform(reactor_op* base) + { + descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + return descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + } + +private: + int descriptor_; + MutableBufferSequence buffers_; +}; + +template <typename MutableBufferSequence, typename Handler> +class descriptor_read_op + : public descriptor_read_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); + + descriptor_read_op(int descriptor, + const MutableBufferSequence& buffers, Handler handler) + : descriptor_read_op_base<MutableBufferSequence>( + descriptor, buffers, &descriptor_read_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast<descriptor_read_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP diff --git a/ext/asio/asio/detail/descriptor_write_op.hpp b/ext/asio/asio/detail/descriptor_write_op.hpp new file mode 100644 index 0000000000..9caa283e70 --- /dev/null +++ b/ext/asio/asio/detail/descriptor_write_op.hpp @@ -0,0 +1,114 @@ +// +// detail/descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP +#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class descriptor_write_op_base : public reactor_op +{ +public: + descriptor_write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static bool do_perform(reactor_op* base) + { + descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base)); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(o->buffers_); + + return descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + } + +private: + int descriptor_; + ConstBufferSequence buffers_; +}; + +template <typename ConstBufferSequence, typename Handler> +class descriptor_write_op + : public descriptor_write_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); + + descriptor_write_op(int descriptor, + const ConstBufferSequence& buffers, Handler handler) + : descriptor_write_op_base<ConstBufferSequence>( + descriptor, buffers, &descriptor_write_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast<descriptor_write_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP diff --git a/ext/asio/asio/detail/dev_poll_reactor.hpp b/ext/asio/asio/detail/dev_poll_reactor.hpp index 1367b7190f..6bbf1b203d 100644 --- a/ext/asio/asio/detail/dev_poll_reactor.hpp +++ b/ext/asio/asio/detail/dev_poll_reactor.hpp @@ -1,8 +1,8 @@ // -// dev_poll_reactor.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,36 +15,28 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/dev_poll_reactor_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_DEV_POLL) -#include "asio/detail/push_options.hpp" #include <cstddef> #include <vector> -#include <boost/config.hpp> -#include <boost/date_time/posix_time/posix_time_types.hpp> -#include <boost/throw_exception.hpp> #include <sys/devpoll.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/io_service.hpp" -#include "asio/system_error.hpp" +#include "asio/detail/dev_poll_reactor_fwd.hpp" #include "asio/detail/hash_map.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" -#include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" +#include "asio/io_service.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -62,358 +54,93 @@ public: }; // Constructor. - dev_poll_reactor(asio::io_service& io_service) - : asio::detail::service_base<dev_poll_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), - mutex_(), - dev_poll_fd_(do_dev_poll_create()), - interrupter_(), - shutdown_(false) - { - // Add the interrupter's descriptor to /dev/poll. - ::pollfd ev = { 0 }; - ev.fd = interrupter_.read_descriptor(); - ev.events = POLLIN | POLLERR; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); - } + ASIO_DECL dev_poll_reactor(asio::io_service& io_service); // Destructor. - ~dev_poll_reactor() - { - shutdown_service(); - ::close(dev_poll_fd_); - } + ASIO_DECL ~dev_poll_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue<operation> ops; - - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); - - timer_queues_.get_all_timers(ops); - } + ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data&) + ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool allow_speculative) - { - asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (allow_speculative) - { - if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) - { - if (!op_queue_[op_type].has_operation(descriptor)) - { - if (op->perform()) - { - lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - } - } - - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); - if (first) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLERR | POLLHUP; - if (op_type == read_op - || op_queue_[read_op].has_operation(descriptor)) - ev.events |= POLLIN; - if (op_type == write_op - || op_queue_[write_op].has_operation(descriptor)) - ev.events |= POLLOUT; - if (op_type == except_op - || op_queue_[except_op].has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) - { - asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, asio::error::operation_aborted); - } + ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - asio::detail::mutex::scoped_lock lock(mutex_); - - // Remove the descriptor from /dev/poll. - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLREMOVE; - interrupter_.interrupt(); - - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor, asio::error::operation_aborted); - } + ASIO_DECL void close_descriptor( + socket_type descriptor, per_descriptor_data&); // Add a new timer queue to the reactor. template <typename Time_Traits> - void add_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> - void remove_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> - void schedule_timer(timer_queue<Time_Traits>& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupter_.interrupt(); - } - } + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template <typename Time_Traits> - std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token) - { - asio::detail::mutex::scoped_lock lock(mutex_); - op_queue<operation> ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer); // Run /dev/poll once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue<operation>& ops) - { - asio::detail::mutex::scoped_lock lock(mutex_); - - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() - && op_queue_[except_op].empty() && timer_queues_.all_empty()) - return; - - // Write the pending event registration changes to the /dev/poll descriptor. - std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); - if (events_size > 0) - { - errno = 0; - int result = ::write(dev_poll_fd_, - &pending_event_changes_[0], events_size); - if (result != static_cast<int>(events_size)) - { - asio::error_code ec = asio::error_code( - errno, asio::error::get_system_category()); - for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) - { - int descriptor = pending_event_changes_[i].fd; - for (int j = 0; j < max_ops; ++j) - op_queue_[j].cancel_operations(descriptor, ops, ec); - } - } - pending_event_changes_.clear(); - pending_event_change_index_.clear(); - } - - int timeout = block ? get_timeout() : 0; - lock.unlock(); - - // Block on the /dev/poll descriptor. - ::pollfd events[128] = { { 0 } }; - ::dvpoll dp = { 0 }; - dp.dp_fds = events; - dp.dp_nfds = 128; - dp.dp_timeout = timeout; - int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); - - lock.lock(); - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - int descriptor = events[i].fd; - if (descriptor == interrupter_.read_descriptor()) - { - interrupter_.reset(); - } - else - { - bool more_reads = false; - bool more_writes = false; - bool more_except = false; - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) - more_except = - op_queue_[except_op].perform_operations(descriptor, ops); - else - more_except = op_queue_[except_op].has_operation(descriptor); - - if (events[i].events & (POLLIN | POLLERR | POLLHUP)) - more_reads = op_queue_[read_op].perform_operations(descriptor, ops); - else - more_reads = op_queue_[read_op].has_operation(descriptor); - - if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) - more_writes = op_queue_[write_op].perform_operations(descriptor, ops); - else - more_writes = op_queue_[write_op].has_operation(descriptor); - - if ((events[i].events & (POLLERR | POLLHUP)) != 0 - && !more_except && !more_reads && !more_writes) - { - // If we have an event and no operations associated with the - // descriptor then we need to delete the descriptor from /dev/poll. - // The poll operation can produce POLLHUP or POLLERR events when there - // is no operation pending, so if we do not remove the descriptor we - // can end up in a tight polling loop. - ::pollfd ev = { 0 }; - ev.fd = descriptor; - ev.events = POLLREMOVE; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); - } - else - { - ::pollfd ev = { 0 }; - ev.fd = descriptor; - ev.events = POLLERR | POLLHUP; - if (more_reads) - ev.events |= POLLIN; - if (more_writes) - ev.events |= POLLOUT; - if (more_except) - ev.events |= POLLPRI; - ev.revents = 0; - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - asio::error_code ec(errno, - asio::error::get_system_category()); - for (int j = 0; j < max_ops; ++j) - op_queue_[j].cancel_operations(descriptor, ops, ec); - } - } - } - } - timer_queues_.get_ready_timers(ops); - } + ASIO_DECL void run(bool block, op_queue<operation>& ops); // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } + ASIO_DECL void interrupt(); private: // Create the /dev/poll file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_dev_poll_create() - { - int fd = ::open("/dev/poll", O_RDWR); - if (fd == -1) - { - boost::throw_exception( - asio::system_error( - asio::error_code(errno, - asio::error::get_system_category()), - "/dev/poll")); - } - return fd; - } + ASIO_DECL static int do_dev_poll_create(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the /dev/poll DP_POLL operation. The timeout // value is returned as a number of milliseconds. A return value of -1 // indicates that the poll should block indefinitely. - int get_timeout() - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - return timer_queues_.wait_duration_msec(5 * 60 * 1000); - } + ASIO_DECL int get_timeout(); // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not // acquire the dev_poll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const asio::error_code& ec) - { - bool need_interrupt = false; - op_queue<operation> ops; - for (int i = 0; i < max_ops; ++i) - need_interrupt = op_queue_[i].cancel_operations( - descriptor, ops, ec) || need_interrupt; - io_service_.post_deferred_completions(ops); - if (need_interrupt) - interrupter_.interrupt(); - } + ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec); // Add a pending event entry for the given descriptor. - ::pollfd& add_pending_event_change(int descriptor) - { - hash_map<int, std::size_t>::iterator iter - = pending_event_change_index_.find(descriptor); - if (iter == pending_event_change_index_.end()) - { - std::size_t index = pending_event_changes_.size(); - pending_event_changes_.reserve(pending_event_changes_.size() + 1); - pending_event_change_index_.insert(std::make_pair(descriptor, index)); - pending_event_changes_.push_back(::pollfd()); - pending_event_changes_[index].fd = descriptor; - pending_event_changes_[index].revents = 0; - return pending_event_changes_[index]; - } - else - { - return pending_event_changes_[iter->second]; - } - } + ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -446,8 +173,13 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_DEV_POLL) - #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/dev_poll_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/dev_poll_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_DEV_POLL) + #endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp b/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp index f7f1aebab4..c54f5e17db 100644 --- a/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp +++ b/ext/asio/asio/detail/dev_poll_reactor_fwd.hpp @@ -1,8 +1,8 @@ // -// dev_poll_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/dev_poll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#if !defined(ASIO_DISABLE_DEV_POLL) -#if defined(__sun) // This service is only supported on Solaris. - -// Define this to indicate that /dev/poll is supported on the target platform. -#define ASIO_HAS_DEV_POLL 1 +#if defined(ASIO_HAS_DEV_POLL) namespace asio { namespace detail { @@ -31,9 +27,6 @@ class dev_poll_reactor; } // namespace detail } // namespace asio -#endif // defined(__sun) -#endif // !defined(ASIO_DISABLE_DEV_POLL) - -#include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_DEV_POLL) #endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP diff --git a/ext/asio/asio/detail/epoll_reactor.hpp b/ext/asio/asio/detail/epoll_reactor.hpp index 0a1eac0265..a085766b5f 100644 --- a/ext/asio/asio/detail/epoll_reactor.hpp +++ b/ext/asio/asio/detail/epoll_reactor.hpp @@ -1,8 +1,8 @@ // -// epoll_reactor.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,43 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/epoll_reactor_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_EPOLL) -#include "asio/detail/push_options.hpp" -#include <cstddef> -#include <sys/epoll.h> -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/hash_map.hpp" +#include "asio/detail/epoll_reactor_fwd.hpp" #include "asio/detail/mutex.hpp" +#include "asio/detail/object_pool.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/select_interrupter.hpp" -#include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" -#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) -# define ASIO_HAS_TIMERFD 1 -#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) - -#if defined(ASIO_HAS_TIMERFD) -# include "asio/detail/push_options.hpp" -# include <sys/timerfd.h> -# include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_TIMERFD) +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -64,357 +45,86 @@ public: connect_op = 1, except_op = 2, max_ops = 3 }; // Per-descriptor queues. - struct descriptor_state + class descriptor_state { - descriptor_state() {} - descriptor_state(const descriptor_state&) {} - void operator=(const descriptor_state&) {} - + friend class epoll_reactor; + friend class object_pool_access; mutex mutex_; op_queue<reactor_op> op_queue_[max_ops]; bool shutdown_; + descriptor_state* next_; + descriptor_state* prev_; }; // Per-descriptor data. typedef descriptor_state* per_descriptor_data; // Constructor. - epoll_reactor(asio::io_service& io_service) - : asio::detail::service_base<epoll_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), - mutex_(), - epoll_fd_(do_epoll_create()), -#if defined(ASIO_HAS_TIMERFD) - timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), -#else // defined(ASIO_HAS_TIMERFD) - timer_fd_(-1), -#endif // defined(ASIO_HAS_TIMERFD) - interrupter_(), - shutdown_(false) - { - // Add the interrupter's descriptor to epoll. - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLET; - ev.data.ptr = &interrupter_; - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); - interrupter_.interrupt(); - - // Add the timer descriptor to epoll. - if (timer_fd_ != -1) - { - ev.events = EPOLLIN | EPOLLERR; - ev.data.ptr = &timer_fd_; - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); - } - } + ASIO_DECL epoll_reactor(asio::io_service& io_service); // Destructor. - ~epoll_reactor() - { - close(epoll_fd_); - if (timer_fd_ != -1) - close(timer_fd_); - } + ASIO_DECL ~epoll_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue<operation> ops; - - descriptor_map::iterator iter = registered_descriptors_.begin(); - descriptor_map::iterator end = registered_descriptors_.end(); - while (iter != end) - { - for (int i = 0; i < max_ops; ++i) - ops.push(iter->second.op_queue_[i]); - iter->second.shutdown_ = true; - ++iter; - } - - timer_queues_.get_all_timers(ops); - } + ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock lock(registered_descriptors_mutex_); - - descriptor_map::iterator new_entry = registered_descriptors_.insert( - std::make_pair(descriptor, descriptor_state())).first; - descriptor_data = &new_entry->second; - - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; - ev.data.ptr = descriptor_data; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - return errno; - - descriptor_data->shutdown_ = false; + ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); - return 0; + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) + { + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, + ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - reactor_op* op, bool allow_speculative) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (descriptor_data->shutdown_) - return; - - if (descriptor_data->op_queue_[op_type].empty()) - { - if (allow_speculative - && (op_type != read_op - || descriptor_data->op_queue_[except_op].empty())) - { - if (op->perform()) - { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - else - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP - | EPOLLOUT | EPOLLPRI | EPOLLET; - ev.data.ptr = descriptor_data; - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - } - } - - descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); - } + reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type, per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - op_queue<operation> ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - - // Remove the descriptor from the set of known descriptors. The descriptor - // will be automatically removed from the epoll set when it is closed. - descriptor_data->shutdown_ = true; - - op_queue<operation> ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - registered_descriptors_.erase(descriptor); - - descriptors_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template <typename Time_Traits> - void add_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue<Time_Traits>& timer_queue); // Remove a timer queue from the reactor. template <typename Time_Traits> - void remove_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> - void schedule_timer(timer_queue<Time_Traits>& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - { -#if defined(ASIO_HAS_TIMERFD) - if (timer_fd_ != -1) - { - itimerspec new_timeout; - itimerspec old_timeout; - int flags = get_timeout(new_timeout); - timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); - return; - } -#endif // defined(ASIO_HAS_TIMERFD) - interrupter_.interrupt(); - } - } - } + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template <typename Time_Traits> - std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token) - { - mutex::scoped_lock lock(mutex_); - op_queue<operation> ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer); // Run epoll once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue<operation>& ops) - { - // Calculate a timeout only if timerfd is not used. - int timeout; - if (timer_fd_ != -1) - timeout = block ? -1 : 0; - else - { - mutex::scoped_lock lock(mutex_); - timeout = block ? get_timeout() : 0; - } - - // Block on the epoll descriptor. - epoll_event events[128]; - int num_events = epoll_wait(epoll_fd_, events, 128, timeout); - -#if defined(ASIO_HAS_TIMERFD) - bool check_timers = (timer_fd_ == -1); -#else // defined(ASIO_HAS_TIMERFD) - bool check_timers = true; -#endif // defined(ASIO_HAS_TIMERFD) - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - void* ptr = events[i].data.ptr; - if (ptr == &interrupter_) - { - // No need to reset the interrupter since we're leaving the descriptor - // in a ready-to-read state and relying on edge-triggered notifications - // to make it so that we only get woken up when the descriptor's epoll - // registration is updated. - -#if defined(ASIO_HAS_TIMERFD) - if (timer_fd_ == -1) - check_timers = true; -#else // defined(ASIO_HAS_TIMERFD) - check_timers = true; -#endif // defined(ASIO_HAS_TIMERFD) - } -#if defined(ASIO_HAS_TIMERFD) - else if (ptr == &timer_fd_) - { - check_timers = true; - } -#endif // defined(ASIO_HAS_TIMERFD) - else - { - descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; - for (int j = max_ops - 1; j >= 0; --j) - { - if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - if (op->perform()) - { - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - else - break; - } - } - } - } - } - - if (check_timers) - { - mutex::scoped_lock common_lock(mutex_); - timer_queues_.get_ready_timers(ops); - -#if defined(ASIO_HAS_TIMERFD) - if (timer_fd_ != -1) - { - itimerspec new_timeout; - itimerspec old_timeout; - int flags = get_timeout(new_timeout); - timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); - } -#endif // defined(ASIO_HAS_TIMERFD) - } - } + ASIO_DECL void run(bool block, op_queue<operation>& ops); // Interrupt the select loop. - void interrupt() - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLET; - ev.data.ptr = &interrupter_; - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); - } + ASIO_DECL void interrupt(); private: // The hint to pass to epoll_create to size its data structures. @@ -422,44 +132,26 @@ private: // Create the epoll file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_epoll_create() - { - int fd = epoll_create(epoll_size); - if (fd == -1) - { - boost::throw_exception( - asio::system_error( - asio::error_code(errno, - asio::error::get_system_category()), - "epoll")); - } - return fd; - } + ASIO_DECL static int do_epoll_create(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); // Get the timeout value for the epoll_wait call. The timeout value is // returned as a number of milliseconds. A return value of -1 indicates // that epoll_wait should block indefinitely. - int get_timeout() - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - return timer_queues_.wait_duration_msec(5 * 60 * 1000); - } + ASIO_DECL int get_timeout(); #if defined(ASIO_HAS_TIMERFD) // Get the timeout value for the timer descriptor. The return value is the // flag argument to be used when calling timerfd_settime. - int get_timeout(itimerspec& ts) - { - ts.it_interval.tv_sec = 0; - ts.it_interval.tv_nsec = 0; - - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - ts.it_value.tv_sec = usec / 1000000; - ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; - - return usec ? 0 : TFD_TIMER_ABSTIME; - } + ASIO_DECL int get_timeout(itimerspec& ts); #endif // defined(ASIO_HAS_TIMERFD) // The io_service implementation used to post completions. @@ -486,22 +178,20 @@ private: // Mutex to protect access to the registered descriptors. mutex registered_descriptors_mutex_; - // Keep track of all registered descriptors. This code relies on the fact that - // the hash_map implementation pools deleted nodes, meaning that we can assume - // our descriptor_state pointer remains valid even after the entry is removed. - // Technically this is not true for C++98, as that standard says that spliced - // elements in a list are invalidated. However, C++0x fixes this shortcoming - // so we'll just assume that C++98 std::list implementations will do the right - // thing anyway. - typedef detail::hash_map<socket_type, descriptor_state> descriptor_map; - descriptor_map registered_descriptors_; + // Keep track of all registered descriptors. + object_pool<descriptor_state> registered_descriptors_; }; } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_EPOLL) - #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/epoll_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/epoll_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_EPOLL) + #endif // ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/ext/asio/asio/detail/epoll_reactor_fwd.hpp b/ext/asio/asio/detail/epoll_reactor_fwd.hpp index 266bccdab0..49df6ed9b7 100644 --- a/ext/asio/asio/detail/epoll_reactor_fwd.hpp +++ b/ext/asio/asio/detail/epoll_reactor_fwd.hpp @@ -1,8 +1,8 @@ // -// epoll_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/epoll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,19 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#if !defined(ASIO_DISABLE_EPOLL) -#if defined(__linux__) // This service is only supported on Linux. - -#include "asio/detail/push_options.hpp" -#include <linux/version.h> -#include "asio/detail/pop_options.hpp" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45. - -// Define this to indicate that epoll is supported on the target platform. -#define ASIO_HAS_EPOLL 1 +#if defined(ASIO_HAS_EPOLL) namespace asio { namespace detail { @@ -37,10 +27,6 @@ class epoll_reactor; } // namespace detail } // namespace asio -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) -#endif // defined(__linux__) -#endif // !defined(ASIO_DISABLE_EPOLL) - -#include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_EPOLL) #endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP diff --git a/ext/asio/asio/detail/event.hpp b/ext/asio/asio/detail/event.hpp index 65aa4cba7f..46ee8a6bd9 100644 --- a/ext/asio/asio/detail/event.hpp +++ b/ext/asio/asio/detail/event.hpp @@ -1,8 +1,8 @@ // -// event.hpp -// ~~~~~~~~~ +// detail/event.hpp +// ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_event.hpp" @@ -45,6 +41,4 @@ typedef posix_event event; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_EVENT_HPP diff --git a/ext/asio/asio/detail/eventfd_select_interrupter.hpp b/ext/asio/asio/detail/eventfd_select_interrupter.hpp index 63b7ac4ff5..0d3b95802d 100644 --- a/ext/asio/asio/detail/eventfd_select_interrupter.hpp +++ b/ext/asio/asio/detail/eventfd_select_interrupter.hpp @@ -1,8 +1,8 @@ // -// eventfd_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,36 +16,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#if defined(__linux__) -# if !defined(ASIO_DISABLE_EVENTFD) -# include <linux/version.h> -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -# define ASIO_HAS_EVENTFD -# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -# endif // !defined(ASIO_DISABLE_EVENTFD) -#endif // defined(__linux__) +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_EVENTFD) #include "asio/detail/push_options.hpp" -#include <fcntl.h> -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -# include <asm/unistd.h> -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -# include <sys/eventfd.h> -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/socket_types.hpp" namespace asio { namespace detail { @@ -54,87 +29,16 @@ class eventfd_select_interrupter { public: // Constructor. - eventfd_select_interrupter() - { -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - if (read_descriptor_ != -1) - { - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - int pipe_fds[2]; - if (pipe(pipe_fds) == 0) - { - read_descriptor_ = pipe_fds[0]; - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - write_descriptor_ = pipe_fds[1]; - ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - asio::error_code ec(errno, - asio::error::get_system_category()); - asio::system_error e(ec, "eventfd_select_interrupter"); - boost::throw_exception(e); - } - } - } + ASIO_DECL eventfd_select_interrupter(); // Destructor. - ~eventfd_select_interrupter() - { - if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) - ::close(write_descriptor_); - if (read_descriptor_ != -1) - ::close(read_descriptor_); - } + ASIO_DECL ~eventfd_select_interrupter(); // Interrupt the select call. - void interrupt() - { - uint64_t counter(1UL); - int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); - (void)result; - } + ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - if (write_descriptor_ == read_descriptor_) - { - for (;;) - { - // Only perform one read. The kernel maintains an atomic counter. - uint64_t counter(0); - errno = 0; - int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - return was_interrupted; - } - } - else - { - for (;;) - { - // Clear all data from the pipe. - char data[1024]; - int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; - } - } - } + ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const @@ -159,8 +63,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_EVENTFD) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/eventfd_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_EVENTFD) + #endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/ext/asio/asio/detail/fd_set_adapter.hpp b/ext/asio/asio/detail/fd_set_adapter.hpp index a575491bfb..953cad1729 100644 --- a/ext/asio/asio/detail/fd_set_adapter.hpp +++ b/ext/asio/asio/detail/fd_set_adapter.hpp @@ -1,8 +1,8 @@ // -// fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/posix_fd_set_adapter.hpp" #include "asio/detail/win_fd_set_adapter.hpp" @@ -36,6 +31,4 @@ typedef posix_fd_set_adapter fd_set_adapter; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/ext/asio/asio/detail/fenced_block.hpp b/ext/asio/asio/detail/fenced_block.hpp index 60198bc65b..70c47e13cf 100644 --- a/ext/asio/asio/detail/fenced_block.hpp +++ b/ext/asio/asio/detail/fenced_block.hpp @@ -1,8 +1,8 @@ // -// fenced_block.hpp -// ~~~~~~~~~~~~~~~~ +// detail/fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) \ + || defined(ASIO_DISABLE_THREADS) \ + || defined(ASIO_DISABLE_FENCED_BLOCK) # include "asio/detail/null_fenced_block.hpp" #elif defined(__MACH__) && defined(__APPLE__) # include "asio/detail/macos_fenced_block.hpp" #elif defined(__sun) # include "asio/detail/solaris_fenced_block.hpp" +#elif defined(__GNUC__) && defined(__arm__) +# include "asio/detail/gcc_arm_fenced_block.hpp" +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +# include "asio/detail/gcc_hppa_fenced_block.hpp" #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) -# include "asio/detail/gcc_fenced_block.hpp" +# include "asio/detail/gcc_sync_fenced_block.hpp" #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) # include "asio/detail/gcc_x86_fenced_block.hpp" #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) @@ -43,17 +45,23 @@ namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) \ + || defined(ASIO_DISABLE_THREADS) \ + || defined(ASIO_DISABLE_FENCED_BLOCK) typedef null_fenced_block fenced_block; #elif defined(__MACH__) && defined(__APPLE__) typedef macos_fenced_block fenced_block; #elif defined(__sun) typedef solaris_fenced_block fenced_block; +#elif defined(__GNUC__) && defined(__arm__) +typedef gcc_arm_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +typedef gcc_hppa_fenced_block fenced_block; #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) -typedef gcc_fenced_block fenced_block; +typedef gcc_sync_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) typedef gcc_x86_fenced_block fenced_block; #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) @@ -65,6 +73,4 @@ typedef null_fenced_block fenced_block; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/gcc_arm_fenced_block.hpp b/ext/asio/asio/detail/gcc_arm_fenced_block.hpp new file mode 100644 index 0000000000..76c4d99900 --- /dev/null +++ b/ext/asio/asio/detail/gcc_arm_fenced_block.hpp @@ -0,0 +1,76 @@ +// +// detail/gcc_arm_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && defined(__arm__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_arm_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_arm_fenced_block() + { + barrier(); + } + + // Destructor. + ~gcc_arm_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { +#if defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) \ + || defined(__ARM_ARCH_5__) \ + || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) \ + || defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) + int a = 0, b = 0; + __asm__ __volatile__ ("swp %0, %1, [%2]" + : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc"); +#else + // ARMv7 and later. + __asm__ __volatile__ ("dmb" : : : "memory"); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && defined(__arm__) + +#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp b/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp new file mode 100644 index 0000000000..215086a6cc --- /dev/null +++ b/ext/asio/asio/detail/gcc_hppa_fenced_block.hpp @@ -0,0 +1,58 @@ +// +// detail/gcc_hppa_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_hppa_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_hppa_fenced_block() + { + barrier(); + } + + // Destructor. + ~gcc_hppa_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/gcc_sync_fenced_block.hpp b/ext/asio/asio/detail/gcc_sync_fenced_block.hpp new file mode 100644 index 0000000000..569b559124 --- /dev/null +++ b/ext/asio/asio/detail/gcc_sync_fenced_block.hpp @@ -0,0 +1,61 @@ +// +// detail/gcc_sync_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_sync_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_sync_fenced_block() + : value_(0) + { + __sync_lock_test_and_set(&value_, 1); + } + + // Destructor. + ~gcc_sync_fenced_block() + { + __sync_lock_release(&value_); + } + +private: + int value_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) + // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + // && !defined(__INTEL_COMPILER) && !defined(__ICL) + // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/gcc_x86_fenced_block.hpp b/ext/asio/asio/detail/gcc_x86_fenced_block.hpp index 48119f4c39..3e2e5bcb7e 100644 --- a/ext/asio/asio/detail/gcc_x86_fenced_block.hpp +++ b/ext/asio/asio/detail/gcc_x86_fenced_block.hpp @@ -1,8 +1,8 @@ // -// gcc_x86_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -54,8 +52,8 @@ private: } // namespace detail } // namespace asio -#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - #include "asio/detail/pop_options.hpp" +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + #endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/handler_alloc_helpers.hpp b/ext/asio/asio/detail/handler_alloc_helpers.hpp index 0ac42a7b12..9ae80de916 100644 --- a/ext/asio/asio/detail/handler_alloc_helpers.hpp +++ b/ext/asio/asio/detail/handler_alloc_helpers.hpp @@ -1,8 +1,8 @@ // -// handler_alloc_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <boost/detail/workaround.hpp> #include <boost/utility/addressof.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/handler_alloc_hook.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/handler_alloc_hook.hpp" + +#include "asio/detail/push_options.hpp" // Calls to asio_handler_allocate and asio_handler_deallocate must be made from // a namespace that does not contain any overloads of these functions. The @@ -56,203 +54,31 @@ inline void deallocate(void* p, std::size_t s, Handler& h) } // namespace asio_handler_alloc_helpers -namespace asio { -namespace detail { - -// Traits for handler allocation. -template <typename Handler, typename Object> -struct handler_alloc_traits -{ - typedef Handler handler_type; - typedef Object value_type; - typedef Object* pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object)); -}; - -template <typename Alloc_Traits> -class handler_ptr; - -// Helper class to provide RAII on uninitialised handler memory. -template <typename Alloc_Traits> -class raw_handler_ptr - : private noncopyable -{ -public: - typedef typename Alloc_Traits::handler_type handler_type; - typedef typename Alloc_Traits::value_type value_type; - typedef typename Alloc_Traits::pointer_type pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); - - // Constructor allocates the memory. - raw_handler_ptr(handler_type& handler) - : handler_(handler), - pointer_(static_cast<pointer_type>( - asio_handler_alloc_helpers::allocate(value_size, handler_))) - { - } - - // Destructor automatically deallocates memory, unless it has been stolen by - // a handler_ptr object. - ~raw_handler_ptr() - { - if (pointer_) - asio_handler_alloc_helpers::deallocate( - pointer_, value_size, handler_); - } - -private: - friend class handler_ptr<Alloc_Traits>; - handler_type& handler_; - pointer_type pointer_; -}; - -// Helper class to provide RAII on uninitialised handler memory. -template <typename Alloc_Traits> -class handler_ptr - : private noncopyable -{ -public: - typedef typename Alloc_Traits::handler_type handler_type; - typedef typename Alloc_Traits::value_type value_type; - typedef typename Alloc_Traits::pointer_type pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); - typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type; - - // Take ownership of existing memory. - handler_ptr(handler_type& handler, pointer_type pointer) - : handler_(handler), - pointer_(pointer) - { - } - - // Construct object in raw memory and take ownership if construction succeeds. - handler_ptr(raw_ptr_type& raw_ptr) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2, typename Arg3> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, - typename Arg5> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, - typename Arg5, typename Arg6> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, - typename Arg5, typename Arg6, typename Arg7> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6, Arg7& a7) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, - typename Arg5, typename Arg6, typename Arg7, typename Arg8> - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type( - a1, a2, a3, a4, a5, a6, a7, a8)) - { - raw_ptr.pointer_ = 0; - } - - // Destructor automatically deallocates memory, unless it has been released. - ~handler_ptr() - { - reset(); - } - - // Get the memory. - pointer_type get() const - { - return pointer_; - } - - // Release ownership of the memory. - pointer_type release() - { - pointer_type tmp = pointer_; - pointer_ = 0; - return tmp; - } - - // Explicitly destroy and deallocate the memory. - void reset() - { - if (pointer_) - { - pointer_->value_type::~value_type(); - asio_handler_alloc_helpers::deallocate( - pointer_, value_size, handler_); - pointer_ = 0; - } - } - -private: - handler_type& handler_; - pointer_type pointer_; -}; - -} // namespace detail -} // namespace asio +#define ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + Handler* h; \ + void* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \ + v = 0; \ + } \ + } \ + } \ + /**/ #include "asio/detail/pop_options.hpp" diff --git a/ext/asio/asio/detail/handler_invoke_helpers.hpp b/ext/asio/asio/detail/handler_invoke_helpers.hpp index 8332567c9f..5b122d9f69 100644 --- a/ext/asio/asio/detail/handler_invoke_helpers.hpp +++ b/ext/asio/asio/detail/handler_invoke_helpers.hpp @@ -1,8 +1,8 @@ // -// handler_invoke_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <boost/detail/workaround.hpp> #include <boost/utility/addressof.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/handler_invoke_hook.hpp" +#include "asio/detail/push_options.hpp" + // Calls to asio_handler_invoke must be made from a namespace that does not // contain overloads of this function. The asio_handler_invoke_helpers // namespace is defined here for that purpose. diff --git a/ext/asio/asio/detail/hash_map.hpp b/ext/asio/asio/detail/hash_map.hpp index b2a1517865..a3957dfa33 100644 --- a/ext/asio/asio/detail/hash_map.hpp +++ b/ext/asio/asio/detail/hash_map.hpp @@ -1,8 +1,8 @@ // -// hash_map.hpp -// ~~~~~~~~~~~~ +// detail/hash_map.hpp +// ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,33 +15,38 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cassert> #include <list> #include <utility> -#include <boost/functional/hash.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/noncopyable.hpp" -#include "asio/detail/socket_types.hpp" + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include "asio/detail/socket_types.hpp" +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename T> -inline std::size_t calculate_hash_value(const T& t) +inline std::size_t calculate_hash_value(int i) +{ + return static_cast<std::size_t>(i); +} + +inline std::size_t calculate_hash_value(void* p) { - return boost::hash_value(t); + return reinterpret_cast<std::size_t>(p) + + (reinterpret_cast<std::size_t>(p) >> 3); } -#if defined(_WIN64) +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) inline std::size_t calculate_hash_value(SOCKET s) { return static_cast<std::size_t>(s); } -#endif // defined(_WIN64) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Note: assumes K and V are POD types. template <typename K, typename V> diff --git a/ext/asio/asio/detail/impl/descriptor_ops.ipp b/ext/asio/asio/detail/impl/descriptor_ops.ipp new file mode 100644 index 0000000000..db08c26351 --- /dev/null +++ b/ext/asio/asio/detail/impl/descriptor_ops.ipp @@ -0,0 +1,370 @@ +// +// detail/impl/descriptor_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP +#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cerrno> +#include "asio/detail/descriptor_ops.hpp" +#include "asio/error.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace descriptor_ops { + +int open(const char* path, int flags, asio::error_code& ec) +{ + errno = 0; + int result = error_wrapper(::open(path, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +} + +int close(int d, state_type& state, asio::error_code& ec) +{ + int result = 0; + if (d != -1) + { + if (state & internal_non_blocking) + { +#if defined(__SYMBIAN32__) + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(d, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) + state &= ~internal_non_blocking; + } + + errno = 0; + result = error_wrapper(::close(d), ec); + } + + if (result == 0) + ec = asio::error_code(); + return result; +} + +bool set_internal_non_blocking(int d, + state_type& state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return false; + } + + errno = 0; +#if defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + if (result >= 0) + { + errno = 0; + result = error_wrapper(::fcntl(d, F_SETFL, result | O_NONBLOCK), ec); + } +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); +#endif // defined(__SYMBIAN32__) + + if (result >= 0) + { + ec = asio::error_code(); + state |= internal_non_blocking; + return true; + } + + return false; +} + +std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = asio::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, ec) < 0) + return 0; + } +} + +bool non_blocking_read(int d, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + errno = 0; + int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec); + + // Check for end of stream. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes > 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +std::size_t sync_write(int d, state_type state, const buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = asio::error_code(); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, ec) < 0) + return 0; + } +} + +bool non_blocking_write(int d, const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + errno = 0; + int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::ioctl(d, cmd, arg), ec); + + if (result >= 0) + { + ec = asio::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (cmd == static_cast<long>(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int fcntl(int d, long cmd, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd), ec); + if (result != -1) + ec = asio::error_code(); + return result; +} + +int fcntl(int d, long cmd, long arg, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd, arg), ec); + if (result != -1) + ec = asio::error_code(); + return result; +} + +int poll_read(int d, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +} + +int poll_write(int d, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP diff --git a/ext/asio/asio/detail/impl/dev_poll_reactor.hpp b/ext/asio/asio/detail/impl/dev_poll_reactor.hpp new file mode 100644 index 0000000000..7fbef82c3d --- /dev/null +++ b/ext/asio/asio/detail/impl/dev_poll_reactor.hpp @@ -0,0 +1,77 @@ +// +// detail/impl/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP +#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + io_service_.post_immediate_completion(op); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template <typename Time_Traits> +std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP diff --git a/ext/asio/asio/detail/impl/dev_poll_reactor.ipp b/ext/asio/asio/detail/impl/dev_poll_reactor.ipp new file mode 100644 index 0000000000..0d1456fcbb --- /dev/null +++ b/ext/asio/asio/detail/impl/dev_poll_reactor.ipp @@ -0,0 +1,338 @@ +// +// detail/impl/dev_poll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP +#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/dev_poll_reactor.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +dev_poll_reactor::dev_poll_reactor(asio::io_service& io_service) + : asio::detail::service_base<dev_poll_reactor>(io_service), + io_service_(use_service<io_service_impl>(io_service)), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); +} + +dev_poll_reactor::~dev_poll_reactor() +{ + shutdown_service(); + ::close(dev_poll_fd_); +} + +void dev_poll_reactor::shutdown_service() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); +} + +void dev_poll_reactor::init_task() +{ + io_service_.init_task(); +} + +int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) +{ + return 0; +} + +void dev_poll_reactor::start_op(int op_type, socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, + reactor_op* op, bool allow_speculative) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op); + return; + } + + if (allow_speculative) + { + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) + { + if (!op_queue_[op_type].has_operation(descriptor)) + { + if (op->perform()) + { + lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + } + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) + ev.events |= POLLOUT; + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::cancel_ops(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void dev_poll_reactor::close_descriptor(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void dev_poll_reactor::run(bool block, op_queue<operation>& ops) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) + return; + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + if (events_size > 0) + { + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast<int>(events_size)) + { + asio::error_code ec = asio::error_code( + errno, asio::error::get_system_category()); + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + } + + int timeout = block ? get_timeout() : 0; + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0 } }; + ::dvpoll dp = { 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) + more_except = + op_queue_[except_op].perform_operations(descriptor, ops); + else + more_except = op_queue_[except_op].has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + else + more_reads = op_queue_[read_op].has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); + else + more_writes = op_queue_[write_op].has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + } + } + timer_queues_.get_ready_timers(ops); +} + +void dev_poll_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int dev_poll_reactor::do_dev_poll_create() +{ + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "/dev/poll"); + } + return fd; +} + +void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +int dev_poll_reactor::get_timeout() +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + return timer_queues_.wait_duration_msec(5 * 60 * 1000); +} + +void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec) +{ + bool need_interrupt = false; + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + io_service_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) +{ + hash_map<int, std::size_t>::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP diff --git a/ext/asio/asio/detail/impl/epoll_reactor.hpp b/ext/asio/asio/detail/impl/epoll_reactor.hpp new file mode 100644 index 0000000000..9f50a235bc --- /dev/null +++ b/ext/asio/asio/detail/impl/epoll_reactor.hpp @@ -0,0 +1,75 @@ +// +// detail/impl/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP +#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(ASIO_HAS_EPOLL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + io_service_.post_immediate_completion(op); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + io_service_.work_started(); + if (earliest) + update_timeout(); +} + +template <typename Time_Traits> +std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP diff --git a/ext/asio/asio/detail/impl/epoll_reactor.ipp b/ext/asio/asio/detail/impl/epoll_reactor.ipp new file mode 100644 index 0000000000..a95b8f290d --- /dev/null +++ b/ext/asio/asio/detail/impl/epoll_reactor.ipp @@ -0,0 +1,390 @@ +// +// detail/impl/epoll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP +#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EPOLL) + +#include <cstddef> +#include <sys/epoll.h> +#include "asio/detail/epoll_reactor.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#if defined(ASIO_HAS_TIMERFD) +# include <sys/timerfd.h> +#endif // defined(ASIO_HAS_TIMERFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +epoll_reactor::epoll_reactor(asio::io_service& io_service) + : asio::detail::service_base<epoll_reactor>(io_service), + io_service_(use_service<io_service_impl>(io_service)), + mutex_(), + epoll_fd_(do_epoll_create()), +#if defined(ASIO_HAS_TIMERFD) + timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), +#else // defined(ASIO_HAS_TIMERFD) + timer_fd_(-1), +#endif // defined(ASIO_HAS_TIMERFD) + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } +} + +epoll_reactor::~epoll_reactor() +{ + close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); +} + +void epoll_reactor::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); +} + +void epoll_reactor::init_task() +{ + io_service_.init_task(); +} + +int epoll_reactor::register_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_data = registered_descriptors_.alloc(); + descriptor_data->shutdown_ = false; + + lock.unlock(); + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + + return 0; +} + +void epoll_reactor::start_op(int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + else + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP + | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); +} + +void epoll_reactor::cancel_ops(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void epoll_reactor::close_descriptor(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + + if (!descriptor_data->shutdown_) + { + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the epoll set when it is closed. + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + registered_descriptors_.free(descriptor_data); + descriptor_data = 0; + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); + } +} + +void epoll_reactor::run(bool block, op_queue<operation>& ops) +{ + // Calculate a timeout only if timerfd is not used. + int timeout; + if (timer_fd_ != -1) + timeout = block ? -1 : 0; + else + { + mutex::scoped_lock lock(mutex_); + timeout = block ? get_timeout() : 0; + } + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); + +#if defined(ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(ASIO_HAS_TIMERFD) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(ASIO_HAS_TIMERFD) + } +#if defined(ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(ASIO_HAS_TIMERFD) + else + { + descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + } + + if (check_timers) + { + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(ASIO_HAS_TIMERFD) + } +} + +void epoll_reactor::interrupt() +{ + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); +} + +int epoll_reactor::do_epoll_create() +{ + int fd = epoll_create(epoll_size); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "epoll"); + } + return fd; +} + +void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void epoll_reactor::update_timeout() +{ +#if defined(ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(ASIO_HAS_TIMERFD) + interrupt(); +} + +int epoll_reactor::get_timeout() +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + return timer_queues_.wait_duration_msec(5 * 60 * 1000); +} + +#if defined(ASIO_HAS_TIMERFD) +int epoll_reactor::get_timeout(itimerspec& ts) +{ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; +} +#endif // defined(ASIO_HAS_TIMERFD) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP diff --git a/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp b/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp new file mode 100644 index 0000000000..959d356af7 --- /dev/null +++ b/ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp @@ -0,0 +1,125 @@ +// +// detail/impl/eventfd_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EVENTFD) + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include <asm/unistd.h> +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include <sys/eventfd.h> +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include "asio/detail/eventfd_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +eventfd_select_interrupter::eventfd_select_interrupter() +{ +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "eventfd_select_interrupter"); + } + } +} + +eventfd_select_interrupter::~eventfd_select_interrupter() +{ + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); +} + +void eventfd_select_interrupter::interrupt() +{ + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; +} + +bool eventfd_select_interrupter::reset() +{ + if (write_descriptor_ == read_descriptor_) + { + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + } + else + { + for (;;) + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EVENTFD) + +#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP diff --git a/ext/asio/asio/detail/impl/kqueue_reactor.hpp b/ext/asio/asio/detail/impl/kqueue_reactor.hpp new file mode 100644 index 0000000000..7950c3b976 --- /dev/null +++ b/ext/asio/asio/detail/impl/kqueue_reactor.hpp @@ -0,0 +1,79 @@ +// +// detail/impl/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP +#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template <typename Time_Traits> +void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + io_service_.post_immediate_completion(op); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + io_service_.work_started(); + if (earliest) + interrupt(); +} + +template <typename Time_Traits> +std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP diff --git a/ext/asio/asio/detail/impl/kqueue_reactor.ipp b/ext/asio/asio/detail/impl/kqueue_reactor.ipp new file mode 100644 index 0000000000..8db77cb3e5 --- /dev/null +++ b/ext/asio/asio/detail/impl/kqueue_reactor.ipp @@ -0,0 +1,385 @@ +// +// detail/impl/kqueue_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP +#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include "asio/detail/kqueue_reactor.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(__NetBSD__) +# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, \ + data, reinterpret_cast<intptr_t>(udata)) +#else +# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, udata) +#endif + +namespace asio { +namespace detail { + +kqueue_reactor::kqueue_reactor(asio::io_service& io_service) + : asio::detail::service_base<kqueue_reactor>(io_service), + io_service_(use_service<io_service_impl>(io_service)), + mutex_(), + kqueue_fd_(do_kqueue_create()), + interrupter_(), + shutdown_(false) +{ + // The interrupter is put into a permanently readable state. Whenever we + // want to interrupt the blocked kevent call we register a one-shot read + // operation against the descriptor. + interrupter_.interrupt(); +} + +kqueue_reactor::~kqueue_reactor() +{ + close(kqueue_fd_); +} + +void kqueue_reactor::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); +} + +void kqueue_reactor::init_task() +{ + io_service_.init_task(); +} + +int kqueue_reactor::register_descriptor(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_data = registered_descriptors_.alloc(); + descriptor_data->shutdown_ = false; + + return 0; +} + +void kqueue_reactor::start_op(int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op); + return; + } + + bool first = descriptor_data->op_queue_[op_type].empty(); + if (first) + { + if (allow_speculative) + { + if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + } + } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); + + if (first) + { + struct kevent event; + switch (op_type) + { + case read_op: + ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case write_op: + ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case except_op: + if (!descriptor_data->op_queue_[read_op].empty()) + return; // Already registered for read events. + ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + break; + } + + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + op->ec_ = asio::error_code(errno, + asio::error::get_system_category()); + descriptor_data->op_queue_[op_type].pop(); + io_service_.post_deferred_completion(op); + } + } +} + +void kqueue_reactor::cancel_ops(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void kqueue_reactor::close_descriptor(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + + if (!descriptor_data->shutdown_) + { + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the kqueue set when it is closed. + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + registered_descriptors_.free(descriptor_data); + descriptor_data = 0; + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); + } +} + +void kqueue_reactor::run(bool block, op_queue<operation>& ops) +{ + mutex::scoped_lock lock(mutex_); + + // Determine how long to block while waiting for events. + timespec timeout_buf = { 0, 0 }; + timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; + + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].ident; + void* ptr = reinterpret_cast<void*>(events[i].udata); + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on one-shot notifications. + } + else + { + descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. +#if defined(__NetBSD__) + static const unsigned int filter[max_ops] = +#else + static const int filter[max_ops] = +#endif + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = asio::error_code(events[i].data, + asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + + // Renew registration for event notifications. + struct kevent event; + switch (events[i].filter) + { + case EVFILT_READ: + if (!descriptor_data->op_queue_[read_op].empty()) + ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else if (!descriptor_data->op_queue_[except_op].empty()) + ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + else + continue; + case EVFILT_WRITE: + if (!descriptor_data->op_queue_[write_op].empty()) + ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else + continue; + default: + break; + } + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + asio::error_code error(errno, + asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + op->ec_ = error; + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + } + } + } + } + + lock.lock(); + timer_queues_.get_ready_timers(ops); +} + +void kqueue_reactor::interrupt() +{ + struct kevent event; + ASIO_KQUEUE_EV_SET(&event, interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); + ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); +} + +int kqueue_reactor::do_kqueue_create() +{ + int fd = ::kqueue(); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue"); + } + return fd; +} + +void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timespec* kqueue_reactor::get_timeout(timespec& ts) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + return &ts; +} + +} // namespace detail +} // namespace asio + +#undef ASIO_KQUEUE_EV_SET + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP diff --git a/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp b/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp new file mode 100644 index 0000000000..aac20d43d2 --- /dev/null +++ b/ext/asio/asio/detail/impl/pipe_select_interrupter.ipp @@ -0,0 +1,96 @@ +// +// detail/impl/pipe_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(BOOST_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(ASIO_HAS_EVENTFD) + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "asio/detail/pipe_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +pipe_select_interrupter::pipe_select_interrupter() +{ + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "pipe_select_interrupter"); + } +} + +pipe_select_interrupter::~pipe_select_interrupter() +{ + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); +} + +void pipe_select_interrupter::interrupt() +{ + char byte = 0; + int result = ::write(write_descriptor_, &byte, 1); + (void)result; +} + +bool pipe_select_interrupter::reset() +{ + for (;;) + { + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(BOOST_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP diff --git a/ext/asio/asio/detail/impl/posix_event.ipp b/ext/asio/asio/detail/impl/posix_event.ipp new file mode 100644 index 0000000000..3206418c54 --- /dev/null +++ b/ext/asio/asio/detail/impl/posix_event.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_EVENT_IPP +#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#include "asio/detail/posix_event.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_event::posix_event() + : signalled_(false) +{ + int error = ::pthread_cond_init(&cond_, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP diff --git a/ext/asio/asio/detail/impl/posix_mutex.ipp b/ext/asio/asio/detail/impl/posix_mutex.ipp new file mode 100644 index 0000000000..12b6659745 --- /dev/null +++ b/ext/asio/asio/detail/impl/posix_mutex.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP +#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#include "asio/detail/posix_mutex.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_mutex::posix_mutex() +{ + int error = ::pthread_mutex_init(&mutex_, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "mutex"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP diff --git a/ext/asio/asio/detail/impl/posix_thread.ipp b/ext/asio/asio/detail/impl/posix_thread.ipp new file mode 100644 index 0000000000..ce91c57bbc --- /dev/null +++ b/ext/asio/asio/detail/impl/posix_thread.ipp @@ -0,0 +1,74 @@ +// +// detail/impl/posix_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_THREAD_IPP +#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#include "asio/detail/posix_thread.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_thread::~posix_thread() +{ + if (!joined_) + ::pthread_detach(thread_); +} + +void posix_thread::join() +{ + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } +} + +void posix_thread::start_thread(func_base* arg) +{ + int error = ::pthread_create(&thread_, 0, + asio_detail_posix_thread_function, arg); + if (error != 0) + { + delete arg; + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } +} + +void* asio_detail_posix_thread_function(void* arg) +{ + posix_thread::auto_func_base_ptr func = { + static_cast<posix_thread::func_base*>(arg) }; + func.ptr->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP diff --git a/ext/asio/asio/detail/impl/posix_tss_ptr.ipp b/ext/asio/asio/detail/impl/posix_tss_ptr.ipp new file mode 100644 index 0000000000..89b40f7022 --- /dev/null +++ b/ext/asio/asio/detail/impl/posix_tss_ptr.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP +#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#include "asio/detail/posix_tss_ptr.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void posix_tss_ptr_create(pthread_key_t& key) +{ + int error = ::pthread_key_create(&key, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "tss"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP diff --git a/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp b/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp new file mode 100644 index 0000000000..706d60f423 --- /dev/null +++ b/ext/asio/asio/detail/impl/reactive_descriptor_service.ipp @@ -0,0 +1,136 @@ +// +// detail/impl/reactive_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/error.hpp" +#include "asio/detail/reactive_descriptor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_descriptor_service::reactive_descriptor_service( + asio::io_service& io_service) + : reactor_(asio::use_service<reactor>(io_service)) +{ + reactor_.init_task(); +} + +void reactive_descriptor_service::shutdown_service() +{ +} + +void reactive_descriptor_service::construct( + reactive_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; +} + +void reactive_descriptor_service::destroy( + reactive_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + asio::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); +} + +asio::error_code reactive_descriptor_service::assign( + reactive_descriptor_service::implementation_type& impl, + const native_type& native_descriptor, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.state_ = 0; + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_descriptor_service::close( + reactive_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0) + construct(impl); + + return ec; +} + +asio::error_code reactive_descriptor_service::cancel( + reactive_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = asio::error_code(); + return ec; +} + +void reactive_descriptor_service::start_op( + reactive_descriptor_service::implementation_type& impl, + int op_type, reactor_op* op, bool non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & descriptor_ops::non_blocking) || + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp b/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp new file mode 100644 index 0000000000..c4df79303c --- /dev/null +++ b/ext/asio/asio/detail/impl/reactive_serial_port_service.ipp @@ -0,0 +1,151 @@ +// +// detail/impl/reactive_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include <cstring> +#include "asio/detail/reactive_serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_serial_port_service::reactive_serial_port_service( + asio::io_service& io_service) + : descriptor_service_(io_service) +{ +} + +void reactive_serial_port_service::shutdown_service() +{ + descriptor_service_.shutdown_service(); +} + +asio::error_code reactive_serial_port_service::open( + reactive_serial_port_service::implementation_type& impl, + const std::string& device, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + descriptor_ops::state_type state = 0; + int fd = descriptor_ops::open(device.c_str(), + O_RDWR | O_NONBLOCK | O_NOCTTY, ec); + if (fd < 0) + return ec; + + int s = descriptor_ops::fcntl(fd, F_GETFL, ec); + if (s >= 0) + s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); + if (s < 0) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + errno = 0; + s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + if (s >= 0) + { +#if defined(_BSD_SOURCE) + ::cfmakeraw(&ios); +#else + ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK + | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + ios.c_oflag &= ~OPOST; + ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ios.c_cflag &= ~(CSIZE | PARENB); + ios.c_cflag |= CS8; +#endif + ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; + errno = 0; + s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + } + if (s < 0) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + return ec; +} + +asio::error_code reactive_serial_port_service::do_set_option( + reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::store_function_type store, + const void* option, asio::error_code& ec) +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + if (store(option, ios, ec)) + return ec; + + errno = 0; + descriptor_ops::error_wrapper(::tcsetattr( + descriptor_service_.native(impl), TCSANOW, &ios), ec); + return ec; +} + +asio::error_code reactive_serial_port_service::do_get_option( + const reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::load_function_type load, + void* option, asio::error_code& ec) const +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + return load(option, ios, ec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp b/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp new file mode 100644 index 0000000000..54e7944875 --- /dev/null +++ b/ext/asio/asio/detail/impl/reactive_socket_service_base.ipp @@ -0,0 +1,212 @@ +// +// detail/reactive_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) + +#include "asio/detail/reactive_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_socket_service_base::reactive_socket_service_base( + asio::io_service& io_service) + : reactor_(use_service<reactor>(io_service)) +{ + reactor_.init_task(); +} + +void reactive_socket_service_base::shutdown_service() +{ +} + +void reactive_socket_service_base::construct( + reactive_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; +} + +void reactive_socket_service_base::destroy( + reactive_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + } +} + +asio::error_code reactive_socket_service_base::close( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0) + construct(impl); + + return ec; +} + +asio::error_code reactive_socket_service_base::cancel( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_socket_service_base::do_open( + reactive_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_socket_service_base::do_assign( + reactive_socket_service_base::base_implementation_type& impl, int type, + const reactive_socket_service_base::native_type& native_socket, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = asio::error_code(); + return ec; +} + +void reactive_socket_service_base::start_op( + reactive_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op, bool non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op); +} + +void reactive_socket_service_base::start_accept_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, reactor::read_op, op, true, false); + else + { + op->ec_ = asio::error::already_open; + reactor_.post_immediate_completion(op); + } +} + +void reactive_socket_service_base::start_connect_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, size_t addrlen) +{ + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == asio::error::in_progress + || op->ec_ == asio::error::would_block) + { + op->ec_ = asio::error_code(); + reactor_.start_op(reactor::connect_op, + impl.socket_, impl.reactor_data_, op, false); + return; + } + } + } + + reactor_.post_immediate_completion(op); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/ext/asio/asio/detail/impl/resolver_service_base.ipp b/ext/asio/asio/detail/impl/resolver_service_base.ipp new file mode 100644 index 0000000000..a844a2374e --- /dev/null +++ b/ext/asio/asio/detail/impl/resolver_service_base.ipp @@ -0,0 +1,106 @@ +// +// detail/impl/resolver_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/resolver_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolver_service_base::work_io_service_runner +{ +public: + work_io_service_runner(asio::io_service& io_service) + : io_service_(io_service) {} + void operator()() { io_service_.run(); } +private: + asio::io_service& io_service_; +}; + +resolver_service_base::resolver_service_base( + asio::io_service& io_service) + : io_service_impl_(asio::use_service<io_service_impl>(io_service)), + work_io_service_(new asio::io_service), + work_io_service_impl_(asio::use_service< + io_service_impl>(*work_io_service_)), + work_(new asio::io_service::work(*work_io_service_)), + work_thread_(0) +{ +} + +resolver_service_base::~resolver_service_base() +{ + shutdown_service(); +} + +void resolver_service_base::shutdown_service() +{ + work_.reset(); + if (work_io_service_) + { + work_io_service_->stop(); + if (work_thread_) + { + work_thread_->join(); + work_thread_.reset(); + } + work_io_service_.reset(); + } +} + +void resolver_service_base::construct( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast<void*>(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::destroy( + resolver_service_base::implementation_type&) +{ +} + +void resolver_service_base::cancel( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast<void*>(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::start_resolve_op(operation* op) +{ + start_work_thread(); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(op); +} + +void resolver_service_base::start_work_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_) + { + work_thread_.reset(new asio::detail::thread( + work_io_service_runner(*work_io_service_))); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP diff --git a/ext/asio/asio/detail/impl/select_reactor.hpp b/ext/asio/asio/detail/impl/select_reactor.hpp new file mode 100644 index 0000000000..50d3ad42d0 --- /dev/null +++ b/ext/asio/asio/detail/impl/select_reactor.hpp @@ -0,0 +1,84 @@ +// +// detail/impl/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP +#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE)) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template <typename Time_Traits> +void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + io_service_.post_immediate_completion(op); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template <typename Time_Traits> +std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE)) + +#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP diff --git a/ext/asio/asio/detail/impl/select_reactor.ipp b/ext/asio/asio/detail/impl/select_reactor.ipp new file mode 100644 index 0000000000..1a59be37e7 --- /dev/null +++ b/ext/asio/asio/detail/impl/select_reactor.ipp @@ -0,0 +1,273 @@ +// +// detail/impl/select_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP +#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE)) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fd_set_adapter.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/signal_blocker.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +select_reactor::select_reactor(asio::io_service& io_service) + : asio::detail::service_base<select_reactor>(io_service), + io_service_(use_service<io_service_impl>(io_service)), + mutex_(), + interrupter_(), +#if defined(ASIO_HAS_IOCP) + stop_thread_(false), + thread_(0), +#endif // defined(ASIO_HAS_IOCP) + shutdown_(false) +{ +#if defined(ASIO_HAS_IOCP) + asio::detail::signal_blocker sb; + thread_ = new asio::detail::thread( + bind_handler(&select_reactor::call_run_thread, this)); +#endif // defined(ASIO_HAS_IOCP) +} + +select_reactor::~select_reactor() +{ + shutdown_service(); +} + +void select_reactor::shutdown_service() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; +#if defined(ASIO_HAS_IOCP) + stop_thread_ = true; +#endif // defined(ASIO_HAS_IOCP) + lock.unlock(); + +#if defined(ASIO_HAS_IOCP) + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } +#endif // defined(ASIO_HAS_IOCP) + + op_queue<operation> ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); +} + +void select_reactor::init_task() +{ + io_service_.init_task(); +} + +int select_reactor::register_descriptor(socket_type, + select_reactor::per_descriptor_data&) +{ + return 0; +} + +void select_reactor::start_op(int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op); + return; + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) + interrupter_.interrupt(); +} + +void select_reactor::cancel_ops(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void select_reactor::close_descriptor(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void select_reactor::run(bool block, op_queue<operation>& ops) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_IOCP) + // Check if the thread is supposed to stop. + if (stop_thread_) + return; +#endif // defined(ASIO_HAS_IOCP) + + // Set up the descriptor sets. + fd_set_adapter fds[max_select_ops]; + fds[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) + { + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + op_queue_[i].get_descriptors(fds[i], ops); + if (fds[i].max_descriptor() > max_fd) + max_fd = fds[i].max_descriptor(); + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + op_queue_[connect_op].get_descriptors(fds[write_op], ops); + if (fds[write_op].max_descriptor() > max_fd) + max_fd = fds[write_op].max_descriptor(); + op_queue_[connect_op].get_descriptors(fds[except_op], ops); + if (fds[except_op].max_descriptor() > max_fd) + max_fd = fds[except_op].max_descriptor(); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && !have_work_to_do) + return; + + // Determine how long to block while waiting for events. + timeval tv_buf = { 0, 0 }; + timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; + + lock.unlock(); + + // Block on the select call until descriptors become ready. + asio::error_code ec; + int retval = socket_ops::select(static_cast<int>(max_fd + 1), + fds[read_op], fds[write_op], fds[except_op], tv, ec); + + // Reset the interrupter. + if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) + interrupter_.reset(); + + lock.lock(); + + // Dispatch all ready operations. + if (retval > 0) + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + op_queue_[connect_op].perform_operations_for_descriptors( + fds[except_op], ops); + op_queue_[connect_op].perform_operations_for_descriptors( + fds[write_op], ops); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + for (int i = max_select_ops - 1; i >= 0; --i) + op_queue_[i].perform_operations_for_descriptors(fds[i], ops); + } + timer_queues_.get_ready_timers(ops); +} + +void select_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +#if defined(ASIO_HAS_IOCP) +void select_reactor::run_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue<operation> ops; + run(true, ops); + io_service_.post_deferred_completions(ops); + lock.lock(); + } +} + +void select_reactor::call_run_thread(select_reactor* reactor) +{ + reactor->run_thread(); +} +#endif // defined(ASIO_HAS_IOCP) + +void select_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void select_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timeval* select_reactor::get_timeout(timeval& tv) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return &tv; +} + +void select_reactor::cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec) +{ + bool need_interrupt = false; + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + io_service_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE)) + +#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP diff --git a/ext/asio/asio/detail/impl/service_registry.hpp b/ext/asio/asio/detail/impl/service_registry.hpp new file mode 100644 index 0000000000..c2aa9ec4e4 --- /dev/null +++ b/ext/asio/asio/detail/impl/service_registry.hpp @@ -0,0 +1,70 @@ +// +// detail/impl/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP +#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Service> +Service& service_registry::use_service() +{ + asio::io_service::service::key key; + init_key(key, Service::id); + factory_type factory = &service_registry::create<Service>; + return *static_cast<Service*>(do_use_service(key, factory)); +} + +template <typename Service> +void service_registry::add_service(Service* new_service) +{ + asio::io_service::service::key key; + init_key(key, Service::id); + return do_add_service(key, new_service); +} + +template <typename Service> +bool service_registry::has_service() const +{ + asio::io_service::service::key key; + init_key(key, Service::id); + return do_has_service(key); +} + +#if !defined(ASIO_NO_TYPEID) +template <typename Service> +void service_registry::init_key(asio::io_service::service::key& key, + const asio::detail::service_id<Service>& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper<Service>); + key.id_ = 0; +} +#endif // !defined(ASIO_NO_TYPEID) + +template <typename Service> +asio::io_service::service* service_registry::create( + asio::io_service& owner) +{ + return new Service(owner); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP diff --git a/ext/asio/asio/detail/impl/service_registry.ipp b/ext/asio/asio/detail/impl/service_registry.ipp new file mode 100644 index 0000000000..57c57b88b0 --- /dev/null +++ b/ext/asio/asio/detail/impl/service_registry.ipp @@ -0,0 +1,164 @@ +// +// detail/impl/service_registry.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP +#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/throw_exception.hpp> +#include "asio/detail/service_registry.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +service_registry::service_registry(asio::io_service& o) + : owner_(o), + first_service_(0) +{ +} + +service_registry::~service_registry() +{ + // Shutdown all services. This must be done in a separate loop before the + // services are destroyed since the destructors of user-defined handler + // objects may try to access other service objects. + asio::io_service::service* service = first_service_; + while (service) + { + service->shutdown_service(); + service = service->next_; + } + + // Destroy all services. + while (first_service_) + { + asio::io_service::service* next_service = first_service_->next_; + destroy(first_service_); + first_service_ = next_service; + } +} + +void service_registry::init_key(asio::io_service::service::key& key, + const asio::io_service::id& id) +{ + key.type_info_ = 0; + key.id_ = &id; +} + +bool service_registry::keys_match( + const asio::io_service::service::key& key1, + const asio::io_service::service::key& key2) +{ + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; +} + +void service_registry::destroy(asio::io_service::service* service) +{ + delete service; +} + +asio::io_service::service* service_registry::do_use_service( + const asio::io_service::service::key& key, + factory_type factory) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // First see if there is an existing service object with the given key. + asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // at this time to allow for nested calls into this function from the new + // service's constructor. + lock.unlock(); + auto_service_ptr new_service = { factory(owner_) }; + new_service.ptr_->key_ = key; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; +} + +void service_registry::do_add_service( + const asio::io_service::service::key& key, + asio::io_service::service* new_service) +{ + if (&owner_ != &new_service->io_service()) + boost::throw_exception(invalid_service_owner()); + + asio::detail::mutex::scoped_lock lock(mutex_); + + // Check if there is an existing service object with the given key. + asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + boost::throw_exception(service_already_exists()); + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; +} + +bool service_registry::do_has_service( + const asio::io_service::service::key& key) const +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return true; + service = service->next_; + } + + return false; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP diff --git a/ext/asio/asio/detail/impl/socket_ops.ipp b/ext/asio/asio/detail/impl/socket_ops.ipp new file mode 100644 index 0000000000..d348d1b737 --- /dev/null +++ b/ext/asio/asio/detail/impl/socket_ops.ipp @@ -0,0 +1,2863 @@ +// +// detail/impl/socket_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_OPS_IPP +#define ASIO_DETAIL_SOCKET_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/assert.hpp> +#include <boost/detail/workaround.hpp> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cerrno> +#include <new> +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_ops { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +inline void clear_last_error() +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif +} + +template <typename ReturnType> +inline ReturnType error_wrapper(ReturnType return_value, + asio::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(WSAGetLastError(), + asio::error::get_system_category()); +#else + ec = asio::error_code(errno, + asio::error::get_system_category()); +#endif + return return_value; +} + +template <typename SockLenType> +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + clear_last_error(); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = error_wrapper(::setsockopt(new_s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + ec = asio::error_code(); + return new_s; +} + +socket_type sync_accept(socket_type s, state_type state, + socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) +{ + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return new_socket; + + // Operation failed. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + { + if (state & user_set_non_blocking) + return invalid_socket; + // Fall through to retry operation. + } + else if (ec == asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return invalid_socket; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return invalid_socket; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_aborted; + + if (!ec) + { + // Get the address of the peer. + if (addr && addrlen) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(output_buffer, 0, address_length, + address_length, &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast<std::size_t>(remote_addr_length) > *addrlen) + { + ec = asio::error::invalid_argument; + } + else + { + using namespace std; // For memcpy. + memcpy(addr, remote_addr, remote_addr_length); + *addrlen = static_cast<std::size_t>(remote_addr_length); + } + } + + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + SOCKET update_ctx_param = s; + socket_ops::state_type state = 0; + socket_ops::setsockopt(new_socket, state, + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, socket_type& new_socket) +{ + for (;;) + { + // Accept the waiting connection. + new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return true; + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Operation failed. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + { + if (state & user_set_non_blocking) + return true; + // Fall through to retry operation. + } + else if (ec == asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return true; + + return false; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +template <typename SockLenType> +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +int close(socket_type s, state_type& state, + bool destruction, asio::error_code& ec) +{ + int result = 0; + if (s != invalid_socket) + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if ((state & non_blocking) && (state & user_set_linger)) + { + ioctl_arg_type arg = 0; + ::ioctlsocket(s, FIONBIO, &arg); + state &= ~non_blocking; + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (state & non_blocking) + { +#if defined(__SYMBIAN32__) + int flags = ::fcntl(s, F_GETFL, 0); + if (flags >= 0) + ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(s, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) + state &= ~non_blocking; + } +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + if (destruction && (state & user_set_linger)) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + asio::error_code ignored_ec; + socket_ops::setsockopt(s, state, SOL_SOCKET, + SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::closesocket(s), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::close(s), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + } + + if (result == 0) + ec = asio::error_code(); + return result; +} + +bool set_internal_non_blocking(socket_type s, + state_type& state, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#elif defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + if (result >= 0) + { + clear_last_error(); + result = error_wrapper(::fcntl(s, F_SETFL, result | O_NONBLOCK), ec); + } +#else + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif + + if (result >= 0) + { + ec = asio::error_code(); + state |= internal_non_blocking; + return true; + } + + return false; +} + +int shutdown(socket_type s, int what, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::shutdown(s, what), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +template <typename SockLenType> +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + // Perform the connect operation. + socket_ops::connect(s, addr, addrlen, ec); + if (ec != asio::error::in_progress + && ec != asio::error::would_block) + { + // The connect operation finished immediately. + return; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(s, ec) < 0) + return; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return; + + // Return the result of the connect operation. + ec = asio::error_code(connect_error, + asio::error::get_system_category()); +} + +bool non_blocking_connect(socket_type s, asio::error_code& ec) +{ + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == 0) + { + if (connect_error) + { + ec = asio::error_code(connect_error, + asio::error::get_system_category()); + } + else + ec = asio::error_code(); + } + + return true; +} + +int socketpair(int af, int type, int protocol, + socket_type sv[2], asio::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = asio::error::operation_not_supported; + return socket_error_retval; +#else + clear_last_error(); + int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); + if (result == 0) + ec = asio::error_code(); + return result; +#endif +} + +bool sockatmark(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + +#if defined(SIOCATMARK) + ioctl_arg_type value = 0; +# if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); +# else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); +# endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = asio::error_code(); +# if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +# endif // defined(ENOTTY) +#else // defined(SIOCATMARK) + int value = error_wrapper(::sockatmark(s), ec); + if (value != -1) + ec = asio::error_code(); +#endif // defined(SIOCATMARK) + + return ec ? false : value != 0; +} + +size_t available(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + ioctl_arg_type value = 0; +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = asio::error_code(); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +#endif // defined(ENOTTY) + + return ec ? static_cast<size_t>(0) : static_cast<size_t>(value); +} + +int listen(socket_type s, int backlog, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::listen(s, backlog), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template <typename T> +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast<T>(addr); +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +void init_buf(buf& b, void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast<char*>(data); + b.len = static_cast<u_long>(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast<char*>(const_cast<void*>(data)); + b.len = static_cast<u_long>(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast<void*>(data)); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast<socket_addr_type*>(addr); +} + +template <typename T> +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast<T>(addr); +} + +template <typename T> +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr)); +} + +int recv(socket_type s, buf* bufs, size_t count, int flags, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, bufs, + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = asio::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + asio::error_code& ec, size_t bytes_transferred) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && (state & stream_oriented) != 0 + && !all_empty) + { + ec = asio::error::eof; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + int bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +int recvfrom(socket_type s, buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = *addrlen; + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + *addrlen = msg.msg_namelen; + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +int send(socket_type s, const buf* bufs, size_t count, int flags, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast<buf*>(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_send(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = asio::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + int bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +int sendto(socket_type s, const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast<int>(addrlen), 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = addrlen; + msg.msg_iov = const_cast<buf*>(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_sendto(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, ec) < 0) + return 0; + } +} + +#if !defined(ASIO_HAS_IOCP) + +bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // !defined(ASIO_HAS_IOCP) + +socket_type socket(int af, int type, int protocol, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == AF_INET6) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast<const char*>(&optval), sizeof(optval)); + } + + ec = asio::error_code(); + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = error_wrapper(::socket(af, type, protocol), ec); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = error_wrapper(::setsockopt(s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = error_wrapper(::socket(af, type, protocol), ec); + if (s >= 0) + ec = asio::error_code(); + return s; +#endif +} + +template <typename SockLenType> +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +int setsockopt(socket_type s, state_type& state, int level, int optname, + const void* optval, std::size_t optlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (optlen != sizeof(int)) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (*static_cast<const int*>(optval)) + state |= enable_connection_aborted; + else + state &= ~enable_connection_aborted; + ec = asio::error_code(); + return 0; + } + + if (level == SOL_SOCKET && optname == SO_LINGER) + state |= user_set_linger; + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + clear_last_error(); + return error_wrapper(sso(s, level, optname, + reinterpret_cast<const char*>(optval), + static_cast<int>(optlen)), ec); + } + } + ec = asio::error::fault; + return socket_error_retval; +#else // defined(__BORLANDC__) + clear_last_error(); + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result == 0) + { + ec = asio::error_code(); + +#if defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if ((state & datagram_oriented) + && level == SOL_SOCKET && optname == SO_REUSEADDR) + { + call_setsockopt(&msghdr::msg_namelen, s, + SOL_SOCKET, SO_REUSEPORT, optval, optlen); + } +#endif + } + + return result; +#endif // defined(__BORLANDC__) +} + +template <typename SockLenType> +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +int getsockopt(socket_type s, state_type state, int level, int optname, + void* optval, size_t* optlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (*optlen != sizeof(int)) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0; + ec = asio::error_code(); + return 0; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + clear_last_error(); + int tmp_optlen = static_cast<int>(*optlen); + int result = error_wrapper(gso(s, level, optname, + reinterpret_cast<char*>(optval), &tmp_optlen), ec); + *optlen = static_cast<size_t>(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast<DWORD*>(optval) = 1; + ec = asio::error_code(); + } + return result; + } + } + ec = asio::error::fault; + return socket_error_retval; +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast<DWORD*>(optval) = 1; + ec = asio::error_code(); + } + if (result == 0) + ec = asio::error_code(); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast<int*>(optval) /= 2; + } +#endif // defined(__linux__) + if (result == 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +template <typename SockLenType> +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (cached) + { + // Check if socket is still connected. + DWORD connect_time = 0; + size_t connect_time_len = sizeof(connect_time); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, + &connect_time, &connect_time_len, ec) == socket_error_retval) + { + return socket_error_retval; + } + if (connect_time == 0xFFFFFFFF) + { + ec = asio::error::not_connected; + return socket_error_retval; + } + + // The cached value is still valid. + ec = asio::error_code(); + return 0; + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)cached; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + clear_last_error(); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +template <typename SockLenType> +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +int ioctl(socket_type s, state_type& state, int cmd, + ioctl_arg_type* arg, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +#elif defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + int result = error_wrapper(::ioctl(s, + static_cast<unsigned int>(cmd), arg), ec); +#else + int result = error_wrapper(::ioctl(s, cmd, arg), ec); +#endif + if (result >= 0) + { + ec = asio::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the socket is already in + // the correct state. This ensures that the underlying socket is put into + // the state that has been requested by the user. If the ioctl syscall was + // successful then we need to update the flags to match. + if (cmd == static_cast<int>(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec = asio::error_code(); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif +} + +int poll_read(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_last_error(); + int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#else // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +int poll_write(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_last_error(); + int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#else // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +int poll_connect(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + clear_last_error(); + int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#else // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != AF_INET && af != AF_INET6) + { + ec = asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == AF_INET) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = AF_INET; + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = AF_INET6; + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast<DWORD>(length); +#if defined(BOOST_NO_ANSI_APIS) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); +#else + int result = error_wrapper(::WSAAddressToStringA( + &address.base, address_length, 0, dest, &string_length), ec); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + ec = asio::error_code(); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); + if (result == 0 && !ec) + ec = asio::error::invalid_argument; + if (result != 0 && af == AF_INET6 && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[IF_NAMESIZE + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != AF_INET && af != AF_INET6) + { + ec = asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) + int num_wide_chars = strlen(src) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, &address.base, &address_length), ec); +#else + int result = error_wrapper(::WSAStringToAddressA( + const_cast<char*>(src), af, 0, &address.base, &address_length), ec); +#endif + + if (af == AF_INET) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + ec = asio::error_code(); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; + ec = asio::error_code(); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + ec = asio::error_code(); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; + + if (result != socket_error_retval) + ec = asio::error_code(); + + return result == socket_error_retval ? -1 : 1; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::inet_pton(af, src, dest), ec); + if (result <= 0 && !ec) + ec = asio::error::invalid_argument; + if (result > 0 && af == AF_INET6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (const char* if_name = strchr(src, '%')) + { + in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (is_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int gethostname(char* name, int namelen, asio::error_code& ec) +{ + clear_last_error(); + int result = error_wrapper(::gethostname(name, namelen), ec); +#if defined(BOOST_WINDOWS) + if (result == 0) + ec = asio::error_code(); +#endif + return result; +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline asio::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return asio::error_code(); + case HOST_NOT_FOUND: + return asio::error::host_not_found; + case TRY_AGAIN: + return asio::error::host_not_found_try_again; + case NO_RECOVERY: + return asio::error::no_recovery; + case NO_DATA: + return asio::error::no_data; + default: + BOOST_ASSERT(false); + return asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + if (!retval) + return 0; + ec = asio::error_code(); + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, asio::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != AF_INET) + { + ec = asio::error::address_family_not_supported; + return 0; + } + hostent* retval = error_wrapper(::gethostbyname(name), ec); + if (!retval) + return 0; + ec = asio::error_code(); + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != AF_INET) + { + ec = asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyname( + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != AF_INET) + { + ec = asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template <typename T> +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast<T*>(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + strcpy_s(target, max_size, source); +#else + *target = 0; + strncat(target, source, max_size); +#endif +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc<addrinfo_type>(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = AF_INET; + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = AF_INET6; + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc<addrinfo_type>(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = + reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(static_cast<unsigned char>(serv[0]))) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case AF_UNSPEC: + break; + case AF_INET: + case AF_INET6: + if (service != 0 && service[0] != '\0') + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = AF_UNSPEC; + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + asio::error_code ec; + if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET6) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == asio::error::host_not_found) + return EAI_NONAME; + if (ec == asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == asio::error::no_recovery) + return EAI_FAIL; + if (ec == asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc<char>(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc<char>(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline asio::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + asio::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case AF_INET: + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = asio::error::invalid_argument; + } + addr = reinterpret_cast<const char*>( + &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port; + break; + case AF_INET6: + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = asio::error::invalid_argument; + } + addr = reinterpret_cast<const char*>( + &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port; + break; + default: + return ec = asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast<int>(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } + else + { +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ + && !defined(ASIO_DISABLE_THREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + // && !defined(ASIO_DISABLE_THREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ + && !defined(ASIO_DISABLE_THREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + // && !defined(ASIO_DISABLE_THREADS) + } + } + + ec = asio::error_code(); + return ec; +} + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +inline asio::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return asio::error_code(); + case EAI_AGAIN: + return asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return asio::error::invalid_argument; + case EAI_FAIL: + return asio::error::no_recovery; + case EAI_FAMILY: + return asio::error::address_family_not_supported; + case EAI_MEMORY: + return asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return asio::error::host_not_found; + case EAI_SERVICE: + return asio::error::service_not_found; + case EAI_SOCKTYPE: + return asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return asio::error_code( + WSAGetLastError(), asio::error::get_system_category()); +#else + return asio::error_code( + errno, asio::error::get_system_category()); +#endif + } +} + +asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec) +{ + host = (host && *host) ? host : 0; + service = (service && *service) ? service : 0; + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, &hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#endif +} + +asio::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec) +{ + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + socket_ops::getaddrinfo(host, service, hints, result, ec); + return ec; +} + +void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +asio::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, asio::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + clear_last_error(); + int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen), + host, static_cast<DWORD>(hostlen), + serv, static_cast<DWORD>(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_last_error(); + int error = gni(addr, static_cast<int>(addrlen), + host, static_cast<DWORD>(hostlen), + serv, static_cast<DWORD>(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + tmp_addr.ss_len = addrlen; + addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_last_error(); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +asio::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec) +{ + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + + return ec; +} + +asio::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec) +{ + if (cancel_token.expired()) + { + ec = asio::error::operation_aborted; + } + else + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + } + + return ec; +} + +u_long_type network_to_host_long(u_long_type value) +{ + return ntohl(value); +} + +u_long_type host_to_network_long(u_long_type value) +{ + return htonl(value); +} + +u_short_type network_to_host_short(u_short_type value) +{ + return ntohs(value); +} + +u_short_type host_to_network_short(u_short_type value) +{ + return htons(value); +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_OPS_IPP diff --git a/ext/asio/asio/detail/impl/socket_select_interrupter.ipp b/ext/asio/asio/detail/impl/socket_select_interrupter.ipp new file mode 100644 index 0000000000..181c543754 --- /dev/null +++ b/ext/asio/asio/detail/impl/socket_select_interrupter.ipp @@ -0,0 +1,151 @@ +// +// detail/impl/socket_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include <cstdlib> +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +socket_select_interrupter::socket_select_interrupter() +{ + asio::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + int opt = 1; + socket_ops::state_type acceptor_state = 0; + socket_ops::setsockopt(acceptor.get(), acceptor_state, + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + // Some broken firewalls on Windows will intermittently cause getsockname to + // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We + // explicitly specify the target address here to work around this problem. + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + ioctl_arg_type non_blocking = 1; + socket_ops::state_type client_state = 0; + if (socket_ops::ioctl(client.get(), client_state, + FIONBIO, &non_blocking, ec)) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(client.get(), client_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + socket_ops::state_type server_state = 0; + if (socket_ops::ioctl(server.get(), server_state, + FIONBIO, &non_blocking, ec)) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(server.get(), server_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); +} + +socket_select_interrupter::~socket_select_interrupter() +{ + asio::error_code ec; + socket_ops::state_type state = socket_ops::internal_non_blocking; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, state, true, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, state, true, ec); +} + +void socket_select_interrupter::interrupt() +{ + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + asio::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); +} + +bool socket_select_interrupter::reset() +{ + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + asio::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + return was_interrupted; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP diff --git a/ext/asio/asio/detail/impl/strand_service.hpp b/ext/asio/asio/detail/impl/strand_service.hpp new file mode 100644 index 0000000000..81f438a988 --- /dev/null +++ b/ext/asio/asio/detail/impl/strand_service.hpp @@ -0,0 +1,140 @@ +// +// detail/impl/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP +#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/call_stack.hpp" +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +inline strand_service::strand_impl::strand_impl() + : operation(&strand_service::do_complete), + count_(0) +{ +} + +struct strand_service::on_dispatch_exit +{ + io_service_impl* io_service_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + io_service_->post_immediate_completion(impl_); + } +}; + +inline void strand_service::destroy(strand_service::implementation_type& impl) +{ + impl = 0; +} + +template <typename Handler> +void strand_service::dispatch(strand_service::implementation_type& impl, + Handler handler) +{ + // If we are already in the strand then the handler can run immediately. + if (call_stack<strand_impl>::contains(impl)) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + // If we are running inside the io_service, and no other handler is queued + // or running, then the handler can run immediately. + bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_); + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + if (can_dispatch && first) + { + // Immediate invocation is allowed. + impl->mutex_.unlock(); + + // Memory must be releaesed before any upcall is made. + p.reset(); + + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_service_, impl }; + (void)on_exit; + + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Immediate invocation is not allowed, so enqueue for later. + impl->queue_.push(p.p); + impl->mutex_.unlock(); + p.v = p.p = 0; + + // The first handler to be enqueued is responsible for scheduling the + // strand. + if (first) + io_service_.post_immediate_completion(impl); +} + +// Request the io_service to invoke the given handler and return immediately. +template <typename Handler> +void strand_service::post(strand_service::implementation_type& impl, + Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + // Add the handler to the queue. + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + impl->queue_.push(p.p); + impl->mutex_.unlock(); + p.v = p.p = 0; + + // The first handler to be enqueue is responsible for scheduling the strand. + if (first) + io_service_.post_immediate_completion(impl); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP diff --git a/ext/asio/asio/detail/impl/strand_service.ipp b/ext/asio/asio/detail/impl/strand_service.ipp new file mode 100644 index 0000000000..84b806a553 --- /dev/null +++ b/ext/asio/asio/detail/impl/strand_service.ipp @@ -0,0 +1,106 @@ +// +// detail/impl/strand_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP +#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/call_stack.hpp" +#include "asio/detail/strand_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct strand_service::on_do_complete_exit +{ + io_service_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_); + } +}; + +strand_service::strand_service(asio::io_service& io_service) + : asio::detail::service_base<strand_service>(io_service), + io_service_(asio::use_service<io_service_impl>(io_service)), + mutex_(), + salt_(0) +{ +} + +void strand_service::shutdown_service() +{ + op_queue<operation> ops; + + asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + if (strand_impl* impl = implementations_[i].get()) + ops.push(impl->queue_); +} + +void strand_service::construct(strand_service::implementation_type& impl) +{ + std::size_t salt = salt_++; + std::size_t index = reinterpret_cast<std::size_t>(&impl); + index += (reinterpret_cast<std::size_t>(&impl) >> 3); + index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); + index = index % num_implementations; + + asio::detail::mutex::scoped_lock lock(mutex_); + + if (!implementations_[index]) + implementations_[index].reset(new strand_impl); + impl = implementations_[index].get(); +} + +void strand_service::do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + strand_impl* impl = static_cast<strand_impl*>(base); + + // Get the next handler to be executed. + impl->mutex_.lock(); + operation* o = impl->queue_.front(); + impl->queue_.pop(); + impl->mutex_.unlock(); + + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_do_complete_exit on_exit = { owner, impl }; + (void)on_exit; + + o->complete(*owner); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/task_io_service.hpp b/ext/asio/asio/detail/impl/task_io_service.hpp new file mode 100644 index 0000000000..20ffd61c06 --- /dev/null +++ b/ext/asio/asio/detail/impl/task_io_service.hpp @@ -0,0 +1,60 @@ +// +// detail/impl/task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP +#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/call_stack.hpp" +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +void task_io_service::dispatch(Handler handler) +{ + if (call_stack<task_io_service>::contains(this)) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler); + } + else + post(handler); +} + +template <typename Handler> +void task_io_service::post(Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + post_immediate_completion(p.p); + p.v = p.p = 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP diff --git a/ext/asio/asio/detail/impl/task_io_service.ipp b/ext/asio/asio/detail/impl/task_io_service.ipp new file mode 100644 index 0000000000..12a22be8cc --- /dev/null +++ b/ext/asio/asio/detail/impl/task_io_service.ipp @@ -0,0 +1,354 @@ +// +// detail/impl/task_io_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP +#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) + +#include <boost/limits.hpp> +#include "asio/detail/call_stack.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/task_io_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct task_io_service::task_cleanup +{ + ~task_cleanup() + { + // Enqueue the completed operations and reinsert the task at the end of + // the operation queue. + lock_->lock(); + task_io_service_->task_interrupted_ = true; + task_io_service_->op_queue_.push(*ops_); + task_io_service_->op_queue_.push(&task_io_service_->task_operation_); + } + + task_io_service* task_io_service_; + mutex::scoped_lock* lock_; + op_queue<operation>* ops_; +}; + +struct task_io_service::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + task_io_service_->work_finished(); + } + + task_io_service* task_io_service_; +}; + +struct task_io_service::idle_thread_info +{ + event wakeup_event; + idle_thread_info* next; +}; + +task_io_service::task_io_service(asio::io_service& io_service) + : asio::detail::service_base<task_io_service>(io_service), + mutex_(), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + first_idle_thread_(0) +{ +} + +void task_io_service::init(std::size_t /*concurrency_hint*/) +{ +} + +void task_io_service::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + // Destroy handler objects. + while (!op_queue_.empty()) + { + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); + } + + // Reset to initial state. + task_ = 0; +} + +void task_io_service::init_task() +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service<reactor>(this->get_io_service()); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t task_io_service::run(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack<task_io_service>::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_one(lock, &this_idle_thread); lock.lock()) + if (n != (std::numeric_limits<std::size_t>::max)()) + ++n; + return n; +} + +std::size_t task_io_service::run_one(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack<task_io_service>::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + mutex::scoped_lock lock(mutex_); + + return do_one(lock, &this_idle_thread); +} + +std::size_t task_io_service::poll(asio::error_code& ec) +{ + if (outstanding_work_ == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + call_stack<task_io_service>::context ctx(this); + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_one(lock, 0); lock.lock()) + if (n != (std::numeric_limits<std::size_t>::max)()) + ++n; + return n; +} + +std::size_t task_io_service::poll_one(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack<task_io_service>::context ctx(this); + + mutex::scoped_lock lock(mutex_); + + return do_one(lock, 0); +} + +void task_io_service::stop() +{ + mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); +} + +void task_io_service::reset() +{ + mutex::scoped_lock lock(mutex_); + stopped_ = false; +} + +void task_io_service::post_immediate_completion(task_io_service::operation* op) +{ + work_started(); + post_deferred_completion(op); +} + +void task_io_service::post_deferred_completion(task_io_service::operation* op) +{ + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void task_io_service::post_deferred_completions( + op_queue<task_io_service::operation>& ops) +{ + if (!ops.empty()) + { + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t task_io_service::do_one(mutex::scoped_lock& lock, + task_io_service::idle_thread_info* this_idle_thread) +{ + bool polling = !this_idle_thread; + bool task_has_run = false; + while (!stopped_) + { + if (!op_queue_.empty()) + { + // Prepare to execute first handler from queue. + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + if (o == &task_operation_) + { + task_interrupted_ = more_handlers || polling; + + // If the task has already run and we're polling then we're done. + if (task_has_run && polling) + { + task_interrupted_ = true; + op_queue_.push(&task_operation_); + return 0; + } + task_has_run = true; + + if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) + lock.unlock(); + + op_queue<operation> completed_ops; + task_cleanup c = { this, &lock, &completed_ops }; + (void)c; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(!more_handlers && !polling, completed_ops); + } + else + { + if (more_handlers) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + // Complete the operation. May throw an exception. + o->complete(*this); // deletes the operation object + + return 1; + } + } + else if (this_idle_thread) + { + // Nothing to run right now, so just wait for work to do. + this_idle_thread->next = first_idle_thread_; + first_idle_thread_ = this_idle_thread; + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); + } + else + { + return 0; + } + } + + return 0; +} + +void task_io_service::stop_all_threads( + mutex::scoped_lock& lock) +{ + stopped_ = true; + + while (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); + } + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } +} + +bool task_io_service::wake_one_idle_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal_and_unlock(lock); + return true; + } + return false; +} + +void task_io_service::wake_one_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (!wake_one_idle_thread_and_unlock(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/throw_error.ipp b/ext/asio/asio/detail/impl/throw_error.ipp new file mode 100644 index 0000000000..913df7c619 --- /dev/null +++ b/ext/asio/asio/detail/impl/throw_error.ipp @@ -0,0 +1,45 @@ +// +// detail/impl/throw_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_THROW_ERROR_IPP +#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/throw_exception.hpp> +#include "asio/detail/throw_error.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void do_throw_error(const asio::error_code& err) +{ + asio::system_error e(err); + boost::throw_exception(e); +} + +void do_throw_error(const asio::error_code& err, const char* location) +{ + asio::system_error e(err, location); + boost::throw_exception(e); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP diff --git a/ext/asio/asio/detail/impl/timer_queue.ipp b/ext/asio/asio/detail/impl/timer_queue.ipp new file mode 100644 index 0000000000..63fbd7e90a --- /dev/null +++ b/ext/asio/asio/detail/impl/timer_queue.ipp @@ -0,0 +1,85 @@ +// +// detail/impl/timer_queue.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP +#define ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HEADER_ONLY) + +#include "asio/detail/timer_queue.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue() +{ +} + +timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue() +{ +} + +bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer( + const time_type& time, per_timer_data& timer, timer_op* op) +{ + return impl_.enqueue_timer(time, timer, op); +} + +bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const +{ + return impl_.empty(); +} + +long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec( + long max_duration) const +{ + return impl_.wait_duration_msec(max_duration); +} + +long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec( + long max_duration) const +{ + return impl_.wait_duration_usec(max_duration); +} + +void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers( + op_queue<operation>& ops) +{ + impl_.get_ready_timers(ops); +} + +void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers( + op_queue<operation>& ops) +{ + impl_.get_all_timers(ops); +} + +std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer( + per_timer_data& timer, op_queue<operation>& ops) +{ + return impl_.cancel_timer(timer, ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP diff --git a/ext/asio/asio/detail/impl/timer_queue_set.ipp b/ext/asio/asio/detail/impl/timer_queue_set.ipp new file mode 100644 index 0000000000..81ab5a9a3c --- /dev/null +++ b/ext/asio/asio/detail/impl/timer_queue_set.ipp @@ -0,0 +1,101 @@ +// +// detail/impl/timer_queue_set.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP +#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_queue_set.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +timer_queue_set::timer_queue_set() + : first_(0) +{ +} + +void timer_queue_set::insert(timer_queue_base* q) +{ + q->next_ = first_; + first_ = q; +} + +void timer_queue_set::erase(timer_queue_base* q) +{ + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } +} + +bool timer_queue_set::all_empty() const +{ + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; +} + +long timer_queue_set::wait_duration_msec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; +} + +long timer_queue_set::wait_duration_usec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; +} + +void timer_queue_set::get_ready_timers(op_queue<operation>& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); +} + +void timer_queue_set::get_all_timers(op_queue<operation>& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP diff --git a/ext/asio/asio/detail/impl/win_event.ipp b/ext/asio/asio/detail/impl/win_event.ipp new file mode 100644 index 0000000000..2b72f6ecda --- /dev/null +++ b/ext/asio/asio/detail/impl/win_event.ipp @@ -0,0 +1,50 @@ +// +// detail/win_event.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_EVENT_IPP +#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_event.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_event::win_event() + : event_(::CreateEvent(0, true, false, 0)) +{ + if (!event_) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP diff --git a/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp b/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp new file mode 100644 index 0000000000..3b30b1d5df --- /dev/null +++ b/ext/asio/asio/detail/impl/win_iocp_handle_service.ipp @@ -0,0 +1,452 @@ +// +// detail/impl/win_iocp_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/win_iocp_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_handle_service::overlapped_wrapper + : public OVERLAPPED +{ +public: + explicit overlapped_wrapper(asio::error_code& ec) + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + + // Create a non-signalled manual-reset event, for GetOverlappedResult. + hEvent = ::CreateEvent(0, TRUE, FALSE, 0); + if (hEvent) + { + // As documented in GetQueuedCompletionStatus, setting the low order + // bit of this event prevents our synchronous writes from being treated + // as completion port events. + *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1; + } + else + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + + ~overlapped_wrapper() + { + if (hEvent) + { + ::CloseHandle(hEvent); + } + } +}; + +win_iocp_handle_service::win_iocp_handle_service( + asio::io_service& io_service) + : iocp_service_(asio::use_service<win_iocp_io_service>(io_service)), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_handle_service::shutdown_service() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_handle_service::construct( + win_iocp_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::destroy( + win_iocp_handle_service::implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code win_iocp_handle_service::assign( + win_iocp_handle_service::implementation_type& impl, + const native_type& native_handle, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(native_handle, ec)) + return ec; + + impl.handle_ = native_handle; + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_handle_service::close( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_handle_service::cancel( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + } + else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + if (!cancel_io_ex(impl.handle_, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = asio::error_code(); + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + else + { + ec = asio::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = asio::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + if (!::CancelIo(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = asio::error::operation_not_supported; + } + + return ec; +} + +size_t win_iocp_handle_service::do_write( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const asio::const_buffer& buffer, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a handle is a no-op. + if (asio::buffer_size(buffer) == 0) + { + ec = asio::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Write the data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + asio::buffer_cast<LPCVOID>(buffer), + static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING) + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + ec = asio::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_write_op( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const asio::const_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, asio::error::bad_descriptor); + } + else if (asio::buffer_size(buffer) == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + asio::buffer_cast<LPCVOID>(buffer), + static_cast<DWORD>(asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +size_t win_iocp_handle_service::do_read( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const asio::mutable_buffer& buffer, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream handle is a no-op. + if (asio::buffer_size(buffer) == 0) + { + ec = asio::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Read some data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + asio::buffer_cast<LPVOID>(buffer), + static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) + { + if (last_error == ERROR_HANDLE_EOF) + { + ec = asio::error::eof; + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_HANDLE_EOF) + { + ec = asio::error::eof; + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + return 0; + } + + ec = asio::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_read_op( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const asio::mutable_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, asio::error::bad_descriptor); + } + else if (asio::buffer_size(buffer) == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + asio::buffer_cast<LPVOID>(buffer), + static_cast<DWORD>(asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_handle_service::update_cancellation_thread_id( + win_iocp_handle_service::implementation_type& impl) +{ + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +} + +void win_iocp_handle_service::close_for_destruction(implementation_type& impl) +{ + if (is_open(impl)) + { + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/win_iocp_io_service.hpp b/ext/asio/asio/detail/impl/win_iocp_io_service.hpp new file mode 100644 index 0000000000..ab235471e8 --- /dev/null +++ b/ext/asio/asio/detail/impl/win_iocp_io_service.hpp @@ -0,0 +1,115 @@ +// +// detail/impl/win_iocp_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/call_stack.hpp" +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +void win_iocp_io_service::dispatch(Handler handler) +{ + if (call_stack<win_iocp_io_service>::contains(this)) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler); + } + else + post(handler); +} + +template <typename Handler> +void win_iocp_io_service::post(Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + post_immediate_completion(p.p); + p.v = p.p = 0; +} + +template <typename Time_Traits> +void win_iocp_io_service::add_timer_queue( + timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void win_iocp_io_service::remove_timer_queue( + timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op) +{ + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + { + post_immediate_completion(op); + return; + } + + mutex::scoped_lock lock(dispatch_mutex_); + + bool earliest = queue.enqueue_timer(time, timer, op); + work_started(); + if (earliest) + update_timeout(); +} + +template <typename Time_Traits> +std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue<win_iocp_operation> ops; + std::size_t n = queue.cancel_timer(timer, ops); + post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP diff --git a/ext/asio/asio/detail/impl/win_iocp_io_service.ipp b/ext/asio/asio/detail/impl/win_iocp_io_service.ipp new file mode 100644 index 0000000000..890e32f534 --- /dev/null +++ b/ext/asio/asio/detail/impl/win_iocp_io_service.ipp @@ -0,0 +1,496 @@ +// +// detail/impl/win_iocp_io_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/limits.hpp> +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_iocp_io_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_iocp_io_service::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + io_service_->work_finished(); + } + + win_iocp_io_service* io_service_; +}; + +struct win_iocp_io_service::timer_thread_function +{ + void operator()() + { + while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0) + { + if (::WaitForSingleObject(io_service_->waitable_timer_.handle, + INFINITE) == WAIT_OBJECT_0) + { + ::InterlockedExchange(&io_service_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_service_->iocp_.handle, + 0, wake_for_dispatch, 0); + } + } + } + + win_iocp_io_service* io_service_; +}; + +win_iocp_io_service::win_iocp_io_service(asio::io_service& io_service) + : asio::detail::service_base<win_iocp_io_service>(io_service), + iocp_(), + outstanding_work_(0), + stopped_(0), + shutdown_(0), + dispatch_required_(0) +{ +} + +void win_iocp_io_service::init(size_t concurrency_hint) +{ + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0)))); + if (!iocp_.handle) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "iocp"); + } +} + +void win_iocp_io_service::shutdown_service() +{ + ::InterlockedExchange(&shutdown_, 1); + + if (timer_thread_) + { + LARGE_INTEGER timeout; + timeout.QuadPart = 1; + ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); + } + + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) + { + op_queue<win_iocp_operation> ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, gqcs_timeout); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast<win_iocp_operation*>(overlapped)->destroy(); + } + } + } + + if (timer_thread_) + timer_thread_->join(); +} + +asio::error_code win_iocp_io_service::register_handle( + HANDLE handle, asio::error_code& ec) +{ + if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + return ec; +} + +size_t win_iocp_io_service::run(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + call_stack<win_iocp_io_service>::context ctx(this); + + size_t n = 0; + while (do_one(true, ec)) + if (n != (std::numeric_limits<size_t>::max)()) + ++n; + return n; +} + +size_t win_iocp_io_service::run_one(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + call_stack<win_iocp_io_service>::context ctx(this); + + return do_one(true, ec); +} + +size_t win_iocp_io_service::poll(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + call_stack<win_iocp_io_service>::context ctx(this); + + size_t n = 0; + while (do_one(false, ec)) + if (n != (std::numeric_limits<size_t>::max)()) + ++n; + return n; +} + +size_t win_iocp_io_service::poll_one(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + call_stack<win_iocp_io_service>::context ctx(this); + + return do_one(false, ec); +} + +void win_iocp_io_service::stop() +{ + if (::InterlockedExchange(&stopped_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "pqcs"); + } + } +} + +void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op) +{ + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_service::post_deferred_completions( + op_queue<win_iocp_operation>& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_service::on_pending(win_iocp_operation* op) +{ + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_service::on_completion(win_iocp_operation* op, + DWORD last_error, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = asio::error::get_system_category(); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_service::on_completion(win_iocp_operation* op, + const asio::error_code& ec, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = ec.category(); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +size_t win_iocp_io_service::do_one(bool block, asio::error_code& ec) +{ + for (;;) + { + // Try to acquire responsibility for dispatching timers and completed ops. + if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) + { + mutex::scoped_lock lock(dispatch_mutex_); + + // Dispatch pending timers and operations. + op_queue<win_iocp_operation> ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); + update_timeout(); + } + + // Get the next operation from the queue. + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::SetLastError(0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, block ? gqcs_timeout : 0); + DWORD last_error = ::GetLastError(); + + if (overlapped) + { + win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped); + asio::error_code result_ec(last_error, + asio::error::get_system_category()); + + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = asio::error_code(static_cast<int>(op->Offset), + static_cast<asio::error_category>(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = result_ec.category(); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(*this, result_ec, bytes_transferred); + ec = asio::error_code(); + return 1; + } + } + else if (!ok) + { + if (last_error != WAIT_TIMEOUT) + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + // If we're not polling we need to keep going until we get a real handler. + if (block) + continue; + + ec = asio::error_code(); + return 0; + } + else if (completion_key == wake_for_dispatch) + { + // We have been woken up to try to acquire responsibility for dispatching + // timers and completed operations. + } + else + { + // The stopped_ flag is always checked to ensure that any leftover + // interrupts from a previous run invocation are ignored. + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) + { + // Wake up next thread that is blocked on GetQueuedCompletionStatus. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + ec = asio::error_code(); + return 0; + } + } + } +} + +void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.insert(&queue); + + if (!waitable_timer_.handle) + { + waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); + if (waitable_timer_.handle == 0) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "timer"); + } + + LARGE_INTEGER timeout; + timeout.QuadPart = -max_timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + + if (!timer_thread_) + { + timer_thread_function thread_function = { this }; + timer_thread_.reset(new thread(thread_function, 65536)); + } +} + +void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.erase(&queue); +} + +void win_iocp_io_service::update_timeout() +{ + if (timer_thread_) + { + // There's no point updating the waitable timer if the new timeout period + // exceeds the maximum timeout. In that case, we might as well wait for the + // existing period of the timer to expire. + long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); + if (timeout_usec < max_timeout_usec) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp b/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp new file mode 100644 index 0000000000..763151434c --- /dev/null +++ b/ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -0,0 +1,180 @@ +// +// detail/impl/win_iocp_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#include <cstring> +#include "asio/detail/win_iocp_serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_serial_port_service::win_iocp_serial_port_service( + asio::io_service& io_service) + : handle_service_(io_service) +{ +} + +void win_iocp_serial_port_service::shutdown_service() +{ +} + +asio::error_code win_iocp_serial_port_service::open( + win_iocp_serial_port_service::implementation_type& impl, + const std::string& device, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + // For convenience, add a leading \\.\ sequence if not already present. + std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; + + // Open a handle to the serial port. + ::HANDLE handle = ::CreateFileA(name.c_str(), + GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (handle == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Determine the initial serial port parameters. + using namespace std; // For memset. + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Set some default serial port parameters. This implementation does not + // support changing these, so they might as well be in a known state. + dcb.fBinary = TRUE; // Win32 only supports binary mode. + dcb.fDsrSensitivity = FALSE; + dcb.fNull = FALSE; // Do not ignore NULL characters. + dcb.fAbortOnError = FALSE; // Ignore serial framing errors. + if (!::SetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Set up timeouts so that the serial port will behave similarly to a + // network socket. Reads wait for at least one byte, then return with + // whatever they have. Writes return once everything is out the door. + ::COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + if (!::SetCommTimeouts(handle, &timeouts)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // We're done. Take ownership of the serial port handle. + if (handle_service_.assign(impl, handle, ec)) + ::CloseHandle(handle); + return ec; +} + +asio::error_code win_iocp_serial_port_service::do_set_option( + win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::store_function_type store, + const void* option, asio::error_code& ec) +{ + using namespace std; // For memcpy. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + if (store(option, dcb, ec)) + return ec; + + if (!::SetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_serial_port_service::do_get_option( + const win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::load_function_type load, + void* option, asio::error_code& ec) const +{ + using namespace std; // For memset. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + return load(option, dcb, ec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP diff --git a/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp b/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp new file mode 100644 index 0000000000..37c6f63379 --- /dev/null +++ b/ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -0,0 +1,575 @@ +// +// detail/impl/win_iocp_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/win_iocp_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_socket_service_base::win_iocp_socket_service_base( + asio::io_service& io_service) + : io_service_(io_service), + iocp_service_(use_service<win_iocp_io_service>(io_service)), + reactor_(0), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_socket_service_base::shutdown_service() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + asio::error_code ignored_ec; + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_socket_service_base::construct( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::destroy( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code win_iocp_socket_service_base::close( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + reactor* r = static_cast<reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); + } + + if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0) + { + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + } + + return ec; +} + +asio::error_code win_iocp_socket_service_base::cancel( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); + if (!cancel_io_ex(sock_as_handle, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = asio::error_code(); + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + else + { + ec = asio::error_code(); + } + } +#if defined(ASIO_ENABLE_CANCELIO) + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = asio::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); + if (!::CancelIo(sock_as_handle)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = asio::error::operation_not_supported; + } +#else // defined(ASIO_ENABLE_CANCELIO) + else + { + // Cancellation is not supported as CancelIo may not be used. + ec = asio::error::operation_not_supported; + } +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Cancel any operations started via the reactor. + if (!ec) + { + reactor* r = static_cast<reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (r) + r->cancel_ops(impl.socket_, impl.reactor_data_); + } + + return ec; +} + +asio::error_code win_iocp_socket_service_base::do_open( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(family, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get()); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter()); + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_socket_service_base::do_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + int type, socket_type native_socket, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter()); + ec = asio::error_code(); + return ec; +} + +void win_iocp_socket_service_base::start_send_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_send_to_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, + static_cast<DWORD>(buffer_count), + &bytes_transferred, flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, + static_cast<DWORD>(buffer_count), + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_null_buffers_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op) +{ + if ((impl.state_ & socket_ops::stream_oriented) != 0) + { + // For stream sockets on Windows, we may issue a 0-byte overlapped + // WSARecv to wait until there is data available on the socket. + ::WSABUF buf = { 0, 0 }; + start_receive_op(impl, &buf, 1, flags, false, op); + } + else + { + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + op); + } +} + +void win_iocp_socket_service_base::start_receive_from_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + static_cast<DWORD>(buffer_count), + &bytes_transferred, &recv_flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_accept_op( + win_iocp_socket_service_base::base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, asio::error::already_open); + else + { + asio::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_socket_service_base::restart_accept_op( + socket_type s, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + new_socket.reset(); + iocp_service_.work_started(); + + asio::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_reactor_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op) +{ + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); + return; + } + else + op->ec_ = asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); +} + +void win_iocp_socket_service_base::start_connect_op( + win_iocp_socket_service_base::base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, std::size_t addrlen) +{ + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if ((impl.state_ & socket_ops::non_blocking) != 0 + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == asio::error::in_progress + || op->ec_ == asio::error::would_block) + { + op->ec_ = asio::error_code(); + r.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, false); + return; + } + } + } + + r.post_immediate_completion(op); +} + +void win_iocp_socket_service_base::close_for_destruction( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + if (is_open(impl)) + { + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + reactor* r = static_cast<reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); + } + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) +} + +void win_iocp_socket_service_base::update_cancellation_thread_id( + win_iocp_socket_service_base::base_implementation_type& impl) +{ +#if defined(ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(ASIO_ENABLE_CANCELIO) +} + +reactor& win_iocp_socket_service_base::get_reactor() +{ + reactor* r = static_cast<reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service<reactor>(io_service_)); + interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); + } + return *r; +} + +void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast<void*>(InterlockedCompareExchange( + reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch), + reinterpret_cast<LONG>(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_socket_service_base::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast<void*>(InterlockedExchange( + reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP diff --git a/ext/asio/asio/detail/impl/win_mutex.ipp b/ext/asio/asio/detail/impl/win_mutex.ipp new file mode 100644 index 0000000000..910cc23372 --- /dev/null +++ b/ext/asio/asio/detail/impl/win_mutex.ipp @@ -0,0 +1,78 @@ +// +// detail/impl/win_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_MUTEX_IPP +#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_mutex.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_mutex::win_mutex() +{ + int error = do_init(); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "mutex"); +} + +int win_mutex::do_init() +{ +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + return 0; +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + return ERROR_OUTOFMEMORY; + } + + return 0; +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP diff --git a/ext/asio/asio/detail/impl/win_thread.ipp b/ext/asio/asio/detail/impl/win_thread.ipp new file mode 100644 index 0000000000..65844c8866 --- /dev/null +++ b/ext/asio/asio/detail/impl/win_thread.ipp @@ -0,0 +1,138 @@ +// +// detail/impl/win_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_THREAD_IPP +#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#include <process.h> +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_thread.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_thread::~win_thread() +{ + ::CloseHandle(thread_); + + // The exit_event_ handle is deliberately allowed to leak here since it + // is an error for the owner of an internal thread not to join() it. +} + +void win_thread::join() +{ + HANDLE handles[2] = { exit_event_, thread_ }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) + { + ::TerminateThread(thread_, 0); + } + else + { + ::QueueUserAPC(apc_function, thread_, 0); + ::WaitForSingleObject(thread_, INFINITE); + } +} + +void win_thread::start_thread(func_base* arg, unsigned int stack_size) +{ + ::HANDLE entry_event = 0; + arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); + if (!entry_event) + { + DWORD last_error = ::GetLastError(); + delete arg; + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread.entry_event"); + } + + arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + delete arg; + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread.exit_event"); + } + + unsigned int thread_id = 0; + thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, + stack_size, win_thread_function, arg, 0, &thread_id)); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + delete arg; + if (entry_event) + ::CloseHandle(entry_event); + if (exit_event_) + ::CloseHandle(exit_event_); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + + if (entry_event) + { + ::WaitForSingleObject(entry_event, INFINITE); + ::CloseHandle(entry_event); + } +} + +unsigned int __stdcall win_thread_function(void* arg) +{ + std::auto_ptr<win_thread::func_base> func( + static_cast<win_thread::func_base*>(arg)); + + ::SetEvent(func->entry_event_); + + func->run(); + + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func->exit_event_; + func.reset(); + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); + + return 0; +} + +#if defined(WINVER) && (WINVER < 0x0500) +void __stdcall apc_function(ULONG) {} +#else +void __stdcall apc_function(ULONG_PTR) {} +#endif + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP diff --git a/ext/asio/asio/detail/impl/win_tss_ptr.ipp b/ext/asio/asio/detail/impl/win_tss_ptr.ipp new file mode 100644 index 0000000000..de3ea3c7e0 --- /dev/null +++ b/ext/asio/asio/detail/impl/win_tss_ptr.ipp @@ -0,0 +1,57 @@ +// +// detail/impl/win_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP +#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_tss_ptr.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD win_tss_ptr_create() +{ +#if defined(UNDER_CE) + enum { out_of_indexes = 0xFFFFFFFF }; +#else + enum { out_of_indexes = TLS_OUT_OF_INDEXES }; +#endif + + DWORD tss_key = ::TlsAlloc(); + if (tss_key == out_of_indexes) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "tss"); + } + return tss_key; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP diff --git a/ext/asio/asio/detail/impl/winsock_init.ipp b/ext/asio/asio/detail/impl/winsock_init.ipp new file mode 100644 index 0000000000..3b20c98e27 --- /dev/null +++ b/ext/asio/asio/detail/impl/winsock_init.ipp @@ -0,0 +1,69 @@ +// +// detail/impl/winsock_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP +#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void winsock_init_base::startup(data& d, + unsigned char major, unsigned char minor) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + WSADATA wsa_data; + long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); + ::InterlockedExchange(&d.result_, result); + } +} + +void winsock_init_base::cleanup(data& d) +{ + if (::InterlockedDecrement(&d.init_count_) == 0) + { + ::WSACleanup(); + } +} + +void winsock_init_base::throw_on_error(data& d) +{ + long result = ::InterlockedExchangeAdd(&d.result_, 0); + if (result != 0) + { + asio::error_code ec(result, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "winsock"); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP diff --git a/ext/asio/asio/detail/io_control.hpp b/ext/asio/asio/detail/io_control.hpp index df7171cbe2..b3ef844958 100644 --- a/ext/asio/asio/detail/io_control.hpp +++ b/ext/asio/asio/detail/io_control.hpp @@ -1,8 +1,8 @@ // -// io_control.hpp -// ~~~~~~~~~~~~~~ +// detail/io_control.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { namespace io_control { diff --git a/ext/asio/asio/detail/kqueue_reactor.hpp b/ext/asio/asio/detail/kqueue_reactor.hpp index bfa004d0da..07087ddd6e 100644 --- a/ext/asio/asio/detail/kqueue_reactor.hpp +++ b/ext/asio/asio/detail/kqueue_reactor.hpp @@ -1,8 +1,8 @@ // -// kqueue_reactor.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,41 +16,35 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/kqueue_reactor_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_KQUEUE) -#include "asio/detail/push_options.hpp" #include <cstddef> #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/io_service.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/hash_map.hpp" +#include "asio/detail/kqueue_reactor_fwd.hpp" #include "asio/detail/mutex.hpp" +#include "asio/detail/object_pool.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/select_interrupter.hpp" -#include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" +#include "asio/error.hpp" +#include "asio/io_service.hpp" // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) # define EV_OOBAND EV_FLAG1 #endif // !defined(EV_OOBAND) +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -64,384 +58,98 @@ public: // Per-descriptor queues. struct descriptor_state { - descriptor_state() {} - descriptor_state(const descriptor_state&) {} - void operator=(const descriptor_state&) {} - + friend class kqueue_reactor; + friend class object_pool_access; mutex mutex_; op_queue<reactor_op> op_queue_[max_ops]; bool shutdown_; + descriptor_state* next_; + descriptor_state* prev_; }; // Per-descriptor data. typedef descriptor_state* per_descriptor_data; // Constructor. - kqueue_reactor(asio::io_service& io_service) - : asio::detail::service_base<kqueue_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), - mutex_(), - kqueue_fd_(do_kqueue_create()), - interrupter_(), - shutdown_(false) - { - // The interrupter is put into a permanently readable state. Whenever we - // want to interrupt the blocked kevent call we register a one-shot read - // operation against the descriptor. - interrupter_.interrupt(); - } + ASIO_DECL kqueue_reactor(asio::io_service& io_service); // Destructor. - ~kqueue_reactor() - { - close(kqueue_fd_); - } + ASIO_DECL ~kqueue_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue<operation> ops; - - descriptor_map::iterator iter = registered_descriptors_.begin(); - descriptor_map::iterator end = registered_descriptors_.end(); - while (iter != end) - { - for (int i = 0; i < max_ops; ++i) - ops.push(iter->second.op_queue_[i]); - iter->second.shutdown_ = true; - ++iter; - } - - timer_queues_.get_all_timers(ops); - } + ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock lock(registered_descriptors_mutex_); - - descriptor_map::iterator new_entry = registered_descriptors_.insert( - std::make_pair(descriptor, descriptor_state())).first; - descriptor_data = &new_entry->second; + ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); - descriptor_data->shutdown_ = false; - - return 0; + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) + { + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, + ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - reactor_op* op, bool allow_speculative) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (descriptor_data->shutdown_) - return; - - bool first = descriptor_data->op_queue_[op_type].empty(); - if (first) - { - if (allow_speculative) - { - if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) - { - if (op->perform()) - { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - } - } - - descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); - - if (first) - { - struct kevent event; - switch (op_type) - { - case read_op: - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - break; - case write_op: - EV_SET(&event, descriptor, EVFILT_WRITE, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - break; - case except_op: - if (!descriptor_data->op_queue_[read_op].empty()) - return; // Already registered for read events. - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); - break; - } - - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - op->ec_ = asio::error_code(errno, - asio::error::get_system_category()); - descriptor_data->op_queue_[op_type].pop(); - io_service_.post_deferred_completion(op); - } - } - } + reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type , per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - op_queue<operation> ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - - // Remove the descriptor from the set of known descriptors. The descriptor - // will be automatically removed from the kqueue set when it is closed. - descriptor_data->shutdown_ = true; - - op_queue<operation> ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - registered_descriptors_.erase(descriptor); - - descriptors_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template <typename Time_Traits> - void add_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> - void remove_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> - void schedule_timer(timer_queue<Time_Traits>& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupt(); - } - } + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template <typename Time_Traits> - std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token) - { - mutex::scoped_lock lock(mutex_); - op_queue<operation> ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer); // Run the kqueue loop. - void run(bool block, op_queue<operation>& ops) - { - mutex::scoped_lock lock(mutex_); - - // Determine how long to block while waiting for events. - timespec timeout_buf = { 0, 0 }; - timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; - - lock.unlock(); - - // Block on the kqueue descriptor. - struct kevent events[128]; - int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - int descriptor = events[i].ident; - void* ptr = events[i].udata; - if (ptr == &interrupter_) - { - // No need to reset the interrupter since we're leaving the descriptor - // in a ready-to-read state and relying on one-shot notifications. - } - else - { - descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - static const int filter[max_ops] = - { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; - for (int j = max_ops - 1; j >= 0; --j) - { - if (events[i].filter == filter[j]) - { - if (j != except_op || events[i].flags & EV_OOBAND) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - if (events[i].flags & EV_ERROR) - { - op->ec_ = asio::error_code(events[i].data, - asio::error::get_system_category()); - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - if (op->perform()) - { - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - else - break; - } - } - } - } - - // Renew registration for event notifications. - struct kevent event; - switch (events[i].filter) - { - case EVFILT_READ: - if (!descriptor_data->op_queue_[read_op].empty()) - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - else if (!descriptor_data->op_queue_[except_op].empty()) - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); - else - continue; - case EVFILT_WRITE: - if (!descriptor_data->op_queue_[write_op].empty()) - EV_SET(&event, descriptor, EVFILT_WRITE, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - else - continue; - default: - break; - } - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - asio::error_code error(errno, - asio::error::get_system_category()); - for (int j = 0; j < max_ops; ++j) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - op->ec_ = error; - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - } - } - } - } - - lock.lock(); - timer_queues_.get_ready_timers(ops); - } + ASIO_DECL void run(bool block, op_queue<operation>& ops); // Interrupt the kqueue loop. - void interrupt() - { - struct kevent event; - EV_SET(&event, interrupter_.read_descriptor(), - EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); - ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); - } + ASIO_DECL void interrupt(); private: // Create the kqueue file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_kqueue_create() - { - int fd = kqueue(); - if (fd == -1) - { - boost::throw_exception( - asio::system_error( - asio::error_code(errno, - asio::error::get_system_category()), - "kqueue")); - } - return fd; - } + ASIO_DECL static int do_kqueue_create(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the kevent call. - timespec* get_timeout(timespec& ts) - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - ts.tv_sec = usec / 1000000; - ts.tv_nsec = (usec % 1000000) * 1000; - return &ts; - } + ASIO_DECL timespec* get_timeout(timespec& ts); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -464,22 +172,20 @@ private: // Mutex to protect access to the registered descriptors. mutex registered_descriptors_mutex_; - // Keep track of all registered descriptors. This code relies on the fact that - // the hash_map implementation pools deleted nodes, meaning that we can assume - // our descriptor_state pointer remains valid even after the entry is removed. - // Technically this is not true for C++98, as that standard says that spliced - // elements in a list are invalidated. However, C++0x fixes this shortcoming - // so we'll just assume that C++98 std::list implementations will do the right - // thing anyway. - typedef detail::hash_map<socket_type, descriptor_state> descriptor_map; - descriptor_map registered_descriptors_; + // Keep track of all registered descriptors. + object_pool<descriptor_state> registered_descriptors_; }; } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_KQUEUE) - #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/kqueue_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/kqueue_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_KQUEUE) + #endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/ext/asio/asio/detail/kqueue_reactor_fwd.hpp b/ext/asio/asio/detail/kqueue_reactor_fwd.hpp index abbc0c7d7b..fda59ce8ec 100644 --- a/ext/asio/asio/detail/kqueue_reactor_fwd.hpp +++ b/ext/asio/asio/detail/kqueue_reactor_fwd.hpp @@ -1,8 +1,8 @@ // -// kqueue_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/kqueue_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,15 +16,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#if !defined(ASIO_DISABLE_KQUEUE) - -#if (defined(__MACH__) && defined(__APPLE__)) \ - || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - -// Define this to indicate that kqueue is supported on the target platform. -#define ASIO_HAS_KQUEUE 1 +#if defined(ASIO_HAS_KQUEUE) namespace asio { namespace detail { @@ -34,11 +28,6 @@ class kqueue_reactor; } // namespace detail } // namespace asio -#endif // (defined(__MACH__) && defined(__APPLE__)) - // || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - -#endif // !defined(ASIO_DISABLE_KQUEUE) - -#include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_KQUEUE) #endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP diff --git a/ext/asio/asio/detail/local_free_on_block_exit.hpp b/ext/asio/asio/detail/local_free_on_block_exit.hpp index 554943c817..a55bd4b34d 100644 --- a/ext/asio/asio/detail/local_free_on_block_exit.hpp +++ b/ext/asio/asio/detail/local_free_on_block_exit.hpp @@ -1,8 +1,8 @@ // -// local_free_on_block_exit.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -52,8 +50,8 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/ext/asio/asio/detail/macos_fenced_block.hpp b/ext/asio/asio/detail/macos_fenced_block.hpp index 3c303d62bc..fcb8bfc61f 100644 --- a/ext/asio/asio/detail/macos_fenced_block.hpp +++ b/ext/asio/asio/detail/macos_fenced_block.hpp @@ -1,8 +1,8 @@ // -// macos_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(__MACH__) && defined(__APPLE__) -#include "asio/detail/push_options.hpp" #include <libkern/OSAtomic.h> -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -50,8 +46,8 @@ public: } // namespace detail } // namespace asio -#endif // defined(__MACH__) && defined(__APPLE__) - #include "asio/detail/pop_options.hpp" +#endif // defined(__MACH__) && defined(__APPLE__) + #endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/mutex.hpp b/ext/asio/asio/detail/mutex.hpp index 024ec7f43f..dc478ff8c3 100644 --- a/ext/asio/asio/detail/mutex.hpp +++ b/ext/asio/asio/detail/mutex.hpp @@ -1,8 +1,8 @@ // -// mutex.hpp -// ~~~~~~~~~ +// detail/mutex.hpp +// ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_mutex.hpp" @@ -45,6 +41,4 @@ typedef posix_mutex mutex; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_MUTEX_HPP diff --git a/ext/asio/asio/detail/noncopyable.hpp b/ext/asio/asio/detail/noncopyable.hpp index 8b73ff0407..e7f6437d7c 100644 --- a/ext/asio/asio/detail/noncopyable.hpp +++ b/ext/asio/asio/detail/noncopyable.hpp @@ -1,8 +1,8 @@ // -// noncopyable.hpp -// ~~~~~~~~~~~~~~~ +// detail/noncopyable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <boost/noncopyable.hpp> #include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/null_event.hpp b/ext/asio/asio/detail/null_event.hpp index bcea31b804..db7b7471fb 100644 --- a/ext/asio/asio/detail/null_event.hpp +++ b/ext/asio/asio/detail/null_event.hpp @@ -1,8 +1,8 @@ // -// null_event.hpp -// ~~~~~~~~~~~~~~ +// detail/null_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -70,8 +68,8 @@ public: } // namespace detail } // namespace asio -#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_NULL_EVENT_HPP diff --git a/ext/asio/asio/detail/null_fenced_block.hpp b/ext/asio/asio/detail/null_fenced_block.hpp index dd9a095a72..fbd025f18b 100644 --- a/ext/asio/asio/detail/null_fenced_block.hpp +++ b/ext/asio/asio/detail/null_fenced_block.hpp @@ -1,8 +1,8 @@ // -// null_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/ext/asio/asio/detail/null_mutex.hpp b/ext/asio/asio/detail/null_mutex.hpp index 6661ef8324..bbceb7c2a5 100644 --- a/ext/asio/asio/detail/null_mutex.hpp +++ b/ext/asio/asio/detail/null_mutex.hpp @@ -1,8 +1,8 @@ // -// null_mutex.hpp -// ~~~~~~~~~~~~~~ +// detail/null_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -59,8 +57,8 @@ public: } // namespace detail } // namespace asio -#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/ext/asio/asio/detail/null_signal_blocker.hpp b/ext/asio/asio/detail/null_signal_blocker.hpp index a5db315acb..e0d996f736 100644 --- a/ext/asio/asio/detail/null_signal_blocker.hpp +++ b/ext/asio/asio/detail/null_signal_blocker.hpp @@ -1,8 +1,8 @@ // -// null_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) \ + || defined(ASIO_DISABLE_THREADS) \ + || defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -56,8 +58,12 @@ public: } // namespace detail } // namespace asio -#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_HAS_THREADS) + // || defined(ASIO_DISABLE_THREADS) + // || defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + #endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/ext/asio/asio/detail/null_thread.hpp b/ext/asio/asio/detail/null_thread.hpp index ce3d470ad9..bfe918e289 100644 --- a/ext/asio/asio/detail/null_thread.hpp +++ b/ext/asio/asio/detail/null_thread.hpp @@ -1,8 +1,8 @@ // -// null_thread.hpp -// ~~~~~~~~~~~~~~~ +// detail/null_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,21 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) -#include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -40,11 +34,10 @@ class null_thread public: // Constructor. template <typename Function> - null_thread(Function ) + null_thread(Function, unsigned int = 0) { - asio::system_error e( + asio::detail::throw_error( asio::error::operation_not_supported, "thread"); - boost::throw_exception(e); } // Destructor. @@ -61,8 +54,8 @@ public: } // namespace detail } // namespace asio -#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_NULL_THREAD_HPP diff --git a/ext/asio/asio/detail/null_tss_ptr.hpp b/ext/asio/asio/detail/null_tss_ptr.hpp index 112b4761c6..d3456e6157 100644 --- a/ext/asio/asio/detail/null_tss_ptr.hpp +++ b/ext/asio/asio/detail/null_tss_ptr.hpp @@ -1,8 +1,8 @@ // -// null_tss_ptr.hpp -// ~~~~~~~~~~~~~~~~ +// detail/null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -63,8 +61,8 @@ private: } // namespace detail } // namespace asio -#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/ext/asio/asio/detail/object_pool.hpp b/ext/asio/asio/detail/object_pool.hpp new file mode 100644 index 0000000000..dc50febb16 --- /dev/null +++ b/ext/asio/asio/detail/object_pool.hpp @@ -0,0 +1,146 @@ +// +// detail/object_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_OBJECT_POOL_HPP +#define ASIO_DETAIL_OBJECT_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Object> +class object_pool; + +class object_pool_access +{ +public: + template <typename Object> + static Object* create() + { + return new Object; + } + + template <typename Object> + static void destroy(Object* o) + { + delete o; + } + + template <typename Object> + static Object*& next(Object* o) + { + return o->next_; + } + + template <typename Object> + static Object*& prev(Object* o) + { + return o->prev_; + } +}; + +template <typename Object> +class object_pool + : private noncopyable +{ +public: + // Constructor. + object_pool() + : live_list_(0), + free_list_(0) + { + } + + // Destructor destroys all objects. + ~object_pool() + { + destroy_list(live_list_); + destroy_list(free_list_); + } + + // Get the object at the start of the live list. + Object* first() + { + return live_list_; + } + + // Allocate a new object. + Object* alloc() + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create<Object>(); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Free an object. Moves it to the free list. No destructors are run. + void free(Object* o) + { + if (live_list_ == o) + live_list_ = object_pool_access::next(o); + + if (object_pool_access::prev(o)) + { + object_pool_access::next(object_pool_access::prev(o)) + = object_pool_access::next(o); + } + + if (object_pool_access::next(o)) + { + object_pool_access::prev(object_pool_access::next(o)) + = object_pool_access::prev(o); + } + + object_pool_access::next(o) = free_list_; + object_pool_access::prev(o) = 0; + free_list_ = o; + } + +private: + // Helper function to destroy all elements in a list. + void destroy_list(Object* list) + { + while (list) + { + Object* o = list; + list = object_pool_access::next(o); + object_pool_access::destroy(o); + } + } + + // The list of live objects. + Object* live_list_; + + // The free list. + Object* free_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_OBJECT_POOL_HPP diff --git a/ext/asio/asio/detail/old_win_sdk_compat.hpp b/ext/asio/asio/detail/old_win_sdk_compat.hpp index 70e5916d6a..fb755791d3 100644 --- a/ext/asio/asio/detail/old_win_sdk_compat.hpp +++ b/ext/asio/asio/detail/old_win_sdk_compat.hpp @@ -1,8 +1,8 @@ // -// old_win_sdk_compat.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -36,6 +32,8 @@ // a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support // in that case. +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -321,6 +319,8 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) } // namespace detail } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_OLD_WIN_SDK) // Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. @@ -335,6 +335,4 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/ext/asio/asio/detail/op_queue.hpp b/ext/asio/asio/detail/op_queue.hpp index ccf8b9a5c2..38278eafac 100644 --- a/ext/asio/asio/detail/op_queue.hpp +++ b/ext/asio/asio/detail/op_queue.hpp @@ -1,8 +1,8 @@ // -// op_queue.hpp -// ~~~~~~~~~~~~ +// detail/op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/operation.hpp b/ext/asio/asio/detail/operation.hpp index 6aba361218..3435c057db 100644 --- a/ext/asio/asio/detail/operation.hpp +++ b/ext/asio/asio/detail/operation.hpp @@ -1,8 +1,8 @@ // -// operation.hpp -// ~~~~~~~~~~~~~ +// detail/operation.hpp +// ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_operation.hpp" #else -# include "asio/detail/reactor_fwd.hpp" # include "asio/detail/task_io_service_operation.hpp" #endif @@ -32,12 +29,10 @@ namespace detail { #if defined(ASIO_HAS_IOCP) typedef win_iocp_operation operation; #else -typedef task_io_service_operation<reactor> operation; +typedef task_io_service_operation operation; #endif } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_OPERATION_HPP diff --git a/ext/asio/asio/detail/pipe_select_interrupter.hpp b/ext/asio/asio/detail/pipe_select_interrupter.hpp index 74695994dc..bf3942684c 100644 --- a/ext/asio/asio/detail/pipe_select_interrupter.hpp +++ b/ext/asio/asio/detail/pipe_select_interrupter.hpp @@ -1,8 +1,8 @@ // -// pipe_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,22 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if !defined(BOOST_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(ASIO_HAS_EVENTFD) #include "asio/detail/push_options.hpp" -#include <fcntl.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/socket_types.hpp" namespace asio { namespace detail { @@ -39,57 +31,16 @@ class pipe_select_interrupter { public: // Constructor. - pipe_select_interrupter() - { - int pipe_fds[2]; - if (pipe(pipe_fds) == 0) - { - read_descriptor_ = pipe_fds[0]; - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - write_descriptor_ = pipe_fds[1]; - ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - asio::error_code ec(errno, - asio::error::get_system_category()); - asio::system_error e(ec, "pipe_select_interrupter"); - boost::throw_exception(e); - } - } + ASIO_DECL pipe_select_interrupter(); // Destructor. - ~pipe_select_interrupter() - { - if (read_descriptor_ != -1) - ::close(read_descriptor_); - if (write_descriptor_ != -1) - ::close(write_descriptor_); - } + ASIO_DECL ~pipe_select_interrupter(); // Interrupt the select call. - void interrupt() - { - char byte = 0; - int result = ::write(write_descriptor_, &byte, 1); - (void)result; - } + ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - for (;;) - { - char data[1024]; - int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; - } - } + ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const @@ -113,8 +64,15 @@ private: } // namespace detail } // namespace asio -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/pipe_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(BOOST_WINDOWS) + #endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/ext/asio/asio/detail/pop_options.hpp b/ext/asio/asio/detail/pop_options.hpp index a26b2039c0..4e193363ab 100644 --- a/ext/asio/asio/detail/pop_options.hpp +++ b/ext/asio/asio/detail/pop_options.hpp @@ -1,8 +1,8 @@ // -// pop_options.hpp -// ~~~~~~~~~~~~~~~ +// detail/pop_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -31,6 +31,16 @@ # pragma pack (pop) # endif +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + #elif defined(__KCC) // Kai C++ diff --git a/ext/asio/asio/detail/posix_event.hpp b/ext/asio/asio/detail/posix_event.hpp index 49c15aa5a0..d0ec8b0012 100644 --- a/ext/asio/asio/detail/posix_event.hpp +++ b/ext/asio/asio/detail/posix_event.hpp @@ -1,8 +1,8 @@ // -// posix_event.hpp -// ~~~~~~~~~~~~~~~ +// detail/posix_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,24 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#if defined(BOOST_HAS_PTHREADS) +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) -#include "asio/detail/push_options.hpp" #include <boost/assert.hpp> -#include <boost/throw_exception.hpp> #include <pthread.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -41,19 +33,7 @@ class posix_event { public: // Constructor. - posix_event() - : signalled_(false) - { - int error = ::pthread_cond_init(&cond_, 0); - if (error != 0) - { - asio::system_error e( - asio::error_code(error, - asio::error::get_system_category()), - "event"); - boost::throw_exception(e); - } - } + ASIO_DECL posix_event(); // Destructor. ~posix_event() @@ -107,8 +87,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_HAS_PTHREADS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/ext/asio/asio/detail/posix_fd_set_adapter.hpp b/ext/asio/asio/detail/posix_fd_set_adapter.hpp index 17ef269cee..92d6bba7f2 100644 --- a/ext/asio/asio/detail/posix_fd_set_adapter.hpp +++ b/ext/asio/asio/detail/posix_fd_set_adapter.hpp @@ -1,8 +1,8 @@ // -// posix_fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <cstring> -#include "asio/detail/pop_options.hpp" +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include <cstring> #include "asio/detail/socket_types.hpp" -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -74,8 +73,8 @@ private: } // namespace detail } // namespace asio -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/ext/asio/asio/detail/posix_mutex.hpp b/ext/asio/asio/detail/posix_mutex.hpp index 230b83a356..bcdf6b27d4 100644 --- a/ext/asio/asio/detail/posix_mutex.hpp +++ b/ext/asio/asio/detail/posix_mutex.hpp @@ -1,8 +1,8 @@ // -// posix_mutex.hpp -// ~~~~~~~~~~~~~~~ +// detail/posix_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,24 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#if defined(BOOST_HAS_PTHREADS) +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) -#include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> #include <pthread.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -45,18 +37,7 @@ public: typedef asio::detail::scoped_lock<posix_mutex> scoped_lock; // Constructor. - posix_mutex() - { - int error = ::pthread_mutex_init(&mutex_, 0); - if (error != 0) - { - asio::system_error e( - asio::error_code(error, - asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } - } + ASIO_DECL posix_mutex(); // Destructor. ~posix_mutex() @@ -84,8 +65,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_HAS_PTHREADS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/ext/asio/asio/detail/posix_signal_blocker.hpp b/ext/asio/asio/detail/posix_signal_blocker.hpp index 135ca41b7e..d41f128476 100644 --- a/ext/asio/asio/detail/posix_signal_blocker.hpp +++ b/ext/asio/asio/detail/posix_signal_blocker.hpp @@ -1,8 +1,8 @@ // -// posix_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,22 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#if defined(BOOST_HAS_PTHREADS) +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) -#include "asio/detail/push_options.hpp" #include <csignal> #include <pthread.h> #include <signal.h> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -83,8 +78,8 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_HAS_PTHREADS) - #include "asio/detail/pop_options.hpp" +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/ext/asio/asio/detail/posix_thread.hpp b/ext/asio/asio/detail/posix_thread.hpp index e0fea75129..743417cd62 100644 --- a/ext/asio/asio/detail/posix_thread.hpp +++ b/ext/asio/asio/detail/posix_thread.hpp @@ -1,8 +1,8 @@ // -// posix_thread.hpp -// ~~~~~~~~~~~~~~~~ +// detail/posix_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,28 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#if defined(BOOST_HAS_PTHREADS) +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) -#include "asio/detail/push_options.hpp" -#include <memory> -#include <boost/throw_exception.hpp> #include <pthread.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { -extern "C" void* asio_detail_posix_thread_function(void* arg); +extern "C" +{ + ASIO_DECL void* asio_detail_posix_thread_function(void* arg); +} class posix_thread : private noncopyable @@ -47,36 +41,14 @@ public: posix_thread(Function f) : joined_(false) { - std::auto_ptr<func_base> arg(new func<Function>(f)); - int error = ::pthread_create(&thread_, 0, - asio_detail_posix_thread_function, arg.get()); - if (error != 0) - { - asio::system_error e( - asio::error_code(error, - asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); - } - arg.release(); + start_thread(new func<Function>(f)); } // Destructor. - ~posix_thread() - { - if (!joined_) - ::pthread_detach(thread_); - } + ASIO_DECL ~posix_thread(); // Wait for the thread to exit. - void join() - { - if (!joined_) - { - ::pthread_join(thread_, 0); - joined_ = true; - } - } + ASIO_DECL void join(); private: friend void* asio_detail_posix_thread_function(void* arg); @@ -88,6 +60,12 @@ private: virtual void run() = 0; }; + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + template <typename Function> class func : public func_base @@ -107,23 +85,21 @@ private: Function f_; }; + ASIO_DECL void start_thread(func_base* arg); + ::pthread_t thread_; bool joined_; }; -inline void* asio_detail_posix_thread_function(void* arg) -{ - std::auto_ptr<posix_thread::func_base> f( - static_cast<posix_thread::func_base*>(arg)); - f->run(); - return 0; -} - } // namespace detail } // namespace asio -#endif // defined(BOOST_HAS_PTHREADS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_thread.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/ext/asio/asio/detail/posix_tss_ptr.hpp b/ext/asio/asio/detail/posix_tss_ptr.hpp index 3b4ba07b44..30d9705e7a 100644 --- a/ext/asio/asio/detail/posix_tss_ptr.hpp +++ b/ext/asio/asio/detail/posix_tss_ptr.hpp @@ -1,8 +1,8 @@ // -// posix_tss_ptr.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,26 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#if defined(BOOST_HAS_PTHREADS) +#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) -#include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> #include <pthread.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { +// Helper function to create thread-specific storage. +ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); + template <typename T> class posix_tss_ptr : private noncopyable @@ -43,15 +38,7 @@ public: // Constructor. posix_tss_ptr() { - int error = ::pthread_key_create(&tss_key_, 0); - if (error != 0) - { - asio::system_error e( - asio::error_code(error, - asio::error::get_system_category()), - "tss"); - boost::throw_exception(e); - } + posix_tss_ptr_create(tss_key_); } // Destructor. @@ -76,13 +63,18 @@ private: // Thread-specific storage to allow unlocked access to determine whether a // thread is a member of the pool. pthread_key_t tss_key_; + }; } // namespace detail } // namespace asio -#endif // defined(BOOST_HAS_PTHREADS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_tss_ptr.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) + #endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/ext/asio/asio/detail/push_options.hpp b/ext/asio/asio/detail/push_options.hpp index cb0e90242e..ebb3276052 100644 --- a/ext/asio/asio/detail/push_options.hpp +++ b/ext/asio/asio/detail/push_options.hpp @@ -1,8 +1,8 @@ // -// push_options.hpp -// ~~~~~~~~~~~~~~~~ +// detail/push_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -31,6 +31,18 @@ # pragma pack (push, 8) # endif +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + #elif defined(__KCC) // Kai C++ diff --git a/ext/asio/asio/detail/reactive_descriptor_service.hpp b/ext/asio/asio/detail/reactive_descriptor_service.hpp index 7ad368d7de..f7e8bf53a5 100644 --- a/ext/asio/asio/detail/reactive_descriptor_service.hpp +++ b/ext/asio/asio/detail/reactive_descriptor_service.hpp @@ -1,8 +1,8 @@ // -// reactive_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,21 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include <boost/utility/addressof.hpp> #include "asio/buffer.hpp" -#include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/descriptor_read_op.hpp" +#include "asio/detail/descriptor_write_op.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/noncopyable.hpp" -#include "asio/detail/null_buffers_op.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" #include "asio/detail/reactor.hpp" -#include "asio/detail/reactor_op.hpp" -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -48,7 +51,7 @@ public: // Default constructor. implementation_type() : descriptor_(-1), - flags_(0) + state_(0) { } @@ -59,94 +62,29 @@ public: // The native descriptor representation. int descriptor_; - enum - { - // The user wants a non-blocking descriptor. - user_set_non_blocking = 1, - - // The descriptor has been set non-blocking. - internal_non_blocking = 2, - - // Helper "flag" used to determine whether the descriptor is non-blocking. - non_blocking = user_set_non_blocking | internal_non_blocking - }; - - // Flags indicating the current state of the descriptor. - unsigned char flags_; + // The current state of the descriptor. + descriptor_ops::state_type state_; // Per-descriptor data used by the reactor. reactor::per_descriptor_data reactor_data_; }; - // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; - // Constructor. - reactive_descriptor_service(asio::io_service& io_service) - : io_service_impl_(asio::use_service<io_service_impl>(io_service)), - reactor_(asio::use_service<reactor>(io_service)) - { - reactor_.init_task(); - } + ASIO_DECL reactive_descriptor_service( + asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } + ASIO_DECL void shutdown_service(); // Construct a new descriptor implementation. - void construct(implementation_type& impl) - { - impl.descriptor_ = -1; - impl.flags_ = 0; - } + ASIO_DECL void construct(implementation_type& impl); // Destroy a descriptor implementation. - void destroy(implementation_type& impl) - { - if (impl.descriptor_ != -1) - { - reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::internal_non_blocking) - { - ioctl_arg_type non_blocking = 0; - asio::error_code ignored_ec; - descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; - } - - asio::error_code ignored_ec; - descriptor_ops::close(impl.descriptor_, ignored_ec); - - impl.descriptor_ = -1; - } - } + ASIO_DECL void destroy(implementation_type& impl); // Assign a native descriptor to a descriptor implementation. - asio::error_code assign(implementation_type& impl, - const native_type& native_descriptor, asio::error_code& ec) - { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - if (int err = reactor_.register_descriptor( - native_descriptor, impl.reactor_data_)) - { - ec = asio::error_code(err, - asio::error::get_system_category()); - return ec; - } - - impl.descriptor_ = native_descriptor; - impl.flags_ = 0; - ec = asio::error_code(); - return ec; - } + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_type& native_descriptor, asio::error_code& ec); // Determine whether the descriptor is open. bool is_open(const implementation_type& impl) const @@ -155,31 +93,8 @@ public: } // Destroy a descriptor implementation. - asio::error_code close(implementation_type& impl, - asio::error_code& ec) - { - if (is_open(impl)) - { - reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::internal_non_blocking) - { - ioctl_arg_type non_blocking = 0; - asio::error_code ignored_ec; - descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; - } - - if (descriptor_ops::close(impl.descriptor_, ec) == -1) - return ec; - - impl.descriptor_ = -1; - } - - ec = asio::error_code(); - return ec; - } + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); // Get the native descriptor representation. native_type native(const implementation_type& impl) const @@ -188,56 +103,16 @@ public: } // Cancel all operations associated with the descriptor. - asio::error_code cancel(implementation_type& impl, - asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); - ec = asio::error_code(); - return ec; - } + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); // Perform an IO control command on the descriptor. template <typename IO_Control_Command> asio::error_code io_control(implementation_type& impl, IO_Control_Command& command, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - descriptor_ops::ioctl(impl.descriptor_, command.name(), - static_cast<ioctl_arg_type*>(command.data()), ec); - - // When updating the non-blocking mode we always perform the ioctl syscall, - // even if the flags would otherwise indicate that the descriptor is - // already in the correct state. This ensures that the underlying - // descriptor is put into the state that has been requested by the user. If - // the ioctl syscall was successful then we need to update the flags to - // match. - if (!ec && command.name() == static_cast<int>(FIONBIO)) - { - if (*static_cast<ioctl_arg_type*>(command.data())) - { - impl.flags_ |= implementation_type::user_set_non_blocking; - } - else - { - // Clearing the non-blocking mode always overrides any internally-set - // non-blocking flag. Any subsequent asynchronous operations will need - // to re-enable non-blocking I/O. - impl.flags_ &= ~(implementation_type::user_set_non_blocking - | implementation_type::internal_non_blocking); - } - } - + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast<ioctl_arg_type*>(command.data()), ec); return ec; } @@ -246,148 +121,23 @@ public: size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); - // A request to read_some 0 bytes on a stream is a no-op. - if (bufs.all_empty()) - { - ec = asio::error_code(); - return 0; - } - - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = descriptor_ops::gather_write( - impl.descriptor_, bufs.buffers(), bufs.count(), ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != asio::error::would_block - && ec != asio::error::try_again)) - return 0; - - // Wait for descriptor to become ready. - if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0) - return 0; - } + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be written without blocking. size_t write_some(implementation_type& impl, const null_buffers&, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - // Wait for descriptor to become ready. descriptor_ops::poll_write(impl.descriptor_, ec); return 0; } - template <typename ConstBufferSequence> - class write_op_base : public reactor_op - { - public: - write_op_base(int descriptor, - const ConstBufferSequence& buffers, func_type complete_func) - : reactor_op(&write_op_base::do_perform, complete_func), - descriptor_(descriptor), - buffers_(buffers) - { - } - - static bool do_perform(reactor_op* base) - { - write_op_base* o(static_cast<write_op_base*>(base)); - - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(o->buffers_); - - for (;;) - { - // Write the data. - asio::error_code ec; - int bytes = descriptor_ops::gather_write( - o->descriptor_, bufs.buffers(), bufs.count(), ec); - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - int descriptor_; - ConstBufferSequence buffers_; - }; - - template <typename ConstBufferSequence, typename Handler> - class write_op : public write_op_base<ConstBufferSequence> - { - public: - write_op(int descriptor, - const ConstBufferSequence& buffers, Handler handler) - : write_op_base<ConstBufferSequence>( - descriptor, buffers, &write_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - write_op* o(static_cast<write_op*>(base)); - typedef handler_alloc_traits<Handler, write_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous write. The data being sent must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> @@ -395,15 +145,16 @@ public: const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef write_op<ConstBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, impl.descriptor_, buffers, handler); + typedef descriptor_write_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); - start_op(impl, reactor::write_op, ptr.get(), true, + start_op(impl, reactor::write_op, p.p, true, buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence>::all_empty(buffers)); - ptr.release(); + p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. @@ -412,13 +163,14 @@ public: const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; } // Read some data from the stream. Returns the number of bytes read. @@ -426,157 +178,23 @@ public: size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); - // A request to read_some 0 bytes on a stream is a no-op. - if (bufs.all_empty()) - { - ec = asio::error_code(); - return 0; - } - - // Read some data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_read = descriptor_ops::scatter_read( - impl.descriptor_, bufs.buffers(), bufs.count(), ec); - - // Check if operation succeeded. - if (bytes_read > 0) - return bytes_read; - - // Check for EOF. - if (bytes_read == 0) - { - ec = asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != asio::error::would_block - && ec != asio::error::try_again)) - return 0; - - // Wait for descriptor to become ready. - if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0) - return 0; - } + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be read without blocking. size_t read_some(implementation_type& impl, const null_buffers&, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - // Wait for descriptor to become ready. descriptor_ops::poll_read(impl.descriptor_, ec); return 0; } - template <typename MutableBufferSequence> - class read_op_base : public reactor_op - { - public: - read_op_base(int descriptor, - const MutableBufferSequence& buffers, func_type complete_func) - : reactor_op(&read_op_base::do_perform, complete_func), - descriptor_(descriptor), - buffers_(buffers) - { - } - - static bool do_perform(reactor_op* base) - { - read_op_base* o(static_cast<read_op_base*>(base)); - - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(o->buffers_); - - for (;;) - { - // Read some data. - asio::error_code ec; - int bytes = descriptor_ops::scatter_read( - o->descriptor_, bufs.buffers(), bufs.count(), ec); - if (bytes == 0) - ec = asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - int descriptor_; - MutableBufferSequence buffers_; - }; - - template <typename MutableBufferSequence, typename Handler> - class read_op : public read_op_base<MutableBufferSequence> - { - public: - read_op(int descriptor, - const MutableBufferSequence& buffers, Handler handler) - : read_op_base<MutableBufferSequence>( - descriptor, buffers, &read_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - read_op* o(static_cast<read_op*>(base)); - typedef handler_alloc_traits<Handler, read_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous read. The buffer for the data being read must be // valid for the lifetime of the asynchronous operation. template <typename MutableBufferSequence, typename Handler> @@ -584,16 +202,16 @@ public: const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef read_op<MutableBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, - impl.descriptor_, buffers, handler); + typedef descriptor_read_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); - start_op(impl, reactor::read_op, ptr.get(), true, + start_op(impl, reactor::read_op, p.p, true, buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence>::all_empty(buffers)); - ptr.release(); + p.v = p.p = 0; } // Wait until data can be read without blocking. @@ -602,57 +220,20 @@ public: const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::read_op, ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::read_op, p.p, false, false); + p.v = p.p = 0; } private: // Start the asynchronous operation. - void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool non_blocking, bool noop) - { - if (!noop) - { - if (is_open(impl)) - { - if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) - { - reactor_.start_op(op_type, impl.descriptor_, - impl.reactor_data_, op, non_blocking); - return; - } - } - else - op->ec_ = asio::error::bad_descriptor; - } - - io_service_impl_.post_immediate_completion(op); - } - - // Determine whether the descriptor has been set non-blocking. - bool is_non_blocking(implementation_type& impl) const - { - return (impl.flags_ & implementation_type::non_blocking); - } - - // Set the internal non-blocking flag. - bool set_non_blocking(implementation_type& impl, - asio::error_code& ec) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - return false; - impl.flags_ |= implementation_type::internal_non_blocking; - return true; - } - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; + ASIO_DECL void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop); // The selector that performs event demultiplexing for the service. reactor& reactor_; @@ -661,8 +242,12 @@ private: } // namespace detail } // namespace asio -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_descriptor_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/ext/asio/asio/detail/reactive_null_buffers_op.hpp b/ext/asio/asio/detail/reactive_null_buffers_op.hpp new file mode 100644 index 0000000000..0c83c612ab --- /dev/null +++ b/ext/asio/asio/detail/reactive_null_buffers_op.hpp @@ -0,0 +1,83 @@ +// +// detail/reactive_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class reactive_null_buffers_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); + + reactive_null_buffers_op(Handler handler) + : reactor_op(&reactive_null_buffers_op::do_perform, + &reactive_null_buffers_op::do_complete), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP diff --git a/ext/asio/asio/detail/reactive_serial_port_service.hpp b/ext/asio/asio/detail/reactive_serial_port_service.hpp index 186460fef6..556ea06d87 100644 --- a/ext/asio/asio/detail/reactive_serial_port_service.hpp +++ b/ext/asio/asio/detail/reactive_serial_port_service.hpp @@ -1,8 +1,8 @@ // -// reactive_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,23 +16,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <cstring> -#include <string> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/serial_port_base.hpp" - -#if defined(ASIO_HAS_SERIAL_PORT) \ - && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if defined(ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include <string> #include "asio/error.hpp" #include "asio/io_service.hpp" +#include "asio/serial_port_base.hpp" #include "asio/detail/descriptor_ops.hpp" #include "asio/detail/reactive_descriptor_service.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -46,119 +43,55 @@ public: // The implementation type of the serial port. typedef reactive_descriptor_service::implementation_type implementation_type; - reactive_serial_port_service(asio::io_service& io_service) - : descriptor_service_(io_service) - { - } + ASIO_DECL reactive_serial_port_service( + asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - descriptor_service_.shutdown_service(); - } + ASIO_DECL void shutdown_service(); - // Construct a new handle implementation. + // Construct a new serial port implementation. void construct(implementation_type& impl) { descriptor_service_.construct(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. void destroy(implementation_type& impl) { descriptor_service_.destroy(impl); } // Open the serial port using the specified device name. - asio::error_code open(implementation_type& impl, - const std::string& device, asio::error_code& ec) - { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - int fd = descriptor_ops::open(device.c_str(), - O_RDWR | O_NONBLOCK | O_NOCTTY, ec); - if (fd < 0) - return ec; - - int s = descriptor_ops::fcntl(fd, F_GETFL, ec); - if (s >= 0) - s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); - if (s < 0) - { - asio::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - return ec; - } - - // Set up default serial port options. - termios ios; - descriptor_ops::clear_error(ec); - s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); - if (s >= 0) - { -#if defined(_BSD_SOURCE) - ::cfmakeraw(&ios); -#else - ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK - | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - ios.c_oflag &= ~OPOST; - ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - ios.c_cflag &= ~(CSIZE | PARENB); - ios.c_cflag |= CS8; -#endif - ios.c_iflag |= IGNPAR; - ios.c_cflag |= CREAD | CLOCAL; - descriptor_ops::clear_error(ec); - s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); - } - if (s < 0) - { - asio::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - return ec; - } - - // We're done. Take ownership of the serial port descriptor. - if (descriptor_service_.assign(impl, fd, ec)) - { - asio::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - } - - return ec; - } + ASIO_DECL asio::error_code open(implementation_type& impl, + const std::string& device, asio::error_code& ec); - // Assign a native handle to a handle implementation. + // Assign a native descriptor to a serial port implementation. asio::error_code assign(implementation_type& impl, const native_type& native_descriptor, asio::error_code& ec) { return descriptor_service_.assign(impl, native_descriptor, ec); } - // Determine whether the handle is open. + // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return descriptor_service_.is_open(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return descriptor_service_.close(impl, ec); } - // Get the native handle representation. + // Get the native serial port representation. native_type native(implementation_type& impl) { return descriptor_service_.native(impl); } - // Cancel all operations associated with the handle. + // Cancel all operations associated with the serial port. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { @@ -170,20 +103,9 @@ public: asio::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, asio::error_code& ec) { - termios ios; - descriptor_ops::clear_error(ec); - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native(impl), &ios), ec); - if (ec) - return ec; - - if (option.store(ios, ec)) - return ec; - - descriptor_ops::clear_error(ec); - descriptor_ops::error_wrapper(::tcsetattr( - descriptor_service_.native(impl), TCSANOW, &ios), ec); - return ec; + return do_set_option(impl, + &reactive_serial_port_service::store_option<SettableSerialPortOption>, + &option, ec); } // Get an option from the serial port. @@ -191,21 +113,16 @@ public: asio::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, asio::error_code& ec) const { - termios ios; - descriptor_ops::clear_error(ec); - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native(impl), &ios), ec); - if (ec) - return ec; - - return option.load(ios, ec); + return do_get_option(impl, + &reactive_serial_port_service::load_option<GettableSerialPortOption>, + &option, ec); } // Send a break sequence to the serial port. asio::error_code send_break(implementation_type& impl, asio::error_code& ec) { - descriptor_ops::clear_error(ec); + errno = 0; descriptor_ops::error_wrapper(::tcsendbreak( descriptor_service_.native(impl), 0), ec); return ec; @@ -246,6 +163,41 @@ public: } private: + // Function pointer type for storing a serial port option. + typedef asio::error_code (*store_function_type)( + const void*, termios&, asio::error_code&); + + // Helper function template to store a serial port option. + template <typename SettableSerialPortOption> + static asio::error_code store_option(const void* option, + termios& storage, asio::error_code& ec) + { + return static_cast<const SettableSerialPortOption*>(option)->store( + storage, ec); + } + + // Helper function to set a serial port option. + ASIO_DECL asio::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, asio::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef asio::error_code (*load_function_type)( + void*, const termios&, asio::error_code&); + + // Helper function template to load a serial port option. + template <typename GettableSerialPortOption> + static asio::error_code load_option(void* option, + const termios& storage, asio::error_code& ec) + { + return static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + } + + // Helper function to get a serial port option. + ASIO_DECL asio::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, asio::error_code& ec) const; + // The implementation used for initiating asynchronous operations. reactive_descriptor_service descriptor_service_; }; @@ -253,9 +205,13 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_SERIAL_PORT) - // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_serial_port_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(ASIO_HAS_SERIAL_PORT) + #endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/ext/asio/asio/detail/reactive_socket_accept_op.hpp b/ext/asio/asio/detail/reactive_socket_accept_op.hpp new file mode 100644 index 0000000000..76c6741180 --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_accept_op.hpp @@ -0,0 +1,131 @@ +// +// detail/reactive_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Socket, typename Protocol> +class reactive_socket_accept_op_base : public reactor_op +{ +public: + reactive_socket_accept_op_base(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, func_type complete_func) + : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_accept_op_base* o( + static_cast<reactive_socket_accept_op_base*>(base)); + + std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0; + socket_type new_socket = invalid_socket; + bool result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket); + + // On success, assign new connection to peer socket object. + if (new_socket >= 0) + { + socket_holder new_socket_holder(new_socket); + if (o->peer_endpoint_) + o->peer_endpoint_->resize(addrlen); + if (!o->peer_.assign(o->protocol_, new_socket, o->ec_)) + new_socket_holder.release(); + } + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; +}; + +template <typename Socket, typename Protocol, typename Handler> +class reactive_socket_accept_op : + public reactive_socket_accept_op_base<Socket, Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); + + reactive_socket_accept_op(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler handler) + : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer, + protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP diff --git a/ext/asio/asio/detail/reactive_socket_connect_op.hpp b/ext/asio/asio/detail/reactive_socket_connect_op.hpp new file mode 100644 index 0000000000..8267091b21 --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_connect_op.hpp @@ -0,0 +1,101 @@ +// +// detail/reactive_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_socket_connect_op_base : public reactor_op +{ +public: + reactive_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + socket_(socket) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_connect_op_base* o( + static_cast<reactive_socket_connect_op_base*>(base)); + + return socket_ops::non_blocking_connect(o->socket_, o->ec_); + } + +private: + socket_type socket_; +}; + +template <typename Handler> +class reactive_socket_connect_op : public reactive_socket_connect_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); + + reactive_socket_connect_op(socket_type socket, Handler handler) + : reactive_socket_connect_op_base(socket, + &reactive_socket_connect_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast<reactive_socket_connect_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP diff --git a/ext/asio/asio/detail/reactive_socket_recv_op.hpp b/ext/asio/asio/detail/reactive_socket_recv_op.hpp new file mode 100644 index 0000000000..91a30a849e --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_recv_op.hpp @@ -0,0 +1,118 @@ +// +// detail/reactive_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class reactive_socket_recv_op_base : public reactor_op +{ +public: + reactive_socket_recv_op_base(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_recv_op_base* o( + static_cast<reactive_socket_recv_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + return socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented), + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template <typename MutableBufferSequence, typename Handler> +class reactive_socket_recv_op : + public reactive_socket_recv_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); + + reactive_socket_recv_op(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state, + buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP diff --git a/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp b/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp new file mode 100644 index 0000000000..121d6ecbd8 --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp @@ -0,0 +1,128 @@ +// +// detail/reactive_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Endpoint> +class reactive_socket_recvfrom_op_base : public reactor_op +{ +public: + reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + protocol_type_(protocol_type), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_recvfrom_op_base* o( + static_cast<reactive_socket_recvfrom_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + std::size_t addr_len = o->sender_endpoint_.capacity(); + bool result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_); + + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + + return result; + } + +private: + socket_type socket_; + int protocol_type_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; +}; + +template <typename MutableBufferSequence, typename Endpoint, typename Handler> +class reactive_socket_recvfrom_op : + public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); + + reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, Handler handler) + : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>( + socket, protocol_type, buffers, endpoint, flags, + &reactive_socket_recvfrom_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast<reactive_socket_recvfrom_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP diff --git a/ext/asio/asio/detail/reactive_socket_send_op.hpp b/ext/asio/asio/detail/reactive_socket_send_op.hpp new file mode 100644 index 0000000000..9a68dacccb --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_send_op.hpp @@ -0,0 +1,115 @@ +// +// detail/reactive_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class reactive_socket_send_op_base : public reactor_op +{ +public: + reactive_socket_send_op_base(socket_type socket, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_send_op_base* o( + static_cast<reactive_socket_send_op_base*>(base)); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(o->buffers_); + + return socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template <typename ConstBufferSequence, typename Handler> +class reactive_socket_send_op : + public reactive_socket_send_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); + + reactive_socket_send_op(socket_type socket, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : reactive_socket_send_op_base<ConstBufferSequence>(socket, + buffers, flags, &reactive_socket_send_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP diff --git a/ext/asio/asio/detail/reactive_socket_sendto_op.hpp b/ext/asio/asio/detail/reactive_socket_sendto_op.hpp new file mode 100644 index 0000000000..e466a2591e --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_sendto_op.hpp @@ -0,0 +1,118 @@ +// +// detail/reactive_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Endpoint> +class reactive_socket_sendto_op_base : public reactor_op +{ +public: + reactive_socket_sendto_op_base(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_sendto_op_base* o( + static_cast<reactive_socket_sendto_op_base*>(base)); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(o->buffers_); + + return socket_ops::non_blocking_sendto(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; +}; + +template <typename ConstBufferSequence, typename Endpoint, typename Handler> +class reactive_socket_sendto_op : + public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); + + reactive_socket_sendto_op(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, Handler handler) + : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket, + buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP diff --git a/ext/asio/asio/detail/reactive_socket_service.hpp b/ext/asio/asio/detail/reactive_socket_service.hpp index 20bd512ef6..daa9f607ad 100644 --- a/ext/asio/asio/detail/reactive_socket_service.hpp +++ b/ext/asio/asio/detail/reactive_socket_service.hpp @@ -1,8 +1,8 @@ // -// reactive_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,28 +15,37 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) +#include <boost/utility/addressof.hpp> #include "asio/buffer.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" -#include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" -#include "asio/detail/fenced_block.hpp" #include "asio/detail/noncopyable.hpp" -#include "asio/detail/null_buffers_op.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_socket_accept_op.hpp" +#include "asio/detail/reactive_socket_connect_op.hpp" +#include "asio/detail/reactive_socket_recvfrom_op.hpp" +#include "asio/detail/reactive_socket_sendto_op.hpp" +#include "asio/detail/reactive_socket_service_base.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { template <typename Protocol> -class reactive_socket_service +class reactive_socket_service : + public reactive_socket_service_base { public: // The protocol type. @@ -49,132 +58,32 @@ public: typedef socket_type native_type; // The implementation type of the socket. - class implementation_type - : private asio::detail::noncopyable + struct implementation_type : + reactive_socket_service_base::base_implementation_type { - public: // Default constructor. implementation_type() - : socket_(invalid_socket), - flags_(0), - protocol_(endpoint_type().protocol()) + : protocol_(endpoint_type().protocol()) { } - private: - // Only this service will have access to the internal values. - friend class reactive_socket_service<Protocol>; - - // The native socket representation. - socket_type socket_; - - enum - { - // The user wants a non-blocking socket. - user_set_non_blocking = 1, - - // The implementation wants a non-blocking socket (in order to be able to - // perform asynchronous read and write operations). - internal_non_blocking = 2, - - // Helper "flag" used to determine whether the socket is non-blocking. - non_blocking = user_set_non_blocking | internal_non_blocking, - - // User wants connection_aborted errors, which are disabled by default. - enable_connection_aborted = 4, - - // The user set the linger option. Needs to be checked when closing. - user_set_linger = 8 - }; - - // Flags indicating the current state of the socket. - unsigned char flags_; - // The protocol associated with the socket. protocol_type protocol_; - - // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; }; // Constructor. reactive_socket_service(asio::io_service& io_service) - : io_service_impl_(use_service<io_service_impl>(io_service)), - reactor_(use_service<reactor>(io_service)) - { - reactor_.init_task(); - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // Construct a new socket implementation. - void construct(implementation_type& impl) + : reactive_socket_service_base(io_service) { - impl.socket_ = invalid_socket; - impl.flags_ = 0; - } - - // Destroy a socket implementation. - void destroy(implementation_type& impl) - { - if (impl.socket_ != invalid_socket) - { - reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::non_blocking) - { - ioctl_arg_type non_blocking = 0; - asio::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::non_blocking; - } - - if (impl.flags_ & implementation_type::user_set_linger) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - asio::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - asio::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - - impl.socket_ = invalid_socket; - } } // Open a new socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - socket_holder sock(socket_ops::socket(protocol.family(), - protocol.type(), protocol.protocol(), ec)); - if (sock.get() == invalid_socket) - return ec; - - if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) - { - ec = asio::error_code(err, - asio::error::get_system_category()); - return ec; - } - - impl.socket_ = sock.release(); - impl.flags_ = 0; - impl.protocol_ = protocol; - ec = asio::error_code(); + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; return ec; } @@ -183,56 +92,8 @@ public: const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - if (int err = reactor_.register_descriptor( - native_socket, impl.reactor_data_)) - { - ec = asio::error_code(err, - asio::error::get_system_category()); - return ec; - } - - impl.socket_ = native_socket; - impl.flags_ = 0; - impl.protocol_ = protocol; - ec = asio::error_code(); - return ec; - } - - // Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return impl.socket_ != invalid_socket; - } - - // Destroy a socket implementation. - asio::error_code close(implementation_type& impl, - asio::error_code& ec) - { - if (is_open(impl)) - { - reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::non_blocking) - { - ioctl_arg_type non_blocking = 0; - asio::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::non_blocking; - } - - if (socket_ops::close(impl.socket_, ec) == socket_error_retval) - return ec; - - impl.socket_ = invalid_socket; - } - - ec = asio::error_code(); + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; return ec; } @@ -242,153 +103,23 @@ public: return impl.socket_; } - // Cancel all operations associated with the socket. - asio::error_code cancel(implementation_type& impl, - asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - reactor_.cancel_ops(impl.socket_, impl.reactor_data_); - ec = asio::error_code(); - return ec; - } - - // Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - asio::error_code& ec) const - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return false; - } - -#if defined(SIOCATMARK) - asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); -# if defined(ENOTTY) - if (ec.value() == ENOTTY) - ec = asio::error::not_socket; -# endif // defined(ENOTTY) -#else // defined(SIOCATMARK) - int value = sockatmark(impl.socket_); - if (value == -1) - ec = asio::error_code(errno, - asio::error::get_system_category()); - else - ec = asio::error_code(); -#endif // defined(SIOCATMARK) - return ec ? false : value != 0; - } - - // Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - asio::error_code& ec) const - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); -#if defined(ENOTTY) - if (ec.value() == ENOTTY) - ec = asio::error::not_socket; -#endif // defined(ENOTTY) - return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value); - } - // Bind the socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } - // Place the socket into the state where it will listen for new connections. - asio::error_code listen(implementation_type& impl, int backlog, - asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - socket_ops::listen(impl.socket_, backlog, ec); - return ec; - } - // Set a socket option. template <typename Option> asio::error_code set_option(implementation_type& impl, const Option& option, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = asio::error::invalid_argument; - } - else - { - if (*reinterpret_cast<const int*>(option.data(impl.protocol_))) - impl.flags_ |= implementation_type::enable_connection_aborted; - else - impl.flags_ &= ~implementation_type::enable_connection_aborted; - ec = asio::error_code(); - } - return ec; - } - else - { - if (option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_LINGER) - { - impl.flags_ |= implementation_type::user_set_linger; - } - - socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_), ec); - -#if defined(__MACH__) && defined(__APPLE__) \ -|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - // To implement portable behaviour for SO_REUSEADDR with UDP sockets we - // need to also set SO_REUSEPORT on BSD-based platforms. - if (!ec && impl.protocol_.type() == SOCK_DGRAM - && option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_REUSEADDR) - { - asio::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT, - option.data(impl.protocol_), option.size(impl.protocol_), - ignored_ec); - } -#endif - - return ec; - } + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } // Set a socket option. @@ -396,78 +127,12 @@ public: asio::error_code get_option(const implementation_type& impl, Option& option, asio::error_code& ec) const { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = asio::error::invalid_argument; - } - else - { - int* target = reinterpret_cast<int*>(option.data(impl.protocol_)); - if (impl.flags_ & implementation_type::enable_connection_aborted) - *target = 1; - else - *target = 0; - option.resize(impl.protocol_, sizeof(int)); - ec = asio::error_code(); - } - return ec; - } - else - { - size_t size = option.size(impl.protocol_); - socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size, ec); - if (!ec) - option.resize(impl.protocol_, size); - return ec; - } - } - - // Perform an IO control command on the socket. - template <typename IO_Control_Command> - asio::error_code io_control(implementation_type& impl, - IO_Control_Command& command, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - socket_ops::ioctl(impl.socket_, command.name(), - static_cast<ioctl_arg_type*>(command.data()), ec); - - // When updating the non-blocking mode we always perform the ioctl - // syscall, even if the flags would otherwise indicate that the socket is - // already in the correct state. This ensures that the underlying socket - // is put into the state that has been requested by the user. If the ioctl - // syscall was successful then we need to update the flags to match. - if (!ec && command.name() == static_cast<int>(FIONBIO)) - { - if (*static_cast<ioctl_arg_type*>(command.data())) - { - impl.flags_ |= implementation_type::user_set_non_blocking; - } - else - { - // Clearing the non-blocking mode always overrides any internally-set - // non-blocking flag. Any subsequent asynchronous operations will need - // to re-enable non-blocking I/O. - impl.flags_ &= ~(implementation_type::user_set_non_blocking - | implementation_type::internal_non_blocking); - } - } - + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); return ec; } @@ -475,12 +140,6 @@ public: endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) @@ -493,218 +152,15 @@ public: endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } - /// Disable sends or receives on the socket. - asio::error_code shutdown(implementation_type& impl, - socket_base::shutdown_type what, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - socket_ops::shutdown(impl.socket_, what, ec); - return ec; - } - - // Send the given data to the peer. - template <typename ConstBufferSequence> - size_t send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = asio::error_code(); - return 0; - } - - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = socket_ops::send(impl.socket_, - bufs.buffers(), bufs.count(), flags, ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != asio::error::would_block - && ec != asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_, ec) < 0) - return 0; - } - } - - // Wait until data can be sent without blocking. - size_t send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, ec); - - return 0; - } - - template <typename ConstBufferSequence> - class send_op_base : public reactor_op - { - public: - send_op_base(socket_type socket, const ConstBufferSequence& buffers, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&send_op_base::do_perform, complete_func), - socket_(socket), - buffers_(buffers), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - send_op_base* o(static_cast<send_op_base*>(base)); - - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(o->buffers_); - - for (;;) - { - // Send the data. - asio::error_code ec; - int bytes = socket_ops::send(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, ec); - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - ConstBufferSequence buffers_; - socket_base::message_flags flags_; - }; - - template <typename ConstBufferSequence, typename Handler> - class send_op : public send_op_base<ConstBufferSequence> - { - public: - send_op(socket_type socket, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : send_op_base<ConstBufferSequence>(socket, - buffers, flags, &send_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - send_op* o(static_cast<send_op*>(base)); - typedef handler_alloc_traits<Handler, send_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef send_op<ConstBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, - impl.socket_, buffers, flags, handler); - - start_op(impl, reactor::write_op, ptr.get(), true, - (impl.protocol_.type() == SOCK_STREAM - && buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::all_empty(buffers))); - ptr.release(); - } - - // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> - void async_send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); - } - // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template <typename ConstBufferSequence> @@ -712,148 +168,25 @@ public: const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(), - bufs.count(), flags, destination.data(), destination.size(), ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != asio::error::would_block - && ec != asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_, ec) < 0) - return 0; - } + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); } // Wait until data can be sent without blocking. size_t send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, + const endpoint_type&, socket_base::message_flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } - template <typename ConstBufferSequence> - class send_to_op_base : public reactor_op - { - public: - send_to_op_base(socket_type socket, const ConstBufferSequence& buffers, - const endpoint_type& endpoint, socket_base::message_flags flags, - func_type complete_func) - : reactor_op(&send_to_op_base::do_perform, complete_func), - socket_(socket), - buffers_(buffers), - destination_(endpoint), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - send_to_op_base* o(static_cast<send_to_op_base*>(base)); - - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(o->buffers_); - - for (;;) - { - // Send the data. - asio::error_code ec; - int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(), - o->flags_, o->destination_.data(), o->destination_.size(), ec); - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - ConstBufferSequence buffers_; - endpoint_type destination_; - socket_base::message_flags flags_; - }; - - template <typename ConstBufferSequence, typename Handler> - class send_to_op : public send_to_op_base<ConstBufferSequence> - { - public: - send_to_op(socket_type socket, const ConstBufferSequence& buffers, - const endpoint_type& endpoint, socket_base::message_flags flags, - Handler handler) - : send_to_op_base<ConstBufferSequence>(socket, - buffers, endpoint, flags, &send_to_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - send_to_op* o(static_cast<send_to_op*>(base)); - typedef handler_alloc_traits<Handler, send_to_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> @@ -863,235 +196,31 @@ public: Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef send_to_op<ConstBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, - buffers, destination, flags, handler); + typedef reactive_socket_sendto_op<ConstBufferSequence, + endpoint_type, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); - start_op(impl, reactor::write_op, ptr.get(), true, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, true, false); + p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template <typename Handler> void async_send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, Handler handler) + const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); - } - - // Receive some data from the peer. Returns the number of bytes received. - template <typename MutableBufferSequence> - size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = asio::error_code(); - return 0; - } - - // Receive some data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_recvd = socket_ops::recv(impl.socket_, - bufs.buffers(), bufs.count(), flags, ec); - - // Check if operation succeeded. - if (bytes_recvd > 0) - return bytes_recvd; - - // Check for EOF. - if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != asio::error::would_block - && ec != asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return 0; - } - } - - // Wait until data can be received without blocking. - size_t receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, ec); + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - return 0; - } - - template <typename MutableBufferSequence> - class receive_op_base : public reactor_op - { - public: - receive_op_base(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&receive_op_base::do_perform, complete_func), - socket_(socket), - protocol_type_(protocol_type), - buffers_(buffers), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - receive_op_base* o(static_cast<receive_op_base*>(base)); - - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(o->buffers_); - - for (;;) - { - // Receive some data. - asio::error_code ec; - int bytes = socket_ops::recv(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, ec); - if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) - ec = asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - int protocol_type_; - MutableBufferSequence buffers_; - socket_base::message_flags flags_; - }; - - template <typename MutableBufferSequence, typename Handler> - class receive_op : public receive_op_base<MutableBufferSequence> - { - public: - receive_op(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : receive_op_base<MutableBufferSequence>(socket, - protocol_type, buffers, flags, &receive_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - receive_op* o(static_cast<receive_op*>(base)); - typedef handler_alloc_traits<Handler, receive_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef receive_op<MutableBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, - protocol_type, buffers, flags, handler); - - start_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get(), (flags & socket_base::message_out_of_band) == 0, - (impl.protocol_.type() == SOCK_STREAM - && buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::all_empty(buffers))); - ptr.release(); - } - - // Wait until data can be received without blocking. - template <typename Handler> - void async_receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - start_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1102,47 +231,18 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); - // Receive some data. - for (;;) - { - // Try to complete the operation without blocking. - std::size_t addr_len = sender_endpoint.capacity(); - int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(), - bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); - // Check if operation succeeded. - if (bytes_recvd > 0) - { - sender_endpoint.resize(addr_len); - return bytes_recvd; - } + if (!ec) + sender_endpoint.resize(addr_len); - // Check for EOF. - if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != asio::error::would_block - && ec != asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return 0; - } + return bytes_recvd; } // Wait until data can be received without blocking. @@ -1150,12 +250,6 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); @@ -1165,105 +259,6 @@ public: return 0; } - template <typename MutableBufferSequence> - class receive_from_op_base : public reactor_op - { - public: - receive_from_op_base(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&receive_from_op_base::do_perform, complete_func), - socket_(socket), - protocol_type_(protocol_type), - buffers_(buffers), - sender_endpoint_(endpoint), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - receive_from_op_base* o(static_cast<receive_from_op_base*>(base)); - - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(o->buffers_); - - for (;;) - { - // Receive some data. - asio::error_code ec; - std::size_t addr_len = o->sender_endpoint_.capacity(); - int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(), - bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec); - if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) - ec = asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - - o->sender_endpoint_.resize(addr_len); - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - int protocol_type_; - MutableBufferSequence buffers_; - endpoint_type& sender_endpoint_; - socket_base::message_flags flags_; - }; - - template <typename MutableBufferSequence, typename Handler> - class receive_from_op : public receive_from_op_base<MutableBufferSequence> - { - public: - receive_from_op(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : receive_from_op_base<MutableBufferSequence>(socket, protocol_type, - buffers, endpoint, flags, &receive_from_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - receive_from_op* o(static_cast<receive_from_op*>(base)); - typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1273,18 +268,20 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_from_op<MutableBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); + typedef reactive_socket_recvfrom_op<MutableBufferSequence, + endpoint_type, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; int protocol_type = impl.protocol_.type(); - handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, - protocol_type, buffers, sender_endpoint, flags, handler); + p.p = new (p.v) op(impl.socket_, protocol_type, + buffers, sender_endpoint, flags, handler); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), true, false); - ptr.release(); + p.p, true, false); + p.v = p.p = 0; } // Wait until data can be received without blocking. @@ -1294,10 +291,11 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -1305,8 +303,8 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), false, false); - ptr.release(); + p.p, false, false); + p.v = p.p = 0; } // Accept a new connection. @@ -1314,12 +312,6 @@ public: asio::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - // We cannot accept a socket that is already open. if (peer.is_open()) { @@ -1327,181 +319,22 @@ public: return ec; } - // Accept a socket. - for (;;) - { - // Try to complete the operation without blocking. - socket_holder new_socket; - std::size_t addr_len = 0; - if (peer_endpoint) - { - addr_len = peer_endpoint->capacity(); - new_socket.reset(socket_ops::accept(impl.socket_, - peer_endpoint->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); - } - - // Check if operation succeeded. - if (new_socket.get() >= 0) - { - if (peer_endpoint) - peer_endpoint->resize(addr_len); - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - return ec; - } + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); - // Operation failed. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - { - if (impl.flags_ & implementation_type::user_set_non_blocking) - return ec; - // Fall through to retry operation. - } - else if (ec == asio::error::connection_aborted) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - return ec; - // Fall through to retry operation. - } -#if defined(EPROTO) - else if (ec.value() == EPROTO) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - return ec; - // Fall through to retry operation. - } -#endif // defined(EPROTO) - else - return ec; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return ec; - } - } - - template <typename Socket> - class accept_op_base : public reactor_op - { - public: - accept_op_base(socket_type socket, Socket& peer, - const protocol_type& protocol, endpoint_type* peer_endpoint, - bool enable_connection_aborted, func_type complete_func) - : reactor_op(&accept_op_base::do_perform, complete_func), - socket_(socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted) - { - } - - static bool do_perform(reactor_op* base) + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) { - accept_op_base* o(static_cast<accept_op_base*>(base)); - - for (;;) - { - // Accept the waiting connection. - asio::error_code ec; - socket_holder new_socket; - std::size_t addr_len = 0; - std::size_t* addr_len_p = 0; - socket_addr_type* addr = 0; - if (o->peer_endpoint_) - { - addr_len = o->peer_endpoint_->capacity(); - addr_len_p = &addr_len; - addr = o->peer_endpoint_->data(); - } - new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec)); - - // Retry operation if interrupted by signal. - if (ec == asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == asio::error::would_block - || ec == asio::error::try_again) - return false; - if (ec == asio::error::connection_aborted - && !o->enable_connection_aborted_) - return false; -#if defined(EPROTO) - if (ec.value() == EPROTO && !o->enable_connection_aborted_) - return false; -#endif // defined(EPROTO) - - // Transfer ownership of the new socket to the peer object. - if (!ec) - { - if (o->peer_endpoint_) - o->peer_endpoint_->resize(addr_len); - o->peer_.assign(o->protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - } - - o->ec_ = ec; - return true; - } - } - - private: - socket_type socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type* peer_endpoint_; - bool enable_connection_aborted_; - }; - - template <typename Socket, typename Handler> - class accept_op : public accept_op_base<Socket> - { - public: - accept_op(socket_type socket, Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : accept_op_base<Socket>(socket, peer, protocol, peer_endpoint, - enable_connection_aborted, &accept_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - accept_op* o(static_cast<accept_op*>(base)); - typedef handler_alloc_traits<Handler, accept_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder1<Handler, asio::error_code> - handler(o->handler_, o->ec_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } + if (peer_endpoint) + peer_endpoint->resize(addr_len); + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + new_socket.release(); } - private: - Handler handler_; - }; + return ec; + } // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. @@ -1510,230 +343,41 @@ public: endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef accept_op<Socket, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted) != 0; - handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, peer, - impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + typedef reactive_socket_accept_op<Socket, Protocol, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, peer, + impl.protocol_, peer_endpoint, handler); - start_accept_op(impl, ptr.get(), peer.is_open()); - ptr.release(); + start_accept_op(impl, p.p, peer.is_open()); + p.v = p.p = 0; } // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - // Perform the connect operation. - socket_ops::connect(impl.socket_, + socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); - if (ec != asio::error::in_progress - && ec != asio::error::would_block) - { - // The connect operation finished immediately. - return ec; - } - - // Wait for socket to become ready. - if (socket_ops::poll_connect(impl.socket_, ec) < 0) - return ec; - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) - return ec; - - // Return the result of the connect operation. - ec = asio::error_code(connect_error, - asio::error::get_system_category()); return ec; } - class connect_op_base : public reactor_op - { - public: - connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&connect_op_base::do_perform, complete_func), - socket_(socket) - { - } - - static bool do_perform(reactor_op* base) - { - connect_op_base* o(static_cast<connect_op_base*>(base)); - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, o->ec_) == socket_error_retval) - return true; - - // The connection failed so the handler will be posted with an error code. - if (connect_error) - { - o->ec_ = asio::error_code(connect_error, - asio::error::get_system_category()); - } - - return true; - } - - private: - socket_type socket_; - }; - - template <typename Handler> - class connect_op : public connect_op_base - { - public: - connect_op(socket_type socket, Handler handler) - : connect_op_base(socket, &connect_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - connect_op* o(static_cast<connect_op*>(base)); - typedef handler_alloc_traits<Handler, connect_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder1<Handler, asio::error_code> - handler(o->handler_, o->ec_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous connect. template <typename Handler> void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef connect_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, handler); - - start_connect_op(impl, ptr.get(), peer_endpoint); - ptr.release(); - } - -private: - // Start the asynchronous read or write operation. - void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool non_blocking, bool noop) - { - if (!noop) - { - if (is_open(impl)) - { - if (!non_blocking || is_non_blocking(impl) - || set_non_blocking(impl, op->ec_)) - { - reactor_.start_op(op_type, impl.socket_, - impl.reactor_data_, op, non_blocking); - return; - } - } - else - op->ec_ = asio::error::bad_descriptor; - } + typedef reactive_socket_connect_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); - io_service_impl_.post_immediate_completion(op); + start_connect_op(impl, p.p, peer_endpoint.data(), peer_endpoint.size()); + p.v = p.p = 0; } - - // Start the asynchronous accept operation. - void start_accept_op(implementation_type& impl, - reactor_op* op, bool peer_is_open) - { - if (!peer_is_open) - start_op(impl, reactor::read_op, op, true, false); - else - { - op->ec_ = asio::error::already_open; - io_service_impl_.post_immediate_completion(op); - } - } - - // Start the asynchronous connect operation. - void start_connect_op(implementation_type& impl, - reactor_op* op, const endpoint_type& peer_endpoint) - { - if (is_open(impl)) - { - if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) - { - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), op->ec_) != 0) - { - if (op->ec_ == asio::error::in_progress - || op->ec_ == asio::error::would_block) - { - op->ec_ = asio::error_code(); - reactor_.start_op(reactor::connect_op, - impl.socket_, impl.reactor_data_, op, false); - return; - } - } - } - } - else - op->ec_ = asio::error::bad_descriptor; - - io_service_impl_.post_immediate_completion(op); - } - - // Determine whether the socket has been set non-blocking. - bool is_non_blocking(implementation_type& impl) const - { - return (impl.flags_ & implementation_type::non_blocking); - } - - // Set the internal non-blocking flag. - bool set_non_blocking(implementation_type& impl, - asio::error_code& ec) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return false; - impl.flags_ |= implementation_type::internal_non_blocking; - return true; - } - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; - - // The selector that performs event demultiplexing for the service. - reactor& reactor_; }; } // namespace detail @@ -1741,4 +385,6 @@ private: #include "asio/detail/pop_options.hpp" +#endif // !defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/ext/asio/asio/detail/reactive_socket_service_base.hpp b/ext/asio/asio/detail/reactive_socket_service_base.hpp new file mode 100644 index 0000000000..b26d73e74a --- /dev/null +++ b/ext/asio/asio/detail/reactive_socket_service_base.hpp @@ -0,0 +1,298 @@ +// +// detail/reactive_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) + +#include <boost/utility/addressof.hpp> +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_socket_recv_op.hpp" +#include "asio/detail/reactive_socket_send_op.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + ASIO_DECL reactive_socket_service_base( + asio::io_service& io_service); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown_service(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Get the native socket representation. + native_type native(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast<ioctl_arg_type*>(command.data()), ec); + return ec; + } + + /// Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. + template <typename ConstBufferSequence> + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, flags, handler); + + start_op(impl, reactor::write_op, p.p, true, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, (flags & socket_base::message_out_of_band) == 0, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, false, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + const native_type& native_socket, asio::error_code& ec); + + // Start the asynchronous read or write operation. + ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop); + + // Start the asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + reactor_op* op, bool peer_is_open); + + // Start the asynchronous connect operation. + ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, size_t addrlen); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/ext/asio/asio/detail/reactor.hpp b/ext/asio/asio/detail/reactor.hpp index 98ac360b9e..0e938c9542 100644 --- a/ext/asio/asio/detail/reactor.hpp +++ b/ext/asio/asio/detail/reactor.hpp @@ -1,8 +1,8 @@ // -// reactor.hpp -// ~~~~~~~~~~~ +// detail/reactor.hpp +// ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - #include "asio/detail/reactor_fwd.hpp" #if defined(ASIO_HAS_EPOLL) @@ -29,6 +27,4 @@ # include "asio/detail/select_reactor.hpp" #endif -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_REACTOR_HPP diff --git a/ext/asio/asio/detail/reactor_fwd.hpp b/ext/asio/asio/detail/reactor_fwd.hpp index 9c33be54ca..d45d768289 100644 --- a/ext/asio/asio/detail/reactor_fwd.hpp +++ b/ext/asio/asio/detail/reactor_fwd.hpp @@ -1,8 +1,8 @@ // -// reactor_fwd.hpp -// ~~~~~~~~~~~~~~~ +// detail/reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,19 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/dev_poll_reactor_fwd.hpp" -#include "asio/detail/epoll_reactor_fwd.hpp" -#include "asio/detail/kqueue_reactor_fwd.hpp" -#include "asio/detail/select_reactor_fwd.hpp" -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/select_reactor_fwd.hpp" +#elif defined(ASIO_HAS_EPOLL) +# include "asio/detail/epoll_reactor_fwd.hpp" +#elif defined(ASIO_HAS_KQUEUE) +# include "asio/detail/kqueue_reactor_fwd.hpp" +#elif defined(ASIO_HAS_DEV_POLL) +# include "asio/detail/dev_poll_reactor_fwd.hpp" +#else +# include "asio/detail/select_reactor_fwd.hpp" +#endif namespace asio { namespace detail { #if defined(ASIO_HAS_IOCP) -typedef select_reactor<true> reactor; +typedef select_reactor reactor; #elif defined(ASIO_HAS_EPOLL) typedef epoll_reactor reactor; #elif defined(ASIO_HAS_KQUEUE) @@ -35,12 +41,10 @@ typedef kqueue_reactor reactor; #elif defined(ASIO_HAS_DEV_POLL) typedef dev_poll_reactor reactor; #else -typedef select_reactor<false> reactor; +typedef select_reactor reactor; #endif } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/ext/asio/asio/detail/reactor_op.hpp b/ext/asio/asio/detail/reactor_op.hpp index cd557fa6ae..3009cf9c12 100644 --- a/ext/asio/asio/detail/reactor_op.hpp +++ b/ext/asio/asio/detail/reactor_op.hpp @@ -1,8 +1,8 @@ // -// reactor_op.hpp -// ~~~~~~~~~~~~ +// detail/reactor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/operation.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/reactor_op_queue.hpp b/ext/asio/asio/detail/reactor_op_queue.hpp index 233c0aec16..6eed398997 100644 --- a/ext/asio/asio/detail/reactor_op_queue.hpp +++ b/ext/asio/asio/detail/reactor_op_queue.hpp @@ -1,8 +1,8 @@ // -// reactor_op_queue.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/error.hpp" +#include "asio/detail/config.hpp" #include "asio/detail/hash_map.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/regex_fwd.hpp b/ext/asio/asio/detail/regex_fwd.hpp new file mode 100644 index 0000000000..9da295b26c --- /dev/null +++ b/ext/asio/asio/detail/regex_fwd.hpp @@ -0,0 +1,31 @@ +// +// detail/regex_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REGEX_FWD_HPP +#define ASIO_DETAIL_REGEX_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/regex_fwd.hpp> +#include <boost/regex/v4/match_flags.hpp> + +namespace boost { + +template <class BidiIterator> +struct sub_match; + +template <class BidiIterator, class Allocator> +class match_results; + +} // namespace boost + +#endif // ASIO_DETAIL_REGEX_FWD_HPP diff --git a/ext/asio/asio/detail/resolve_endpoint_op.hpp b/ext/asio/asio/detail/resolve_endpoint_op.hpp new file mode 100644 index 0000000000..0931fd03db --- /dev/null +++ b/ext/asio/asio/detail/resolve_endpoint_op.hpp @@ -0,0 +1,116 @@ +// +// detail/resolve_endpoint_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP +#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/ip/basic_resolver_iterator.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol, typename Handler> +class resolve_endpoint_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef asio::ip::basic_resolver_iterator<Protocol> iterator_type; + + resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, + const endpoint_type& endpoint, io_service_impl& ios, Handler handler) + : operation(&resolve_endpoint_op::do_complete), + cancel_token_(cancel_token), + endpoint_(endpoint), + io_service_impl_(ios), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + if (owner && owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to perform + // the resolver operation. + + // Perform the blocking endpoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), + o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, + o->endpoint_.protocol().type(), o->ec_); + o->iter_ = iterator_type::create(o->endpoint_, host_name, service_name); + + // Pass operation back to main io_service for completion. + o->io_service_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_service. The completion + // handler is ready to be delivered. + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // a sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + detail::binder2<Handler, asio::error_code, iterator_type> + handler(o->handler_, o->ec_, o->iter_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + endpoint_type endpoint_; + io_service_impl& io_service_impl_; + Handler handler_; + asio::error_code ec_; + iterator_type iter_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP diff --git a/ext/asio/asio/detail/resolve_op.hpp b/ext/asio/asio/detail/resolve_op.hpp new file mode 100644 index 0000000000..a04fbc3b52 --- /dev/null +++ b/ext/asio/asio/detail/resolve_op.hpp @@ -0,0 +1,126 @@ +// +// detail/resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVE_OP_HPP +#define ASIO_DETAIL_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/ip/basic_resolver_iterator.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol, typename Handler> +class resolve_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(resolve_op); + + typedef asio::ip::basic_resolver_query<Protocol> query_type; + typedef asio::ip::basic_resolver_iterator<Protocol> iterator_type; + + resolve_op(socket_ops::weak_cancel_token_type cancel_token, + const query_type& query, io_service_impl& ios, Handler handler) + : operation(&resolve_op::do_complete), + cancel_token_(cancel_token), + query_(query), + io_service_impl_(ios), + handler_(handler), + addrinfo_(0) + { + } + + ~resolve_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_op* o(static_cast<resolve_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + if (owner && owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to perform + // the resolver operation. + + // Perform the blocking host resolution operation. + socket_ops::background_getaddrinfo(o->cancel_token_, + o->query_.host_name().c_str(), o->query_.service_name().c_str(), + o->query_.hints(), &o->addrinfo_, o->ec_); + + // Pass operation back to main io_service for completion. + o->io_service_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_service. The completion + // handler is ready to be delivered. + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // a sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + detail::binder2<Handler, asio::error_code, iterator_type> + handler(o->handler_, o->ec_, iterator_type()); + p.h = boost::addressof(handler.handler_); + if (o->addrinfo_) + { + handler.arg2_ = iterator_type::create(o->addrinfo_, + o->query_.host_name(), o->query_.service_name()); + } + p.reset(); + + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + query_type query_; + io_service_impl& io_service_impl_; + Handler handler_; + asio::error_code ec_; + asio::detail::addrinfo_type* addrinfo_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVE_OP_HPP diff --git a/ext/asio/asio/detail/resolver_service.hpp b/ext/asio/asio/detail/resolver_service.hpp index 562dc10476..c2c3b0c98a 100644 --- a/ext/asio/asio/detail/resolver_service.hpp +++ b/ext/asio/asio/detail/resolver_service.hpp @@ -1,8 +1,8 @@ // -// resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,68 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <cstring> -#include <boost/scoped_ptr.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/weak_ptr.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/io_service.hpp" +#include "asio/detail/config.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" -#include "asio/detail/bind_handler.hpp" -#include "asio/detail/fenced_block.hpp" -#include "asio/detail/mutex.hpp" -#include "asio/detail/noncopyable.hpp" -#include "asio/detail/operation.hpp" -#include "asio/detail/service_base.hpp" -#include "asio/detail/socket_ops.hpp" -#include "asio/detail/socket_types.hpp" -#include "asio/detail/thread.hpp" +#include "asio/detail/resolve_endpoint_op.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/resolver_service_base.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { template <typename Protocol> -class resolver_service - : public asio::detail::service_base<resolver_service<Protocol> > +class resolver_service : public resolver_service_base { -private: - // Helper class to perform exception-safe cleanup of addrinfo objects. - class auto_addrinfo - : private asio::detail::noncopyable - { - public: - explicit auto_addrinfo(asio::detail::addrinfo_type* ai) - : ai_(ai) - { - } - - ~auto_addrinfo() - { - if (ai_) - socket_ops::freeaddrinfo(ai_); - } - - operator asio::detail::addrinfo_type*() - { - return ai_; - } - - private: - asio::detail::addrinfo_type* ai_; - }; - public: - // The implementation type of the resolver. The shared pointer is used as a - // cancellation token to indicate to the background thread that the operation - // has been cancelled. - typedef boost::shared_ptr<void> implementation_type; - struct noop_deleter { void operator()(void*) {} }; + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; @@ -89,55 +46,8 @@ public: // Constructor. resolver_service(asio::io_service& io_service) - : asio::detail::service_base< - resolver_service<Protocol> >(io_service), - mutex_(), - io_service_impl_(asio::use_service<io_service_impl>(io_service)), - work_io_service_(new asio::io_service), - work_io_service_impl_(asio::use_service< - io_service_impl>(*work_io_service_)), - work_(new asio::io_service::work(*work_io_service_)), - work_thread_(0) - { - } - - // Destructor. - ~resolver_service() + : resolver_service_base(io_service) { - shutdown_service(); - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - work_.reset(); - if (work_io_service_) - { - work_io_service_->stop(); - if (work_thread_) - { - work_thread_->join(); - work_thread_.reset(); - } - work_io_service_.reset(); - } - } - - // Construct a new resolver implementation. - void construct(implementation_type& impl) - { - impl.reset(static_cast<void*>(0), noop_deleter()); - } - - // Destroy a resolver implementation. - void destroy(implementation_type&) - { - } - - // Cancel pending asynchronous operations. - void cancel(implementation_type& impl) - { - impl.reset(static_cast<void*>(0), noop_deleter()); } // Resolve a query to a list of entries. @@ -145,293 +55,60 @@ public: asio::error_code& ec) { asio::detail::addrinfo_type* address_info = 0; - std::string host_name = query.host_name(); - std::string service_name = query.service_name(); - asio::detail::addrinfo_type hints = query.hints(); - socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, ec); + socket_ops::getaddrinfo(query.host_name().c_str(), + query.service_name().c_str(), query.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); - if (ec) - return iterator_type(); - - return iterator_type::create(address_info, host_name, service_name); + return ec ? iterator_type() : iterator_type::create( + address_info, query.host_name(), query.service_name()); } - template <typename Handler> - class resolve_op - : public operation - { - public: - resolve_op(implementation_type impl, const query_type& query, - io_service_impl& io_service_impl, Handler handler) - : operation(&resolve_op::do_complete), - impl_(impl), - query_(query), - io_service_impl_(io_service_impl), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_op* o(static_cast<resolve_op*>(base)); - typedef handler_alloc_traits<Handler, resolve_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - if (owner) - { - if (owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to - // perform the resolver operation. - - if (o->impl_.expired()) - { - // THe operation has been cancelled. - o->ec_ = asio::error::operation_aborted; - } - else - { - // Perform the blocking host resolution operation. - asio::detail::addrinfo_type* address_info = 0; - std::string host_name = o->query_.host_name(); - std::string service_name = o->query_.service_name(); - asio::detail::addrinfo_type hints = o->query_.hints(); - socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, o->ec_); - auto_addrinfo auto_address_info(address_info); - o->iter_ = iterator_type::create( - address_info, host_name, service_name); - } - - o->io_service_impl_.post_deferred_completion(o); - ptr.release(); - } - else - { - // The operation has been returned to the main io_serice. The - // completion handler is ready to be delivered. - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object - // remains valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, iterator_type> - handler(o->handler_, o->ec_, o->iter_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - } - - private: - boost::weak_ptr<void> impl_; - query_type query_; - io_service_impl& io_service_impl_; - Handler handler_; - asio::error_code ec_; - iterator_type iter_; - }; - // Asynchronously resolve a query to a list of entries. template <typename Handler> void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, - impl, query, io_service_impl_, handler); - - if (work_io_service_) - { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(ptr.get()); - ptr.release(); - } + typedef resolve_op<Protocol, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl, query, io_service_impl_, handler); + + start_resolve_op(p.p); + p.v = p.p = 0; } // Resolve an endpoint to a list of entries. iterator_type resolve(implementation_type&, const endpoint_type& endpoint, asio::error_code& ec) { - // First try resolving with the service name. If that fails try resolving - // but allow the service to be returned as a number. char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; - int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - if (ec) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - } + socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, + endpoint.protocol().type(), ec); - if (ec) - return iterator_type(); - - return iterator_type::create(endpoint, host_name, service_name); + return ec ? iterator_type() : iterator_type::create( + endpoint, host_name, service_name); } - template <typename Handler> - class resolve_endpoint_op - : public operation - { - public: - resolve_endpoint_op(implementation_type impl, const endpoint_type& ep, - io_service_impl& io_service_impl, Handler handler) - : operation(&resolve_endpoint_op::do_complete), - impl_(impl), - ep_(ep), - io_service_impl_(io_service_impl), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base)); - typedef handler_alloc_traits<Handler, resolve_endpoint_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - if (owner) - { - if (owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to - // perform the resolver operation. - - if (o->impl_.expired()) - { - // THe operation has been cancelled. - o->ec_ = asio::error::operation_aborted; - } - else - { - // Perform the blocking endoint resolution operation. - char host_name[NI_MAXHOST]; - char service_name[NI_MAXSERV]; - int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), - host_name, NI_MAXHOST, service_name, - NI_MAXSERV, flags, o->ec_); - if (o->ec_) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), - host_name, NI_MAXHOST, service_name, - NI_MAXSERV, flags, o->ec_); - } - o->iter_ = iterator_type::create(o->ep_, host_name, service_name); - } - - o->io_service_impl_.post_deferred_completion(o); - ptr.release(); - } - else - { - // The operation has been returned to the main io_serice. The - // completion handler is ready to be delivered. - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object - // remains valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, iterator_type> - handler(o->handler_, o->ec_, o->iter_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - } - - private: - boost::weak_ptr<void> impl_; - endpoint_type ep_; - io_service_impl& io_service_impl_; - Handler handler_; - asio::error_code ec_; - iterator_type iter_; - }; - // Asynchronously resolve an endpoint to a list of entries. template <typename Handler> void async_resolve(implementation_type& impl, const endpoint_type& endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_endpoint_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, - impl, endpoint, io_service_impl_, handler); - - if (work_io_service_) - { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(ptr.get()); - ptr.release(); - } - } - -private: - // Helper class to run the work io_service in a thread. - class work_io_service_runner - { - public: - work_io_service_runner(asio::io_service& io_service) - : io_service_(io_service) {} - void operator()() { io_service_.run(); } - private: - asio::io_service& io_service_; - }; - - // Start the work thread if it's not already running. - void start_work_thread() - { - asio::detail::mutex::scoped_lock lock(mutex_); - if (!work_thread_) - { - work_thread_.reset(new asio::detail::thread( - work_io_service_runner(*work_io_service_))); - } + typedef resolve_endpoint_op<Protocol, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler); + + start_resolve_op(p.p); + p.v = p.p = 0; } - - // Mutex to protect access to internal data. - asio::detail::mutex mutex_; - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; - - // Private io_service used for performing asynchronous host resolution. - boost::scoped_ptr<asio::io_service> work_io_service_; - - // The work io_service implementation used to post completions. - io_service_impl& work_io_service_impl_; - - // Work for the private io_service to perform. - boost::scoped_ptr<asio::io_service::work> work_; - - // Thread used for running the work io_service's run loop. - boost::scoped_ptr<asio::detail::thread> work_thread_; }; } // namespace detail diff --git a/ext/asio/asio/detail/resolver_service_base.hpp b/ext/asio/asio/detail/resolver_service_base.hpp new file mode 100644 index 0000000000..d6f20bdb70 --- /dev/null +++ b/ext/asio/asio/detail/resolver_service_base.hpp @@ -0,0 +1,123 @@ +// +// detail/resolver_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP +#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/scoped_ptr.hpp> +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/thread.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // Constructor. + ASIO_DECL resolver_service_base(asio::io_service& io_service); + + // Destructor. + ASIO_DECL ~resolver_service_base(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown_service(); + + // Construct a new resolver implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Destroy a resolver implementation. + ASIO_DECL void destroy(implementation_type&); + + // Cancel pending asynchronous operations. + ASIO_DECL void cancel(implementation_type& impl); + +protected: + // Helper function to start an asynchronous resolve operation. + ASIO_DECL void start_resolve_op(operation* op); + + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private asio::detail::noncopyable + { + public: + explicit auto_addrinfo(asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + asio::detail::addrinfo_type* ai_; + }; + + // Helper class to run the work io_service in a thread. + class work_io_service_runner; + + // Start the work thread if it's not already running. + ASIO_DECL void start_work_thread(); + + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + +private: + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // Private io_service used for performing asynchronous host resolution. + boost::scoped_ptr<asio::io_service> work_io_service_; + + // The work io_service implementation used to post completions. + io_service_impl& work_io_service_impl_; + + // Work for the private io_service to perform. + boost::scoped_ptr<asio::io_service::work> work_; + + // Thread used for running the work io_service's run loop. + boost::scoped_ptr<asio::detail::thread> work_thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/resolver_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP diff --git a/ext/asio/asio/detail/scoped_lock.hpp b/ext/asio/asio/detail/scoped_lock.hpp index e6f6ba59a0..69b572530b 100644 --- a/ext/asio/asio/detail/scoped_lock.hpp +++ b/ext/asio/asio/detail/scoped_lock.hpp @@ -1,8 +1,8 @@ // -// scoped_lock.hpp -// ~~~~~~~~~~~~~~~ +// detail/scoped_lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - #include "asio/detail/noncopyable.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/select_interrupter.hpp b/ext/asio/asio/detail/select_interrupter.hpp index ff5505bebc..e975ddca00 100644 --- a/ext/asio/asio/detail/select_interrupter.hpp +++ b/ext/asio/asio/detail/select_interrupter.hpp @@ -1,8 +1,8 @@ // -// select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include "asio/detail/socket_select_interrupter.hpp" -#else +#elif defined(ASIO_HAS_EVENTFD) # include "asio/detail/eventfd_select_interrupter.hpp" +#else # include "asio/detail/pipe_select_interrupter.hpp" #endif namespace asio { namespace detail { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) typedef socket_select_interrupter select_interrupter; #elif defined(ASIO_HAS_EVENTFD) typedef eventfd_select_interrupter select_interrupter; @@ -42,6 +39,4 @@ typedef pipe_select_interrupter select_interrupter; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/ext/asio/asio/detail/select_reactor.hpp b/ext/asio/asio/detail/select_reactor.hpp index 798611b281..161305f8c7 100644 --- a/ext/asio/asio/detail/select_reactor.hpp +++ b/ext/asio/asio/detail/select_reactor.hpp @@ -1,8 +1,8 @@ // -// select_reactor.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,41 +15,38 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/socket_types.hpp" // Must come before posix_time. +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE)) -#include "asio/detail/push_options.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/io_service.hpp" -#include "asio/detail/bind_handler.hpp" -#include "asio/detail/fd_set_adapter.hpp" #include "asio/detail/mutex.hpp" -#include "asio/detail/noncopyable.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/select_reactor_fwd.hpp" -#include "asio/detail/service_base.hpp" -#include "asio/detail/signal_blocker.hpp" -#include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" -#include "asio/detail/thread.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" +#include "asio/io_service.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/thread.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <bool Own_Thread> class select_reactor - : public asio::detail::service_base<select_reactor<Own_Thread> > + : public asio::detail::service_base<select_reactor> { public: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -66,280 +63,91 @@ public: }; // Constructor. - select_reactor(asio::io_service& io_service) - : asio::detail::service_base< - select_reactor<Own_Thread> >(io_service), - io_service_(use_service<io_service_impl>(io_service)), - mutex_(), - interrupter_(), - stop_thread_(false), - thread_(0), - shutdown_(false) - { - if (Own_Thread) - { - asio::detail::signal_blocker sb; - thread_ = new asio::detail::thread( - bind_handler(&select_reactor::call_run_thread, this)); - } - } + ASIO_DECL select_reactor(asio::io_service& io_service); // Destructor. - ~select_reactor() - { - shutdown_service(); - } + ASIO_DECL ~select_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - stop_thread_ = true; - lock.unlock(); - - if (Own_Thread) - { - if (thread_) - { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; - } - } - - op_queue<operation> ops; - - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); - - timer_queues_.get_all_timers(ops); - } + ASIO_DECL void shutdown_service(); // Initialise the task, but only if the reactor is not in its own thread. - void init_task() - { - io_service_.init_task(); - } + ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data&) + ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool) - { - asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); - if (first) - interrupter_.interrupt(); - } - } + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) - { - asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, asio::error::operation_aborted); - } + ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, asio::error::operation_aborted); - } + ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data&); // Add a new timer queue to the reactor. template <typename Time_Traits> - void add_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> - void remove_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> - void schedule_timer(timer_queue<Time_Traits>& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupter_.interrupt(); - } - } + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template <typename Time_Traits> - std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token) - { - asio::detail::mutex::scoped_lock lock(mutex_); - op_queue<operation> ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer); // Run select once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue<operation>& ops) - { - asio::detail::mutex::scoped_lock lock(mutex_); - - // Check if the thread is supposed to stop. - if (Own_Thread) - if (stop_thread_) - return; - - // Set up the descriptor sets. - fd_set_adapter fds[max_select_ops]; - fds[read_op].set(interrupter_.read_descriptor()); - socket_type max_fd = 0; - bool have_work_to_do = !timer_queues_.all_empty(); - for (int i = 0; i < max_select_ops; ++i) - { - have_work_to_do = have_work_to_do || !op_queue_[i].empty(); - op_queue_[i].get_descriptors(fds[i], ops); - if (fds[i].max_descriptor() > max_fd) - max_fd = fds[i].max_descriptor(); - } - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Connection operations on Windows use both except and write fd_sets. - have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); - op_queue_[connect_op].get_descriptors(fds[write_op], ops); - if (fds[write_op].max_descriptor() > max_fd) - max_fd = fds[write_op].max_descriptor(); - op_queue_[connect_op].get_descriptors(fds[except_op], ops); - if (fds[except_op].max_descriptor() > max_fd) - max_fd = fds[except_op].max_descriptor(); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && !have_work_to_do) - return; - - // Determine how long to block while waiting for events. - timeval tv_buf = { 0, 0 }; - timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; - - lock.unlock(); - - // Block on the select call until descriptors become ready. - asio::error_code ec; - int retval = socket_ops::select(static_cast<int>(max_fd + 1), - fds[read_op], fds[write_op], fds[except_op], tv, ec); - - // Reset the interrupter. - if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) - interrupter_.reset(); - - lock.lock(); - - // Dispatch all ready operations. - if (retval > 0) - { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Connection operations on Windows use both except and write fd_sets. - op_queue_[connect_op].perform_operations_for_descriptors( - fds[except_op], ops); - op_queue_[connect_op].perform_operations_for_descriptors( - fds[write_op], ops); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - for (int i = max_select_ops - 1; i >= 0; --i) - op_queue_[i].perform_operations_for_descriptors(fds[i], ops); - } - timer_queues_.get_ready_timers(ops); - } + ASIO_DECL void run(bool block, op_queue<operation>& ops); // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } + ASIO_DECL void interrupt(); private: +#if defined(ASIO_HAS_IOCP) // Run the select loop in the thread. - void run_thread() - { - if (Own_Thread) - { - asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - op_queue<operation> ops; - run(true, ops); - io_service_.post_deferred_completions(ops); - lock.lock(); - } - } - } + ASIO_DECL void run_thread(); // Entry point for the select loop thread. - static void call_run_thread(select_reactor* reactor) - { - if (Own_Thread) - { - reactor->run_thread(); - } - } + ASIO_DECL static void call_run_thread(select_reactor* reactor); +#endif // defined(ASIO_HAS_IOCP) + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the select call. - timeval* get_timeout(timeval& tv) - { - // By default we will wait no longer than 5 minutes. This will ensure that - // any changes to the system clock are detected after no longer than this. - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - tv.tv_sec = usec / 1000000; - tv.tv_usec = usec % 1000000; - return &tv; - } + ASIO_DECL timeval* get_timeout(timeval& tv); // Cancel all operations associated with the given descriptor. This function // does not acquire the select_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const asio::error_code& ec) - { - bool need_interrupt = false; - op_queue<operation> ops; - for (int i = 0; i < max_ops; ++i) - need_interrupt = op_queue_[i].cancel_operations( - descriptor, ops, ec) || need_interrupt; - io_service_.post_deferred_completions(ops); - if (need_interrupt) - interrupter_.interrupt(); - } + ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -356,11 +164,13 @@ private: // The timer queues. timer_queue_set timer_queues_; +#if defined(ASIO_HAS_IOCP) // Does the reactor loop thread need to stop. bool stop_thread_; // The thread that is running the reactor loop. asio::detail::thread* thread_; +#endif // defined(ASIO_HAS_IOCP) // Whether the service has been shut down. bool shutdown_; @@ -371,4 +181,14 @@ private: #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/select_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/select_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE)) + #endif // ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/ext/asio/asio/detail/select_reactor_fwd.hpp b/ext/asio/asio/detail/select_reactor_fwd.hpp index 0b72e7e8aa..04e5ecdcac 100644 --- a/ext/asio/asio/detail/select_reactor_fwd.hpp +++ b/ext/asio/asio/detail/select_reactor_fwd.hpp @@ -1,8 +1,8 @@ // -// select_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/select_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { namespace detail { -template <bool Own_Thread> class select_reactor; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP diff --git a/ext/asio/asio/detail/service_registry.hpp b/ext/asio/asio/detail/service_registry.hpp index f80b4b6953..34b946d19b 100644 --- a/ext/asio/asio/detail/service_registry.hpp +++ b/ext/asio/asio/detail/service_registry.hpp @@ -1,8 +1,8 @@ // -// service_registry.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <typeinfo> -#include "asio/detail/pop_options.hpp" - -#include "asio/io_service.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" -#include "asio/detail/service_id.hpp" +#include "asio/io_service.hpp" #if defined(BOOST_NO_TYPEID) # if !defined(ASIO_NO_TYPEID) @@ -32,6 +27,8 @@ # endif // !defined(ASIO_NO_TYPEID) #endif // defined(BOOST_NO_TYPEID) +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -55,98 +52,43 @@ class service_registry { public: // Constructor. - service_registry(asio::io_service& o) - : owner_(o), - first_service_(0) - { - } + ASIO_DECL service_registry(asio::io_service& o); // Destructor. - ~service_registry() - { - // Shutdown all services. This must be done in a separate loop before the - // services are destroyed since the destructors of user-defined handler - // objects may try to access other service objects. - asio::io_service::service* service = first_service_; - while (service) - { - service->shutdown_service(); - service = service->next_; - } - - // Destroy all services. - while (first_service_) - { - asio::io_service::service* next_service = first_service_->next_; - destroy(first_service_); - first_service_ = next_service; - } - } + ASIO_DECL ~service_registry(); // Get the service object corresponding to the specified service type. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. template <typename Service> - Service& use_service() - { - asio::io_service::service::key key; - init_key(key, Service::id); - factory_type factory = &service_registry::create<Service>; - return *static_cast<Service*>(do_use_service(key, factory)); - } + Service& use_service(); - // Add a service object. Returns false on error, in which case ownership of - // the object is retained by the caller. + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. template <typename Service> - bool add_service(Service* new_service) - { - asio::io_service::service::key key; - init_key(key, Service::id); - return do_add_service(key, new_service); - } + void add_service(Service* new_service); // Check whether a service object of the specified type already exists. template <typename Service> - bool has_service() const - { - asio::io_service::service::key key; - init_key(key, Service::id); - return do_has_service(key); - } + bool has_service() const; private: // Initialise a service's key based on its id. - void init_key(asio::io_service::service::key& key, - const asio::io_service::id& id) - { - key.type_info_ = 0; - key.id_ = &id; - } + ASIO_DECL static void init_key( + asio::io_service::service::key& key, + const asio::io_service::id& id); #if !defined(ASIO_NO_TYPEID) // Initialise a service's key based on its id. template <typename Service> - void init_key(asio::io_service::service::key& key, - const asio::detail::service_id<Service>& /*id*/) - { - key.type_info_ = &typeid(typeid_wrapper<Service>); - key.id_ = 0; - } + static void init_key(asio::io_service::service::key& key, + const asio::detail::service_id<Service>& /*id*/); #endif // !defined(ASIO_NO_TYPEID) // Check if a service matches the given id. - static bool keys_match( + ASIO_DECL static bool keys_match( const asio::io_service::service::key& key1, - const asio::io_service::service::key& key2) - { - if (key1.id_ && key2.id_) - if (key1.id_ == key2.id_) - return true; - if (key1.type_info_ && key2.type_info_) - if (*key1.type_info_ == *key2.type_info_) - return true; - return false; - } + const asio::io_service::service::key& key2); // The type of a factory function used for creating a service instance. typedef asio::io_service::service* @@ -155,18 +97,15 @@ private: // Factory function for creating a service instance. template <typename Service> static asio::io_service::service* create( - asio::io_service& owner) - { - return new Service(owner); - } + asio::io_service& owner); // Destroy a service instance. - static void destroy(asio::io_service::service* service) - { - delete service; - } + ASIO_DECL static void destroy( + asio::io_service::service* service); // Helper class to manage service pointers. + struct auto_service_ptr; + friend struct auto_service_ptr; struct auto_service_ptr { asio::io_service::service* ptr_; @@ -176,86 +115,19 @@ private: // Get the service object corresponding to the specified service key. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. - asio::io_service::service* do_use_service( + ASIO_DECL asio::io_service::service* do_use_service( const asio::io_service::service::key& key, - factory_type factory) - { - asio::detail::mutex::scoped_lock lock(mutex_); - - // First see if there is an existing service object with the given key. - asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return service; - service = service->next_; - } - - // Create a new service object. The service registry's mutex is not locked - // at this time to allow for nested calls into this function from the new - // service's constructor. - lock.unlock(); - auto_service_ptr new_service = { factory(owner_) }; - new_service.ptr_->key_ = key; - lock.lock(); - - // Check that nobody else created another service object of the same type - // while the lock was released. - service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return service; - service = service->next_; - } - - // Service was successfully initialised, pass ownership to registry. - new_service.ptr_->next_ = first_service_; - first_service_ = new_service.ptr_; - new_service.ptr_ = 0; - return first_service_; - } + factory_type factory); // Add a service object. Returns false on error, in which case ownership of // the object is retained by the caller. - bool do_add_service( + ASIO_DECL void do_add_service( const asio::io_service::service::key& key, - asio::io_service::service* new_service) - { - asio::detail::mutex::scoped_lock lock(mutex_); - - // Check if there is an existing service object with the given key. - asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return false; - service = service->next_; - } - - // Take ownership of the service object. - new_service->key_ = key; - new_service->next_ = first_service_; - first_service_ = new_service; - - return true; - } + asio::io_service::service* new_service); // Check whether a service object with the specified key already exists. - bool do_has_service(const asio::io_service::service::key& key) const - { - asio::detail::mutex::scoped_lock lock(mutex_); - - asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return true; - service = service->next_; - } - - return false; - } + ASIO_DECL bool do_has_service( + const asio::io_service::service::key& key) const; // Mutex to protect access to internal data. mutable asio::detail::mutex mutex_; @@ -272,4 +144,9 @@ private: #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/service_registry.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/service_registry.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/ext/asio/asio/detail/service_registry_fwd.hpp b/ext/asio/asio/detail/service_registry_fwd.hpp index 423bb4beef..4108c1a100 100644 --- a/ext/asio/asio/detail/service_registry_fwd.hpp +++ b/ext/asio/asio/detail/service_registry_fwd.hpp @@ -1,8 +1,8 @@ // -// service_registry_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/service_registry_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { namespace detail { @@ -25,6 +23,4 @@ class service_registry; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP diff --git a/ext/asio/asio/detail/shared_ptr.hpp b/ext/asio/asio/detail/shared_ptr.hpp new file mode 100644 index 0000000000..cd496f5d1f --- /dev/null +++ b/ext/asio/asio/detail/shared_ptr.hpp @@ -0,0 +1,38 @@ +// +// detail/shared_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SHARED_PTR_HPP +#define ASIO_DETAIL_SHARED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# include <memory> +#else +# include <boost/shared_ptr.hpp> +#endif + +namespace asio { +namespace detail { + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +using std::shared_ptr; +#else +using boost::shared_ptr; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_SHARED_PTR_HPP diff --git a/ext/asio/asio/detail/signal_blocker.hpp b/ext/asio/asio/detail/signal_blocker.hpp index 52f70c8578..89f45ca1dc 100644 --- a/ext/asio/asio/detail/signal_blocker.hpp +++ b/ext/asio/asio/detail/signal_blocker.hpp @@ -1,8 +1,8 @@ // -// signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \ + || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include "asio/detail/null_signal_blocker.hpp" -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# include "asio/detail/win_signal_blocker.hpp" #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_signal_blocker.hpp" #else @@ -34,10 +29,9 @@ namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \ + || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) typedef null_signal_blocker signal_blocker; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -typedef win_signal_blocker signal_blocker; #elif defined(BOOST_HAS_PTHREADS) typedef posix_signal_blocker signal_blocker; #endif @@ -45,6 +39,4 @@ typedef posix_signal_blocker signal_blocker; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/ext/asio/asio/detail/signal_init.hpp b/ext/asio/asio/detail/signal_init.hpp index 12f17d37ac..80925f6978 100644 --- a/ext/asio/asio/detail/signal_init.hpp +++ b/ext/asio/asio/detail/signal_init.hpp @@ -1,8 +1,8 @@ // -// signal_init.hpp -// ~~~~~~~~~~~~~~~ +// detail/signal_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include "asio/detail/push_options.hpp" #include <csignal> -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -44,8 +40,8 @@ public: } // namespace detail } // namespace asio -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/ext/asio/asio/detail/socket_holder.hpp b/ext/asio/asio/detail/socket_holder.hpp index 82a38848a5..cb401759d0 100644 --- a/ext/asio/asio/detail/socket_holder.hpp +++ b/ext/asio/asio/detail/socket_holder.hpp @@ -1,8 +1,8 @@ // -// socket_holder.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_holder.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_ops.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -46,7 +47,8 @@ public: if (socket_ != invalid_socket) { asio::error_code ec; - socket_ops::close(socket_, ec); + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); } } @@ -62,7 +64,8 @@ public: if (socket_ != invalid_socket) { asio::error_code ec; - socket_ops::close(socket_, ec); + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); socket_ = invalid_socket; } } diff --git a/ext/asio/asio/detail/socket_ops.hpp b/ext/asio/asio/detail/socket_ops.hpp index 1a863a9175..8ad464c909 100644 --- a/ext/asio/asio/detail/socket_ops.hpp +++ b/ext/asio/asio/detail/socket_ops.hpp @@ -1,8 +1,8 @@ // -// socket_ops.hpp -// ~~~~~~~~~~~~~~ +// detail/socket_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,193 +15,102 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <boost/assert.hpp> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <cerrno> -#include <boost/detail/workaround.hpp> -#include <new> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/shared_ptr.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/weak_ptr.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace socket_ops { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -struct msghdr { int msg_namelen; }; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +// Socket state bits. +enum +{ + // The user wants a non-blocking socket. + user_set_non_blocking = 1, -#if defined(__hpux) -// HP-UX doesn't declare these functions extern "C", so they are declared again -// here to avoid linker errors about undefined symbols. -extern "C" char* if_indextoname(unsigned int, char*); -extern "C" unsigned int if_nametoindex(const char*); -#endif // defined(__hpux) + // The socket has been set non-blocking. + internal_non_blocking = 2, -inline void clear_error(asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - WSASetLastError(0); -#else - errno = 0; -#endif - ec = asio::error_code(); -} - -template <typename ReturnType> -inline ReturnType error_wrapper(ReturnType return_value, - asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - ec = asio::error_code(WSAGetLastError(), - asio::error::get_system_category()); -#else - ec = asio::error_code(errno, - asio::error::get_system_category()); -#endif - return return_value; -} - -template <typename SockLenType> -inline socket_type call_accept(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; - socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); - if (addrlen) - *addrlen = (std::size_t)tmp_addrlen; - return result; -} - -inline socket_type accept(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, asio::error_code& ec) -{ - clear_error(ec); - - socket_type new_s = error_wrapper(call_accept( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (new_s == invalid_socket) - return new_s; - -#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - int optval = 1; - int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); - if (result != 0) - { - ::close(new_s); - return invalid_socket; - } -#endif - - clear_error(ec); - return new_s; -} - -template <typename SockLenType> -inline int call_bind(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) -{ - return ::bind(s, addr, (SockLenType)addrlen); -} + // Helper "state" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, -inline int bind(socket_type s, const socket_addr_type* addr, - std::size_t addrlen, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_bind( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} - -inline int close(socket_type s, asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::closesocket(s), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::close(s), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - clear_error(ec); - return result; -} + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, -inline int shutdown(socket_type s, int what, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::shutdown(s, what), ec); - if (result == 0) - clear_error(ec); - return result; -} - -template <typename SockLenType> -inline int call_connect(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) -{ - return ::connect(s, addr, (SockLenType)addrlen); -} + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8, -inline int connect(socket_type s, const socket_addr_type* addr, - std::size_t addrlen, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_connect( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} - -inline int socketpair(int af, int type, int protocol, - socket_type sv[2], asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(af); - (void)(type); - (void)(protocol); - (void)(sv); - ec = asio::error::operation_not_supported; - return -1; -#else - clear_error(ec); - int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); - if (result == 0) - clear_error(ec); - return result; -#endif -} - -inline int listen(socket_type s, int backlog, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::listen(s, backlog), ec); - if (result == 0) - clear_error(ec); - return result; -} - -inline void init_buf_iov_base(void*& base, void* addr) -{ - base = addr; -} + // The socket is stream-oriented. + stream_oriented = 16, -template <typename T> -inline void init_buf_iov_base(T& base, void* addr) -{ - base = static_cast<T>(addr); -} + // The socket is datagram-oriented. + datagram_oriented = 32 +}; + +typedef unsigned char state_type; + +struct noop_deleter { void operator()(void*) {} }; +typedef shared_ptr<void> shared_cancel_token_type; +typedef weak_ptr<void> weak_cancel_token_type; + +ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL socket_type sync_accept(socket_type s, + state_type state, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, socket_type& new_socket); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL int close(socket_type s, state_type& state, + bool destruction, asio::error_code& ec); + +ASIO_DECL bool set_internal_non_blocking(socket_type s, + state_type& state, asio::error_code& ec); + +ASIO_DECL int shutdown(socket_type s, + int what, asio::error_code& ec); + +ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL bool non_blocking_connect( + socket_type s, asio::error_code& ec); + +ASIO_DECL int socketpair(int af, int type, int protocol, + socket_type sv[2], asio::error_code& ec); + +ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec); + +ASIO_DECL size_t available(socket_type s, asio::error_code& ec); + +ASIO_DECL int listen(socket_type s, + int backlog, asio::error_code& ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF buf; @@ -209,1699 +118,163 @@ typedef WSABUF buf; typedef iovec buf; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -inline void init_buf(buf& b, void* data, size_t size) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.buf = static_cast<char*>(data); - b.len = static_cast<u_long>(size); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - init_buf_iov_base(b.iov_base, data); - b.iov_len = size; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL void init_buf(buf& b, void* data, size_t size); -inline void init_buf(buf& b, const void* data, size_t size) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.buf = static_cast<char*>(const_cast<void*>(data)); - b.len = static_cast<u_long>(size); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - init_buf_iov_base(b.iov_base, const_cast<void*>(data)); - b.iov_len = size; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL void init_buf(buf& b, const void* data, size_t size); -inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) -{ - name = addr; -} +ASIO_DECL int recv(socket_type s, buf* bufs, size_t count, int flags, + asio::error_code& ec); -inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) -{ - name = const_cast<socket_addr_type*>(addr); -} +ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec); -template <typename T> -inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) -{ - name = reinterpret_cast<T>(addr); -} +#if defined(ASIO_HAS_IOCP) -template <typename T> -inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) -{ - name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr)); -} +ASIO_DECL void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + asio::error_code& ec, size_t bytes_transferred); -inline int recv(socket_type s, buf* bufs, size_t count, int flags, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Receive some data. - DWORD recv_buf_count = static_cast<DWORD>(count); - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - msg.msg_iov = bufs; - msg.msg_iovlen = count; - int result = error_wrapper(::recvmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) -inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, +ASIO_DECL int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Receive some data. - DWORD recv_buf_count = static_cast<DWORD>(count); - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int tmp_addrlen = (int)*addrlen; - int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); - *addrlen = (std::size_t)tmp_addrlen; - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - init_msghdr_msg_name(msg.msg_name, addr); - msg.msg_namelen = *addrlen; - msg.msg_iov = bufs; - msg.msg_iovlen = count; - int result = error_wrapper(::recvmsg(s, &msg, flags), ec); - *addrlen = msg.msg_namelen; - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} + asio::error_code& ec); -inline int send(socket_type s, const buf* bufs, size_t count, int flags, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Send the data. - DWORD send_buf_count = static_cast<DWORD>(count); - DWORD bytes_transferred = 0; - DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - msg.msg_iov = const_cast<buf*>(bufs); - msg.msg_iovlen = count; -#if defined(__linux__) - flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - int result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, + buf* bufs, size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL int send(socket_type s, const buf* bufs, + size_t count, int flags, asio::error_code& ec); + +ASIO_DECL size_t sync_send(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, + bool all_empty, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) -inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, +ASIO_DECL bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL int sendto(socket_type s, const buf* bufs, size_t count, + int flags, const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec); + +ASIO_DECL size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +#if !defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Send the data. - DWORD send_buf_count = static_cast<DWORD>(count); - DWORD bytes_transferred = 0; - int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs), - send_buf_count, &bytes_transferred, flags, addr, - static_cast<int>(addrlen), 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - init_msghdr_msg_name(msg.msg_name, addr); - msg.msg_namelen = addrlen; - msg.msg_iov = const_cast<buf*>(bufs); - msg.msg_iovlen = count; -#if defined(__linux__) - flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - int result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} + asio::error_code& ec, size_t& bytes_transferred); -inline socket_type socket(int af, int type, int protocol, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED), ec); - if (s == invalid_socket) - return s; - - if (af == AF_INET6) - { - // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to - // false. This will only succeed on Windows Vista and later versions of - // Windows, where a dual-stack IPv4/v6 implementation is available. - DWORD optval = 0; - ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast<const char*>(&optval), sizeof(optval)); - } - - clear_error(ec); - - return s; -#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type s = error_wrapper(::socket(af, type, protocol), ec); - if (s == invalid_socket) - return s; - - int optval = 1; - int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); - if (result != 0) - { - ::close(s); - return invalid_socket; - } - - return s; -#else - int s = error_wrapper(::socket(af, type, protocol), ec); - if (s >= 0) - clear_error(ec); - return s; -#endif -} - -template <typename SockLenType> -inline int call_setsockopt(SockLenType msghdr::*, - socket_type s, int level, int optname, - const void* optval, std::size_t optlen) -{ - return ::setsockopt(s, level, optname, - (const char*)optval, (SockLenType)optlen); -} +#endif // !defined(ASIO_HAS_IOCP) -inline int setsockopt(socket_type s, int level, int optname, - const void* optval, std::size_t optlen, asio::error_code& ec) -{ - if (level == custom_socket_option_level && optname == always_fail_option) - { - ec = asio::error::invalid_argument; - return -1; - } - -#if defined(__BORLANDC__) - // Mysteriously, using the getsockopt and setsockopt functions directly with - // Borland C++ results in incorrect values being set and read. The bug can be - // worked around by using function addresses resolved with GetProcAddress. - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); - if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) - { - clear_error(ec); - return error_wrapper(sso(s, level, optname, - reinterpret_cast<const char*>(optval), - static_cast<int>(optlen)), ec); - } - } - ec = asio::error::fault; - return -1; -#else // defined(__BORLANDC__) - clear_error(ec); - int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); - if (result == 0) - clear_error(ec); - return result; -#endif // defined(__BORLANDC__) -} - -template <typename SockLenType> -inline int call_getsockopt(SockLenType msghdr::*, - socket_type s, int level, int optname, - void* optval, std::size_t* optlen) -{ - SockLenType tmp_optlen = (SockLenType)*optlen; - int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); - *optlen = (std::size_t)tmp_optlen; - return result; -} - -inline int getsockopt(socket_type s, int level, int optname, void* optval, - size_t* optlen, asio::error_code& ec) -{ - if (level == custom_socket_option_level && optname == always_fail_option) - { - ec = asio::error::invalid_argument; - return -1; - } - -#if defined(__BORLANDC__) - // Mysteriously, using the getsockopt and setsockopt functions directly with - // Borland C++ results in incorrect values being set and read. The bug can be - // worked around by using function addresses resolved with GetProcAddress. - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); - if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) - { - clear_error(ec); - int tmp_optlen = static_cast<int>(*optlen); - int result = error_wrapper(gso(s, level, optname, - reinterpret_cast<char*>(optval), &tmp_optlen), ec); - *optlen = static_cast<size_t>(tmp_optlen); - if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY - && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) - { - // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are - // only supported on Windows Vista and later. To simplify program logic - // we will fake success of getting this option and specify that the - // value is non-zero (i.e. true). This corresponds to the behavior of - // IPv6 sockets on Windows platforms pre-Vista. - *static_cast<DWORD*>(optval) = 1; - clear_error(ec); - } - return result; - } - } - ec = asio::error::fault; - return -1; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); - if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY - && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) - { - // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only - // supported on Windows Vista and later. To simplify program logic we will - // fake success of getting this option and specify that the value is - // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets - // on Windows platforms pre-Vista. - *static_cast<DWORD*>(optval) = 1; - clear_error(ec); - } - if (result == 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); -#if defined(__linux__) - if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) - && (optname == SO_SNDBUF || optname == SO_RCVBUF)) - { - // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel - // to set the buffer size to N*2. Linux puts additional stuff into the - // buffers so that only about half is actually available to the application. - // The retrieved value is divided by 2 here to make it appear as though the - // correct value has been set. - *static_cast<int*>(optval) /= 2; - } -#endif // defined(__linux__) - if (result == 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL socket_type socket(int af, int type, int protocol, + asio::error_code& ec); -template <typename SockLenType> -inline int call_getpeername(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getpeername(s, addr, &tmp_addrlen); - *addrlen = (std::size_t)tmp_addrlen; - return result; -} - -inline int getpeername(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_getpeername( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} - -template <typename SockLenType> -inline int call_getsockname(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getsockname(s, addr, &tmp_addrlen); - *addrlen = (std::size_t)tmp_addrlen; - return result; -} - -inline int getsockname(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_getsockname( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} - -inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, cmd, arg), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (result >= 0) - clear_error(ec); - return result; -} +ASIO_DECL int setsockopt(socket_type s, state_type& state, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec); -inline int select(int nfds, fd_set* readfds, fd_set* writefds, - fd_set* exceptfds, timeval* timeout, asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (!readfds && !writefds && !exceptfds && timeout) - { - DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; - if (milliseconds == 0) - milliseconds = 1; // Force context switch. - ::Sleep(milliseconds); - ec = asio::error_code(); - return 0; - } - - // The select() call allows timeout values measured in microseconds, but the - // system clock (as wrapped by boost::posix_time::microsec_clock) typically - // has a resolution of 10 milliseconds. This can lead to a spinning select - // reactor, meaning increased CPU usage, when waiting for the earliest - // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight - // spin we'll use a minimum timeout of 1 millisecond. - if (timeout && timeout->tv_sec == 0 - && timeout->tv_usec > 0 && timeout->tv_usec < 1000) - timeout->tv_usec = 1000; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +ASIO_DECL int getsockopt(socket_type s, state_type state, + int level, int optname, void* optval, + size_t* optlen, asio::error_code& ec); -#if defined(__hpux) && defined(__HP_aCC) - timespec ts; - ts.tv_sec = timeout ? timeout->tv_sec : 0; - ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; - return error_wrapper(::pselect(nfds, readfds, - writefds, exceptfds, timeout ? &ts : 0, 0), ec); -#else - int result = error_wrapper(::select(nfds, readfds, - writefds, exceptfds, timeout), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif -} - -inline int poll_read(socket_type s, asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET fds; - FD_ZERO(&fds); - FD_SET(s, &fds); - clear_error(ec); - int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLIN; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, asio::error_code& ec); -inline int poll_write(socket_type s, asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET fds; - FD_ZERO(&fds); - FD_SET(s, &fds); - clear_error(ec); - int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); -inline int poll_connect(socket_type s, asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET write_fds; - FD_ZERO(&write_fds); - FD_SET(s, &write_fds); - FD_SET except_fds; - FD_ZERO(&except_fds); - FD_SET(s, &except_fds); - clear_error(ec); - int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL int ioctl(socket_type s, state_type& state, + int cmd, ioctl_arg_type* arg, asio::error_code& ec); -inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, - unsigned long scope_id, asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - using namespace std; // For memcpy. - - if (af != AF_INET && af != AF_INET6) - { - ec = asio::error::address_family_not_supported; - return 0; - } - - union - { - socket_addr_type base; - sockaddr_storage_type storage; - sockaddr_in4_type v4; - sockaddr_in6_type v6; - } address; - DWORD address_length; - if (af == AF_INET) - { - address_length = sizeof(sockaddr_in4_type); - address.v4.sin_family = AF_INET; - address.v4.sin_port = 0; - memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); - } - else // AF_INET6 - { - address_length = sizeof(sockaddr_in6_type); - address.v6.sin6_family = AF_INET6; - address.v6.sin6_port = 0; - address.v6.sin6_flowinfo = 0; - address.v6.sin6_scope_id = scope_id; - memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); - } - - DWORD string_length = static_cast<DWORD>(length); -#if defined(BOOST_NO_ANSI_APIS) - LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); - int result = error_wrapper(::WSAAddressToStringW(&address.base, - address_length, 0, string_buffer, &string_length), ec); - ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); -#else - int result = error_wrapper(::WSAAddressToStringA( - &address.base, address_length, 0, dest, &string_length), ec); -#endif - - // Windows may set error code on success. - if (result != socket_error_retval) - clear_error(ec); - - // Windows may not set an error code on failure. - else if (result == socket_error_retval && !ec) - ec = asio::error::invalid_argument; - - return result == socket_error_retval ? 0 : dest; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); - if (result == 0 && !ec) - ec = asio::error::invalid_argument; - if (result != 0 && af == AF_INET6 && scope_id != 0) - { - using namespace std; // For strcat and sprintf. - char if_name[IF_NAMESIZE + 1] = "%"; - const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); - bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); - if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) - sprintf(if_name + 1, "%lu", scope_id); - strcat(dest, if_name); - } - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, asio::error_code& ec); -inline int inet_pton(int af, const char* src, void* dest, - unsigned long* scope_id, asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - using namespace std; // For memcpy and strcmp. - - if (af != AF_INET && af != AF_INET6) - { - ec = asio::error::address_family_not_supported; - return -1; - } - - union - { - socket_addr_type base; - sockaddr_storage_type storage; - sockaddr_in4_type v4; - sockaddr_in6_type v6; - } address; - int address_length = sizeof(sockaddr_storage_type); -#if defined(BOOST_NO_ANSI_APIS) - int num_wide_chars = strlen(src) + 1; - LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); - ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); - int result = error_wrapper(::WSAStringToAddressW( - wide_buffer, af, 0, &address.base, &address_length), ec); -#else - int result = error_wrapper(::WSAStringToAddressA( - const_cast<char*>(src), af, 0, &address.base, &address_length), ec); -#endif - - if (af == AF_INET) - { - if (result != socket_error_retval) - { - memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); - clear_error(ec); - } - else if (strcmp(src, "255.255.255.255") == 0) - { - static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; - clear_error(ec); - } - } - else // AF_INET6 - { - if (result != socket_error_retval) - { - memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); - if (scope_id) - *scope_id = address.v6.sin6_scope_id; - clear_error(ec); - } - } - - // Windows may not set an error code on failure. - if (result == socket_error_retval && !ec) - ec = asio::error::invalid_argument; - - if (result != socket_error_retval) - clear_error(ec); - - return result == socket_error_retval ? -1 : 1; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::inet_pton(af, src, dest), ec); - if (result <= 0 && !ec) - ec = asio::error::invalid_argument; - if (result > 0 && af == AF_INET6 && scope_id) - { - using namespace std; // For strchr and atoi. - *scope_id = 0; - if (const char* if_name = strchr(src, '%')) - { - in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest); - bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); - if (is_link_local) - *scope_id = if_nametoindex(if_name + 1); - if (*scope_id == 0) - *scope_id = atoi(if_name + 1); - } - } - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +ASIO_DECL int poll_read(socket_type s, asio::error_code& ec); -inline int gethostname(char* name, int namelen, asio::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::gethostname(name, namelen), ec); -#if defined(BOOST_WINDOWS) - if (result == 0) - clear_error(ec); -#endif - return result; -} - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ - || defined(__MACH__) && defined(__APPLE__) - -// The following functions are only needed for emulation of getaddrinfo and -// getnameinfo. - -inline asio::error_code translate_netdb_error(int error) -{ - switch (error) - { - case 0: - return asio::error_code(); - case HOST_NOT_FOUND: - return asio::error::host_not_found; - case TRY_AGAIN: - return asio::error::host_not_found_try_again; - case NO_RECOVERY: - return asio::error::no_recovery; - case NO_DATA: - return asio::error::no_data; - default: - BOOST_ASSERT(false); - return asio::error::invalid_argument; - } -} - -inline hostent* gethostbyaddr(const char* addr, int length, int af, - hostent* result, char* buffer, int buflength, asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(buffer); - (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); - if (!retval) - return 0; - clear_error(ec); - *result = *retval; - return retval; -#elif defined(__sun) || defined(__QNX__) - int error = 0; - hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#elif defined(__MACH__) && defined(__APPLE__) - (void)(buffer); - (void)(buflength); - int error = 0; - hostent* retval = error_wrapper(::getipnodebyaddr( - addr, length, af, &error), ec); - if (error) - ec = translate_netdb_error(error); - if (!retval) - return 0; - *result = *retval; - return retval; -#else - hostent* retval = 0; - int error = 0; - error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#endif -} - -inline hostent* gethostbyname(const char* name, int af, struct hostent* result, - char* buffer, int buflength, int ai_flags, asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(buffer); - (void)(buflength); - (void)(ai_flags); - if (af != AF_INET) - { - ec = asio::error::address_family_not_supported; - return 0; - } - hostent* retval = error_wrapper(::gethostbyname(name), ec); - if (!retval) - return 0; - clear_error(ec); - *result = *retval; - return result; -#elif defined(__sun) || defined(__QNX__) - (void)(ai_flags); - if (af != AF_INET) - { - ec = asio::error::address_family_not_supported; - return 0; - } - int error = 0; - hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#elif defined(__MACH__) && defined(__APPLE__) - (void)(buffer); - (void)(buflength); - int error = 0; - hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, &error), ec); - if (error) - ec = translate_netdb_error(error); - if (!retval) - return 0; - *result = *retval; - return retval; -#else - (void)(ai_flags); - if (af != AF_INET) - { - ec = asio::error::address_family_not_supported; - return 0; - } - hostent* retval = 0; - int error = 0; - error_wrapper(::gethostbyname_r(name, result, - buffer, buflength, &retval, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#endif -} - -inline void freehostent(hostent* h) -{ -#if defined(__MACH__) && defined(__APPLE__) - if (h) - ::freehostent(h); -#else - (void)(h); -#endif -} - -// Emulation of getaddrinfo based on implementation in: -// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. - -struct gai_search -{ - const char* host; - int family; -}; +ASIO_DECL int poll_write(socket_type s, asio::error_code& ec); -inline int gai_nsearch(const char* host, - const addrinfo_type* hints, gai_search (&search)[2]) -{ - int search_count = 0; - if (host == 0 || host[0] == '\0') - { - if (hints->ai_flags & AI_PASSIVE) - { - // No host and AI_PASSIVE implies wildcard bind. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = "0.0.0.0"; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = "0::0"; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = "0::0"; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = "0.0.0.0"; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - else - { - // No host and not AI_PASSIVE means connect to local host. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = "localhost"; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - } - else - { - // Host is specified. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = host; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = host; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = host; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = host; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - return search_count; -} - -template <typename T> -inline T* gai_alloc(std::size_t size = sizeof(T)) -{ - using namespace std; - T* p = static_cast<T*>(::operator new(size, std::nothrow)); - if (p) - memset(p, 0, size); - return p; -} - -inline void gai_free(void* p) -{ - ::operator delete(p); -} +ASIO_DECL int poll_connect(socket_type s, asio::error_code& ec); -inline void gai_strcpy(char* target, const char* source, std::size_t max_size) -{ - using namespace std; -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - strcpy_s(target, max_size, source); -#else - *target = 0; - strncat(target, source, max_size); -#endif -} - -enum { gai_clone_flag = 1 << 30 }; - -inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, - const void* addr, int family) -{ - using namespace std; - - addrinfo_type* ai = gai_alloc<addrinfo_type>(); - if (ai == 0) - return EAI_MEMORY; - - ai->ai_next = 0; - **next = ai; - *next = &ai->ai_next; - - ai->ai_canonname = 0; - ai->ai_socktype = hints->ai_socktype; - if (ai->ai_socktype == 0) - ai->ai_flags |= gai_clone_flag; - ai->ai_protocol = hints->ai_protocol; - ai->ai_family = family; - - switch (ai->ai_family) - { - case AF_INET: - { - sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>(); - if (sinptr == 0) - return EAI_MEMORY; - sinptr->sin_family = AF_INET; - memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); - ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr); - ai->ai_addrlen = sizeof(sockaddr_in4_type); - break; - } - case AF_INET6: - { - sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>(); - if (sin6ptr == 0) - return EAI_MEMORY; - sin6ptr->sin6_family = AF_INET6; - memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); - ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr); - ai->ai_addrlen = sizeof(sockaddr_in6_type); - break; - } - default: - break; - } - - return 0; -} - -inline addrinfo_type* gai_clone(addrinfo_type* ai) -{ - using namespace std; +ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, + size_t length, unsigned long scope_id, asio::error_code& ec); - addrinfo_type* new_ai = gai_alloc<addrinfo_type>(); - if (new_ai == 0) - return new_ai; +ASIO_DECL int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, asio::error_code& ec); - new_ai->ai_next = ai->ai_next; - ai->ai_next = new_ai; +ASIO_DECL int gethostname(char* name, + int namelen, asio::error_code& ec); - new_ai->ai_flags = 0; - new_ai->ai_family = ai->ai_family; - new_ai->ai_socktype = ai->ai_socktype; - new_ai->ai_protocol = ai->ai_protocol; - new_ai->ai_canonname = 0; - new_ai->ai_addrlen = ai->ai_addrlen; - new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen); - memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); +ASIO_DECL asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec); - return new_ai; -} +ASIO_DECL asio::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec); -inline int gai_port(addrinfo_type* aihead, int port, int socktype) -{ - int num_found = 0; - - for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) - { - if (ai->ai_flags & gai_clone_flag) - { - if (ai->ai_socktype != 0) - { - ai = gai_clone(ai); - if (ai == 0) - return -1; - // ai now points to newly cloned entry. - } - } - else if (ai->ai_socktype != socktype) - { - // Ignore if mismatch on socket type. - continue; - } - - ai->ai_socktype = socktype; - - switch (ai->ai_family) - { - case AF_INET: - { - sockaddr_in4_type* sinptr = - reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); - sinptr->sin_port = port; - ++num_found; - break; - } - case AF_INET6: - { - sockaddr_in6_type* sin6ptr = - reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); - sin6ptr->sin6_port = port; - ++num_found; - break; - } - default: - break; - } - } - - return num_found; -} - -inline int gai_serv(addrinfo_type* aihead, - const addrinfo_type* hints, const char* serv) -{ - using namespace std; - - int num_found = 0; - - if ( -#if defined(AI_NUMERICSERV) - (hints->ai_flags & AI_NUMERICSERV) || -#endif - isdigit(serv[0])) - { - int port = htons(atoi(serv)); - if (hints->ai_socktype) - { - // Caller specifies socket type. - int rc = gai_port(aihead, port, hints->ai_socktype); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - else - { - // Caller does not specify socket type. - int rc = gai_port(aihead, port, SOCK_STREAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - rc = gai_port(aihead, port, SOCK_DGRAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - else - { - // Try service name with TCP first, then UDP. - if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) - { - servent* sptr = getservbyname(serv, "tcp"); - if (sptr != 0) - { - int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) - { - servent* sptr = getservbyname(serv, "udp"); - if (sptr != 0) - { - int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - } - - if (num_found == 0) - { - if (hints->ai_socktype == 0) - { - // All calls to getservbyname() failed. - return EAI_NONAME; - } - else - { - // Service not supported for socket type. - return EAI_SERVICE; - } - } - - return 0; -} - -inline int gai_echeck(const char* host, const char* service, - int flags, int family, int socktype, int protocol) -{ - (void)(flags); - (void)(protocol); - - // Host or service must be specified. - if (host == 0 || host[0] == '\0') - if (service == 0 || service[0] == '\0') - return EAI_NONAME; - - // Check combination of family and socket type. - switch (family) - { - case AF_UNSPEC: - break; - case AF_INET: - case AF_INET6: - if (service != 0 && service[0] != '\0') - if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) - return EAI_SOCKTYPE; - break; - default: - return EAI_FAMILY; - } - - return 0; -} - -inline void freeaddrinfo_emulation(addrinfo_type* aihead) -{ - addrinfo_type* ai = aihead; - while (ai) - { - gai_free(ai->ai_addr); - gai_free(ai->ai_canonname); - addrinfo_type* ainext = ai->ai_next; - gai_free(ai); - ai = ainext; - } -} - -inline int getaddrinfo_emulation(const char* host, const char* service, - const addrinfo_type* hintsp, addrinfo_type** result) -{ - // Set up linked list of addrinfo structures. - addrinfo_type* aihead = 0; - addrinfo_type** ainext = &aihead; - char* canon = 0; - - // Supply default hints if not specified by caller. - addrinfo_type hints = addrinfo_type(); - hints.ai_family = AF_UNSPEC; - if (hintsp) - hints = *hintsp; - - // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED - // and AI_ALL flags. -#if defined(AI_V4MAPPED) - if (hints.ai_family != AF_INET6) - hints.ai_flags &= ~AI_V4MAPPED; -#endif -#if defined(AI_ALL) - if (hints.ai_family != AF_INET6) - hints.ai_flags &= ~AI_ALL; -#endif - - // Basic error checking. - int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, - hints.ai_socktype, hints.ai_protocol); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - return rc; - } - - gai_search search[2]; - int search_count = gai_nsearch(host, &hints, search); - for (gai_search* sptr = search; sptr < search + search_count; ++sptr) - { - // Check for IPv4 dotted decimal string. - in4_addr_type inaddr; - asio::error_code ec; - if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) - { - if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return EAI_FAMILY; - } - if (sptr->family == AF_INET) - { - rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return rc; - } - } - continue; - } - - // Check for IPv6 hex string. - in6_addr_type in6addr; - if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) - { - if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return EAI_FAMILY; - } - if (sptr->family == AF_INET6) - { - rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return rc; - } - } - continue; - } - - // Look up hostname. - hostent hent; - char hbuf[8192] = ""; - hostent* hptr = socket_ops::gethostbyname(sptr->host, - sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); - if (hptr == 0) - { - if (search_count == 2) - { - // Failure is OK if there are multiple searches. - continue; - } - freeaddrinfo_emulation(aihead); - gai_free(canon); - if (ec == asio::error::host_not_found) - return EAI_NONAME; - if (ec == asio::error::host_not_found_try_again) - return EAI_AGAIN; - if (ec == asio::error::no_recovery) - return EAI_FAIL; - if (ec == asio::error::no_data) - return EAI_NONAME; - return EAI_NONAME; - } - - // Check for address family mismatch if one was specified. - if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - socket_ops::freehostent(hptr); - return EAI_FAMILY; - } - - // Save canonical name first time. - if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] - && (hints.ai_flags & AI_CANONNAME) && canon == 0) - { - std::size_t canon_len = strlen(hptr->h_name) + 1; - canon = gai_alloc<char>(canon_len); - if (canon == 0) - { - freeaddrinfo_emulation(aihead); - socket_ops::freehostent(hptr); - return EAI_MEMORY; - } - gai_strcpy(canon, hptr->h_name, canon_len); - } - - // Create an addrinfo structure for each returned address. - for (char** ap = hptr->h_addr_list; *ap; ++ap) - { - rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - socket_ops::freehostent(hptr); - return EAI_FAMILY; - } - } - - socket_ops::freehostent(hptr); - } - - // Check if we found anything. - if (aihead == 0) - { - gai_free(canon); - return EAI_NONAME; - } - - // Return canonical name in first entry. - if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) - { - if (canon) - { - aihead->ai_canonname = canon; - canon = 0; - } - else - { - std::size_t canonname_len = strlen(search[0].host) + 1; - aihead->ai_canonname = gai_alloc<char>(canonname_len); - if (aihead->ai_canonname == 0) - { - freeaddrinfo_emulation(aihead); - return EAI_MEMORY; - } - gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); - } - } - gai_free(canon); - - // Process the service name. - if (service != 0 && service[0] != '\0') - { - rc = gai_serv(aihead, &hints, service); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - return rc; - } - } - - // Return result to caller. - *result = aihead; - return 0; -} - -inline asio::error_code getnameinfo_emulation( - const socket_addr_type* sa, std::size_t salen, char* host, - std::size_t hostlen, char* serv, std::size_t servlen, int flags, - asio::error_code& ec) -{ - using namespace std; - - const char* addr; - size_t addr_len; - unsigned short port; - switch (sa->sa_family) - { - case AF_INET: - if (salen != sizeof(sockaddr_in4_type)) - { - return ec = asio::error::invalid_argument; - } - addr = reinterpret_cast<const char*>( - &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr); - addr_len = sizeof(in4_addr_type); - port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port; - break; - case AF_INET6: - if (salen != sizeof(sockaddr_in6_type)) - { - return ec = asio::error::invalid_argument; - } - addr = reinterpret_cast<const char*>( - &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr); - addr_len = sizeof(in6_addr_type); - port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port; - break; - default: - return ec = asio::error::address_family_not_supported; - } - - if (host && hostlen > 0) - { - if (flags & NI_NUMERICHOST) - { - if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) - { - return ec; - } - } - else - { - hostent hent; - char hbuf[8192] = ""; - hostent* hptr = socket_ops::gethostbyaddr(addr, - static_cast<int>(addr_len), sa->sa_family, - &hent, hbuf, sizeof(hbuf), ec); - if (hptr && hptr->h_name && hptr->h_name[0] != '\0') - { - if (flags & NI_NOFQDN) - { - char* dot = strchr(hptr->h_name, '.'); - if (dot) - { - *dot = 0; - } - } - gai_strcpy(host, hptr->h_name, hostlen); - socket_ops::freehostent(hptr); - } - else - { - socket_ops::freehostent(hptr); - if (flags & NI_NAMEREQD) - { - return ec = asio::error::host_not_found; - } - if (socket_ops::inet_ntop(sa->sa_family, - addr, host, hostlen, 0, ec) == 0) - { - return ec; - } - } - } - } - - if (serv && servlen > 0) - { - if (flags & NI_NUMERICSERV) - { - if (servlen < 6) - { - return ec = asio::error::no_buffer_space; - } -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - sprintf_s(serv, servlen, "%u", ntohs(port)); -#else - sprintf(serv, "%u", ntohs(port)); -#endif - } - else - { -#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - ::pthread_mutex_lock(&mutex); -#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); - if (sptr && sptr->s_name && sptr->s_name[0] != '\0') - { - gai_strcpy(serv, sptr->s_name, servlen); - } - else - { - if (servlen < 6) - { - return ec = asio::error::no_buffer_space; - } -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - sprintf_s(serv, servlen, "%u", ntohs(port)); -#else - sprintf(serv, "%u", ntohs(port)); -#endif - } -#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - ::pthread_mutex_unlock(&mutex); -#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - } - } - - clear_error(ec); - return ec; -} +ASIO_DECL void freeaddrinfo(addrinfo_type* ai); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // || defined(__MACH__) && defined(__APPLE__) +ASIO_DECL asio::error_code getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int flags, asio::error_code& ec); -inline asio::error_code translate_addrinfo_error(int error) -{ - switch (error) - { - case 0: - return asio::error_code(); - case EAI_AGAIN: - return asio::error::host_not_found_try_again; - case EAI_BADFLAGS: - return asio::error::invalid_argument; - case EAI_FAIL: - return asio::error::no_recovery; - case EAI_FAMILY: - return asio::error::address_family_not_supported; - case EAI_MEMORY: - return asio::error::no_memory; - case EAI_NONAME: -#if defined(EAI_ADDRFAMILY) - case EAI_ADDRFAMILY: -#endif -#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) - case EAI_NODATA: -#endif - return asio::error::host_not_found; - case EAI_SERVICE: - return asio::error::service_not_found; - case EAI_SOCKTYPE: - return asio::error::socket_type_not_supported; - default: // Possibly the non-portable EAI_SYSTEM. -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return asio::error_code( - WSAGetLastError(), asio::error::get_system_category()); -#else - return asio::error_code( - errno, asio::error::get_system_category()); -#endif - } -} - -inline asio::error_code getaddrinfo(const char* host, - const char* service, const addrinfo_type* hints, addrinfo_type** result, - asio::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - int error = ::getaddrinfo(host, service, hints, result); - return ec = translate_addrinfo_error(error); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *gai_t)(const char*, - const char*, const addrinfo_type*, addrinfo_type**); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) - { - int error = gai(host, service, hints, result); - return ec = translate_addrinfo_error(error); - } - } - int error = getaddrinfo_emulation(host, service, hints, result); - return ec = translate_addrinfo_error(error); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - int error = getaddrinfo_emulation(host, service, hints, result); - return ec = translate_addrinfo_error(error); -#else - int error = ::getaddrinfo(host, service, hints, result); - return ec = translate_addrinfo_error(error); -#endif -} - -inline void freeaddrinfo(addrinfo_type* ai) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - ::freeaddrinfo(ai); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *fai_t)(addrinfo_type*); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) - { - fai(ai); - return; - } - } - freeaddrinfo_emulation(ai); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - freeaddrinfo_emulation(ai); -#else - ::freeaddrinfo(ai); -#endif -} - -inline asio::error_code getnameinfo(const socket_addr_type* addr, - std::size_t addrlen, char* host, std::size_t hostlen, - char* serv, std::size_t servlen, int flags, asio::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - clear_error(ec); - int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen), - host, static_cast<DWORD>(hostlen), - serv, static_cast<DWORD>(servlen), flags); - return ec = translate_addrinfo_error(error); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *gni_t)(const socket_addr_type*, - int, char*, DWORD, char*, DWORD, int); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) - { - clear_error(ec); - int error = gni(addr, static_cast<int>(addrlen), - host, static_cast<DWORD>(hostlen), - serv, static_cast<DWORD>(servlen), flags); - return ec = translate_addrinfo_error(error); - } - } - clear_error(ec); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - using namespace std; // For memcpy. - sockaddr_storage_type tmp_addr; - memcpy(&tmp_addr, addr, addrlen); - tmp_addr.ss_len = addrlen; - addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); - clear_error(ec); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); -#else - clear_error(ec); - int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); - return ec = translate_addrinfo_error(error); -#endif -} - -inline u_long_type network_to_host_long(u_long_type value) -{ - return ntohl(value); -} +ASIO_DECL asio::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec); -inline u_long_type host_to_network_long(u_long_type value) -{ - return htonl(value); -} +ASIO_DECL asio::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec); -inline u_short_type network_to_host_short(u_short_type value) -{ - return ntohs(value); -} +ASIO_DECL u_long_type network_to_host_long(u_long_type value); -inline u_short_type host_to_network_short(u_short_type value) -{ - return htons(value); -} +ASIO_DECL u_long_type host_to_network_long(u_long_type value); + +ASIO_DECL u_short_type network_to_host_short(u_short_type value); + +ASIO_DECL u_short_type host_to_network_short(u_short_type value); } // namespace socket_ops } // namespace detail @@ -1909,4 +282,8 @@ inline u_short_type host_to_network_short(u_short_type value) #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/socket_ops.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/ext/asio/asio/detail/socket_option.hpp b/ext/asio/asio/detail/socket_option.hpp index ac070b7018..c9d789698d 100644 --- a/ext/asio/asio/detail/socket_option.hpp +++ b/ext/asio/asio/detail/socket_option.hpp @@ -1,8 +1,8 @@ // -// socket_option.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <stdexcept> #include <boost/config.hpp> #include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { namespace socket_option { diff --git a/ext/asio/asio/detail/socket_select_interrupter.hpp b/ext/asio/asio/detail/socket_select_interrupter.hpp index 62e1063e30..b05a4ffa2d 100644 --- a/ext/asio/asio/detail/socket_select_interrupter.hpp +++ b/ext/asio/asio/detail/socket_select_interrupter.hpp @@ -1,8 +1,8 @@ // -// socket_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,19 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <cstdlib> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(BOOST_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) -#include "asio/error.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/socket_holder.hpp" -#include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -35,135 +32,16 @@ class socket_select_interrupter { public: // Constructor. - socket_select_interrupter() - { - asio::error_code ec; - socket_holder acceptor(socket_ops::socket( - AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); - if (acceptor.get() == invalid_socket) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - int opt = 1; - socket_ops::setsockopt(acceptor.get(), - SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); - - using namespace std; // For memset. - sockaddr_in4_type addr; - std::size_t addr_len = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - addr.sin_port = 0; - if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, - addr_len, ec) == socket_error_retval) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, - &addr_len, ec) == socket_error_retval) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - // Some broken firewalls on Windows will intermittently cause getsockname to - // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We - // explicitly specify the target address here to work around this problem. - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - if (socket_ops::listen(acceptor.get(), - SOMAXCONN, ec) == socket_error_retval) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - socket_holder client(socket_ops::socket( - AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); - if (client.get() == invalid_socket) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, - addr_len, ec) == socket_error_retval) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); - if (server.get() == invalid_socket) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec)) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - opt = 1; - socket_ops::setsockopt(client.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); - - non_blocking = 1; - if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec)) - { - asio::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - opt = 1; - socket_ops::setsockopt(server.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); - - read_descriptor_ = server.release(); - write_descriptor_ = client.release(); - } + ASIO_DECL socket_select_interrupter(); // Destructor. - ~socket_select_interrupter() - { - asio::error_code ec; - if (read_descriptor_ != invalid_socket) - socket_ops::close(read_descriptor_, ec); - if (write_descriptor_ != invalid_socket) - socket_ops::close(write_descriptor_, ec); - } + ASIO_DECL ~socket_select_interrupter(); // Interrupt the select call. - void interrupt() - { - char byte = 0; - socket_ops::buf b; - socket_ops::init_buf(b, &byte, 1); - asio::error_code ec; - socket_ops::send(write_descriptor_, &b, 1, 0, ec); - } + ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - char data[1024]; - socket_ops::buf b; - socket_ops::init_buf(b, data, sizeof(data)); - asio::error_code ec; - int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - return was_interrupted; - } + ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. socket_type read_descriptor() const @@ -189,4 +67,12 @@ private: #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/socket_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + #endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/ext/asio/asio/detail/socket_types.hpp b/ext/asio/asio/detail/socket_types.hpp index 34b3d3e631..4e29e513ee 100644 --- a/ext/asio/asio/detail/socket_types.hpp +++ b/ext/asio/asio/detail/socket_types.hpp @@ -1,8 +1,8 @@ // -// socket_types.hpp -// ~~~~~~~~~~~~~~~~ +// detail/socket_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,69 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # error WinSock.h has already been included # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) -# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) || defined(__BORLANDC__) -# pragma message( \ - "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ - "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ - "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ - "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") -# else // defined(_MSC_VER) || defined(__BORLANDC__) -# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. -# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. -# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). -# endif // defined(_MSC_VER) || defined(__BORLANDC__) -# define _WIN32_WINNT 0x0501 -# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) -# if defined(_WIN32) && !defined(WIN32) -# if !defined(_WINSOCK2API_) -# define WIN32 // Needed for correct types in winsock2.h -# else // !defined(_WINSOCK2API_) -# error Please define the macro WIN32 in your compiler options -# endif // !defined(_WINSOCK2API_) -# endif // defined(_WIN32) && !defined(WIN32) -# endif // defined(_MSC_VER) # if defined(__BORLANDC__) # include <stdlib.h> // Needed for __errno -# if defined(__WIN32__) && !defined(WIN32) -# if !defined(_WINSOCK2API_) -# define WIN32 // Needed for correct types in winsock2.h -# else // !defined(_WINSOCK2API_) -# error Please define the macro WIN32 in your compiler options -# endif // !defined(_WINSOCK2API_) -# endif // defined(__WIN32__) && !defined(WIN32) # if !defined(_WSPIAPI_H_) # define _WSPIAPI_H_ # define ASIO_WSPIAPI_H_DEFINED # endif // !defined(_WSPIAPI_H_) # endif // defined(__BORLANDC__) -# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) -# if !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -# endif // !defined(WIN32_LEAN_AND_MEAN) -# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) -# if !defined(ASIO_NO_NOMINMAX) -# if !defined(NOMINMAX) -# define NOMINMAX 1 -# endif // !defined(NOMINMAX) -# endif // !defined(ASIO_NO_NOMINMAX) -# if defined(__CYGWIN__) -# if !defined(__USE_W32_SOCKETS) -# error You must add -D__USE_W32_SOCKETS to your compiler options. -# endif // !defined(__USE_W32_SOCKETS) -# endif // defined(__CYGWIN__) # include <winsock2.h> # include <ws2tcpip.h> # include <mswsock.h> @@ -96,18 +46,25 @@ # include "asio/detail/old_win_sdk_compat.hpp" #else # include <sys/ioctl.h> -# include <sys/poll.h> +# if !defined(__SYMBIAN32__) +# include <sys/poll.h> +# endif # include <sys/types.h> -# if defined(__hpux) && !defined(__HP_aCC) +# include <sys/stat.h> +# include <fcntl.h> +# if defined(__hpux) # include <sys/time.h> -# else +# endif +# if !defined(__hpux) || defined(__SELECT) # include <sys/select.h> # endif # include <sys/socket.h> # include <sys/uio.h> # include <sys/un.h> # include <netinet/in.h> -# include <netinet/tcp.h> +# if !defined(__SYMBIAN32__) +# include <netinet/tcp.h> +# endif # include <arpa/inet.h> # include <netdb.h> # include <net/if.h> @@ -117,7 +74,8 @@ # include <sys/sockio.h> # endif #endif -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/solaris_fenced_block.hpp b/ext/asio/asio/detail/solaris_fenced_block.hpp index d337f3b62e..411c824515 100644 --- a/ext/asio/asio/detail/solaris_fenced_block.hpp +++ b/ext/asio/asio/detail/solaris_fenced_block.hpp @@ -1,8 +1,8 @@ // -// solaris_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(__sun) -#include "asio/detail/push_options.hpp" #include <atomic.h> -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -50,8 +46,8 @@ public: } // namespace detail } // namespace asio -#endif // defined(__sun) - #include "asio/detail/pop_options.hpp" +#endif // defined(__sun) + #endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/strand_service.hpp b/ext/asio/asio/detail/strand_service.hpp index ea50f412a1..4885b93ee8 100644 --- a/ext/asio/asio/detail/strand_service.hpp +++ b/ext/asio/asio/detail/strand_service.hpp @@ -1,8 +1,8 @@ // -// strand_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/functional/hash.hpp> +#include "asio/detail/config.hpp" #include <boost/scoped_ptr.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/io_service.hpp" -#include "asio/detail/call_stack.hpp" -#include "asio/detail/completion_handler.hpp" -#include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/operation.hpp" -#include "asio/detail/service_base.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -41,7 +32,10 @@ class strand_service : public asio::detail::service_base<strand_service> { private: + // Helper class to re-post the strand on exit. struct on_do_complete_exit; + + // Helper class to re-post the strand on exit. struct on_dispatch_exit; public: @@ -51,11 +45,7 @@ public: : public operation { public: - strand_impl() - : operation(&strand_service::do_complete), - count_(0) - { - } + strand_impl(); private: // Only this service will have access to the internal values. @@ -76,180 +66,29 @@ public: typedef strand_impl* implementation_type; // Construct a new strand service for the specified io_service. - explicit strand_service(asio::io_service& io_service) - : asio::detail::service_base<strand_service>(io_service), - io_service_(asio::use_service<io_service_impl>(io_service)), - mutex_(), - salt_(0) - { - } + ASIO_DECL explicit strand_service(asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - op_queue<operation> ops; - - asio::detail::mutex::scoped_lock lock(mutex_); - - for (std::size_t i = 0; i < num_implementations; ++i) - if (strand_impl* impl = implementations_[i].get()) - ops.push(impl->queue_); - } + ASIO_DECL void shutdown_service(); // Construct a new strand implementation. - void construct(implementation_type& impl) - { - std::size_t index = boost::hash_value(&impl); - boost::hash_combine(index, salt_++); - index = index % num_implementations; - - asio::detail::mutex::scoped_lock lock(mutex_); - - if (!implementations_[index]) - implementations_[index].reset(new strand_impl); - impl = implementations_[index].get(); - } + ASIO_DECL void construct(implementation_type& impl); // Destroy a strand implementation. - void destroy(implementation_type& impl) - { - impl = 0; - } + void destroy(implementation_type& impl); // Request the io_service to invoke the given handler. template <typename Handler> - void dispatch(implementation_type& impl, Handler handler) - { - // If we are already in the strand then the handler can run immediately. - if (call_stack<strand_impl>::contains(impl)) - { - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - return; - } - - // Allocate and construct an object to wrap the handler. - typedef completion_handler<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - // If we are running inside the io_service, and no other handler is queued - // or running, then the handler can run immediately. - bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_); - impl->mutex_.lock(); - bool first = (++impl->count_ == 1); - if (can_dispatch && first) - { - // Immediate invocation is allowed. - impl->mutex_.unlock(); - - // Memory must be releaesed before any upcall is made. - ptr.reset(); - - // Indicate that this strand is executing on the current thread. - call_stack<strand_impl>::context ctx(impl); - - // Ensure the next handler, if any, is scheduled on block exit. - on_dispatch_exit on_exit = { &io_service_, impl }; - (void)on_exit; - - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - return; - } - - // Immediate invocation is not allowed, so enqueue for later. - impl->queue_.push(ptr.get()); - impl->mutex_.unlock(); - ptr.release(); - - // The first handler to be enqueued is responsible for scheduling the - // strand. - if (first) - io_service_.post_immediate_completion(impl); - } + void dispatch(implementation_type& impl, Handler handler); // Request the io_service to invoke the given handler and return immediately. template <typename Handler> - void post(implementation_type& impl, Handler handler) - { - // Allocate and construct an object to wrap the handler. - typedef completion_handler<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - // Add the handler to the queue. - impl->mutex_.lock(); - bool first = (++impl->count_ == 1); - impl->queue_.push(ptr.get()); - impl->mutex_.unlock(); - ptr.release(); - - // The first handler to be enqueue is responsible for scheduling the strand. - if (first) - io_service_.post_immediate_completion(impl); - } + void post(implementation_type& impl, Handler handler); private: - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - if (owner) - { - strand_impl* impl = static_cast<strand_impl*>(base); - - // Get the next handler to be executed. - impl->mutex_.lock(); - operation* o = impl->queue_.front(); - impl->queue_.pop(); - impl->mutex_.unlock(); - - // Indicate that this strand is executing on the current thread. - call_stack<strand_impl>::context ctx(impl); - - // Ensure the next handler, if any, is scheduled on block exit. - on_do_complete_exit on_exit = { owner, impl }; - (void)on_exit; - - o->complete(*owner); - } - } - - // Helper class to re-post the strand on exit. - struct on_do_complete_exit - { - io_service_impl* owner_; - strand_impl* impl_; - - ~on_do_complete_exit() - { - impl_->mutex_.lock(); - bool more_handlers = (--impl_->count_ > 0); - impl_->mutex_.unlock(); - - if (more_handlers) - owner_->post_immediate_completion(impl_); - } - }; - - // Helper class to re-post the strand on exit. - struct on_dispatch_exit - { - io_service_impl* io_service_; - strand_impl* impl_; - - ~on_dispatch_exit() - { - impl_->mutex_.lock(); - bool more_handlers = (--impl_->count_ > 0); - impl_->mutex_.unlock(); - - if (more_handlers) - io_service_->post_immediate_completion(impl_); - } - }; + ASIO_DECL static void do_complete(io_service_impl* owner, + operation* base, asio::error_code ec, + std::size_t bytes_transferred); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -273,4 +112,9 @@ private: #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/strand_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/strand_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/ext/asio/asio/detail/task_io_service.hpp b/ext/asio/asio/detail/task_io_service.hpp index eb77c1d8de..2d69513b46 100644 --- a/ext/asio/asio/detail/task_io_service.hpp +++ b/ext/asio/asio/detail/task_io_service.hpp @@ -1,8 +1,8 @@ // -// task_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,180 +15,59 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) +#include <boost/detail/atomic_count.hpp> #include "asio/error_code.hpp" #include "asio/io_service.hpp" -#include "asio/detail/call_stack.hpp" -#include "asio/detail/completion_handler.hpp" -#include "asio/detail/event.hpp" -#include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" -#include "asio/detail/service_base.hpp" +#include "asio/detail/reactor_fwd.hpp" #include "asio/detail/task_io_service_fwd.hpp" #include "asio/detail/task_io_service_operation.hpp" #include "asio/detail/push_options.hpp" -#include <boost/detail/atomic_count.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { -template <typename Task> class task_io_service - : public asio::detail::service_base<task_io_service<Task> > + : public asio::detail::service_base<task_io_service> { public: - typedef task_io_service_operation<Task> operation; + typedef task_io_service_operation operation; // Constructor. - task_io_service(asio::io_service& io_service) - : asio::detail::service_base<task_io_service<Task> >(io_service), - mutex_(), - task_(0), - task_interrupted_(true), - outstanding_work_(0), - stopped_(false), - shutdown_(false), - first_idle_thread_(0) - { - } + ASIO_DECL task_io_service(asio::io_service& io_service); - void init(size_t /*concurrency_hint*/) - { - } + // How many concurrent threads are likely to run the io_service. + ASIO_DECL void init(std::size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - // Destroy handler objects. - while (!op_queue_.empty()) - { - operation* o = op_queue_.front(); - op_queue_.pop(); - if (o != &task_operation_) - o->destroy(); - } - - // Reset to initial state. - task_ = 0; - } + ASIO_DECL void shutdown_service(); // Initialise the task, if required. - void init_task() - { - asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_ && !task_) - { - task_ = &use_service<Task>(this->get_io_service()); - op_queue_.push(&task_operation_); - wake_one_thread_and_unlock(lock); - } - } + ASIO_DECL void init_task(); // Run the event loop until interrupted or no more work. - size_t run(asio::error_code& ec) - { - ec = asio::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack<task_io_service>::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - asio::detail::mutex::scoped_lock lock(mutex_); - - size_t n = 0; - for (; do_one(lock, &this_idle_thread); lock.lock()) - if (n != (std::numeric_limits<size_t>::max)()) - ++n; - return n; - } + ASIO_DECL std::size_t run(asio::error_code& ec); // Run until interrupted or one operation is performed. - size_t run_one(asio::error_code& ec) - { - ec = asio::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack<task_io_service>::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - asio::detail::mutex::scoped_lock lock(mutex_); - - return do_one(lock, &this_idle_thread); - } + ASIO_DECL std::size_t run_one(asio::error_code& ec); // Poll for operations without blocking. - size_t poll(asio::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = asio::error_code(); - return 0; - } - - typename call_stack<task_io_service>::context ctx(this); - - asio::detail::mutex::scoped_lock lock(mutex_); - - size_t n = 0; - for (; do_one(lock, 0); lock.lock()) - if (n != (std::numeric_limits<size_t>::max)()) - ++n; - return n; - } + ASIO_DECL std::size_t poll(asio::error_code& ec); // Poll for one operation without blocking. - size_t poll_one(asio::error_code& ec) - { - ec = asio::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack<task_io_service>::context ctx(this); - - asio::detail::mutex::scoped_lock lock(mutex_); - - return do_one(lock, 0); - } + ASIO_DECL std::size_t poll_one(asio::error_code& ec); // Interrupt the event processing loop. - void stop() - { - asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(lock); - } + ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. - void reset() - { - asio::detail::mutex::scoped_lock lock(mutex_); - stopped_ = false; - } + ASIO_DECL void reset(); // Notify that some work has started. void work_started() @@ -205,228 +84,60 @@ public: // Request invocation of the given handler. template <typename Handler> - void dispatch(Handler handler) - { - if (call_stack<task_io_service>::contains(this)) - { - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - else - post(handler); - } + void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template <typename Handler> - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - post_immediate_completion(ptr.get()); - ptr.release(); - } + void post(Handler handler); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. - void post_immediate_completion(operation* op) - { - work_started(); - post_deferred_completion(op); - } + ASIO_DECL void post_immediate_completion(operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. - void post_deferred_completion(operation* op) - { - asio::detail::mutex::scoped_lock lock(mutex_); - op_queue_.push(op); - wake_one_thread_and_unlock(lock); - } + ASIO_DECL void post_deferred_completion(operation* op); // Request invocation of the given operations and return immediately. Assumes // that work_started() was previously called for each operation. - void post_deferred_completions(op_queue<operation>& ops) - { - if (!ops.empty()) - { - asio::detail::mutex::scoped_lock lock(mutex_); - op_queue_.push(ops); - wake_one_thread_and_unlock(lock); - } - } + ASIO_DECL void post_deferred_completions(op_queue<operation>& ops); private: + // Structure containing information about an idle thread. struct idle_thread_info; - size_t do_one(asio::detail::mutex::scoped_lock& lock, - idle_thread_info* this_idle_thread) - { - bool polling = !this_idle_thread; - bool task_has_run = false; - while (!stopped_) - { - if (!op_queue_.empty()) - { - // Prepare to execute first handler from queue. - operation* o = op_queue_.front(); - op_queue_.pop(); - bool more_handlers = (!op_queue_.empty()); - - if (o == &task_operation_) - { - task_interrupted_ = more_handlers || polling; - - // If the task has already run and we're polling then we're done. - if (task_has_run && polling) - { - task_interrupted_ = true; - op_queue_.push(&task_operation_); - return 0; - } - task_has_run = true; - - if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) - lock.unlock(); - - op_queue<operation> completed_ops; - task_cleanup c = { this, &lock, &completed_ops }; - (void)c; - - // Run the task. May throw an exception. Only block if the operation - // queue is empty and we're not polling, otherwise we want to return - // as soon as possible. - task_->run(!more_handlers && !polling, completed_ops); - } - else - { - if (more_handlers) - wake_one_thread_and_unlock(lock); - else - lock.unlock(); - - // Ensure the count of outstanding work is decremented on block exit. - work_finished_on_block_exit on_exit = { this }; - (void)on_exit; - - // Complete the operation. May throw an exception. - o->complete(*this); // deletes the operation object - - return 1; - } - } - else if (this_idle_thread) - { - // Nothing to run right now, so just wait for work to do. - this_idle_thread->next = first_idle_thread_; - first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(lock); - this_idle_thread->wakeup_event.wait(lock); - } - else - { - return 0; - } - } - - return 0; - } + // Run at most one operation. Blocks only if this_idle_thread is non-null. + ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock, + idle_thread_info* this_idle_thread); // Stop the task and all idle threads. - void stop_all_threads( - asio::detail::mutex::scoped_lock& lock) - { - stopped_ = true; - - while (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); - } - - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - } + ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); // Wakes a single idle thread and unlocks the mutex. Returns true if an idle // thread was found. If there is no idle thread, returns false and leaves the // mutex locked. - bool wake_one_idle_thread_and_unlock( - asio::detail::mutex::scoped_lock& lock) - { - if (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal_and_unlock(lock); - return true; - } - return false; - } + ASIO_DECL bool wake_one_idle_thread_and_unlock( + mutex::scoped_lock& lock); // Wake a single idle thread, or the task, and always unlock the mutex. - void wake_one_thread_and_unlock( - asio::detail::mutex::scoped_lock& lock) - { - if (!wake_one_idle_thread_and_unlock(lock)) - { - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - lock.unlock(); - } - } + ASIO_DECL void wake_one_thread_and_unlock( + mutex::scoped_lock& lock); // Helper class to perform task-related operations on block exit. struct task_cleanup; friend struct task_cleanup; - struct task_cleanup - { - ~task_cleanup() - { - // Enqueue the completed operations and reinsert the task at the end of - // the operation queue. - lock_->lock(); - task_io_service_->task_interrupted_ = true; - task_io_service_->op_queue_.push(*ops_); - task_io_service_->op_queue_.push(&task_io_service_->task_operation_); - } - - task_io_service* task_io_service_; - asio::detail::mutex::scoped_lock* lock_; - op_queue<operation>* ops_; - }; // Helper class to call work_finished() on block exit. - struct work_finished_on_block_exit - { - ~work_finished_on_block_exit() - { - task_io_service_->work_finished(); - } - - task_io_service* task_io_service_; - }; + struct work_finished_on_block_exit; // Mutex to protect access to internal data. - asio::detail::mutex mutex_; + mutex mutex_; // The task to be run by this service. - Task* task_; + reactor* task_; // Operation object to represent the position of the task in the queue. - struct task_operation : public operation + struct task_operation : operation { task_operation() : operation(0) {} } task_operation_; @@ -446,13 +157,6 @@ private: // Flag to indicate that the dispatcher has been shut down. bool shutdown_; - // Structure containing information about an idle thread. - struct idle_thread_info - { - event wakeup_event; - idle_thread_info* next; - }; - // The threads that are currently idle. idle_thread_info* first_idle_thread_; }; @@ -462,4 +166,11 @@ private: #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/task_io_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/task_io_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP diff --git a/ext/asio/asio/detail/task_io_service_fwd.hpp b/ext/asio/asio/detail/task_io_service_fwd.hpp index 5b18d1d700..b66cb07907 100644 --- a/ext/asio/asio/detail/task_io_service_fwd.hpp +++ b/ext/asio/asio/detail/task_io_service_fwd.hpp @@ -1,8 +1,8 @@ // -// task_io_service_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { namespace detail { -template <typename Task> class task_io_service; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP diff --git a/ext/asio/asio/detail/task_io_service_operation.hpp b/ext/asio/asio/detail/task_io_service_operation.hpp index 6776f6992f..dd4384a14f 100644 --- a/ext/asio/asio/detail/task_io_service_operation.hpp +++ b/ext/asio/asio/detail/task_io_service_operation.hpp @@ -1,8 +1,8 @@ // -// task_io_service_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,22 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - #include "asio/error_code.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/task_io_service_fwd.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. -template <typename Task> class task_io_service_operation { public: - void complete(task_io_service<Task>& owner) + void complete(task_io_service& owner) { func_(&owner, this, asio::error_code(), 0); } @@ -41,8 +40,9 @@ public: } protected: - typedef void (*func_type)(task_io_service<Task>*, - task_io_service_operation*, asio::error_code, std::size_t); + typedef void (*func_type)(task_io_service*, + task_io_service_operation*, + asio::error_code, std::size_t); task_io_service_operation(func_type func) : next_(0), diff --git a/ext/asio/asio/detail/thread.hpp b/ext/asio/asio/detail/thread.hpp index 3c9280bcd3..7c4103b28e 100644 --- a/ext/asio/asio/detail/thread.hpp +++ b/ext/asio/asio/detail/thread.hpp @@ -1,8 +1,8 @@ // -// thread.hpp -// ~~~~~~~~~~ +// detail/thread.hpp +// ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_thread.hpp" @@ -53,6 +49,4 @@ typedef posix_thread thread; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_THREAD_HPP diff --git a/ext/asio/asio/detail/throw_error.hpp b/ext/asio/asio/detail/throw_error.hpp index 51d6e48f4f..d39aa92958 100644 --- a/ext/asio/asio/detail/throw_error.hpp +++ b/ext/asio/asio/detail/throw_error.hpp @@ -1,8 +1,8 @@ // -// throw_error.hpp -// ~~~~~~~~~~~~~~~ +// detail/throw_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,25 +15,30 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error_code.hpp" -#include "asio/system_error.hpp" namespace asio { namespace detail { +ASIO_DECL void do_throw_error(const asio::error_code& err); + +ASIO_DECL void do_throw_error(const asio::error_code& err, + const char* location); + inline void throw_error(const asio::error_code& err) { if (err) - { - asio::system_error e(err); - boost::throw_exception(e); - } + do_throw_error(err); +} + +inline void throw_error(const asio::error_code& err, + const char* location) +{ + if (err) + do_throw_error(err, location); } } // namespace detail @@ -41,4 +46,8 @@ inline void throw_error(const asio::error_code& err) #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/throw_error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_DETAIL_THROW_ERROR_HPP diff --git a/ext/asio/asio/detail/timer_op.hpp b/ext/asio/asio/detail/timer_op.hpp index bf3c3ae593..62cd292247 100644 --- a/ext/asio/asio/detail/timer_op.hpp +++ b/ext/asio/asio/detail/timer_op.hpp @@ -1,8 +1,8 @@ // -// timer_op.hpp -// ~~~~~~~~~~~~ +// detail/timer_op.hpp +// ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/operation.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/timer_queue.hpp b/ext/asio/asio/detail/timer_queue.hpp index 2e4d2d5d97..514c434e53 100644 --- a/ext/asio/asio/detail/timer_queue.hpp +++ b/ext/asio/asio/detail/timer_queue.hpp @@ -1,8 +1,8 @@ // -// timer_queue.hpp -// ~~~~~~~~~~~~~~~ +// detail/timer_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,21 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <memory> #include <vector> #include <boost/config.hpp> #include <boost/limits.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/detail/hash_map.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" +#include "asio/error.hpp" +#include "asio/time_traits.hpp" + +#include "asio/detail/push_options.hpp" +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -45,6 +46,26 @@ public: // The duration type. typedef typename Time_Traits::duration_type duration_type; + // Per-timer data. + class per_timer_data + { + public: + per_timer_data() : next_(0), prev_(0) {} + + private: + friend class timer_queue; + + // The operations waiting on the timer. + op_queue<timer_op> op_queue_; + + // The index of the timer in the heap. + std::size_t heap_index_; + + // Pointers to adjacent timers in a linked list. + per_timer_data* next_; + per_timer_data* prev_; + }; + // Constructor. timer_queue() : timers_(), @@ -55,35 +76,45 @@ public: // Add a new timer to the queue. Returns true if this is the timer that is // earliest in the queue, in which case the reactor's event demultiplexing // function call may need to be interrupted and restarted. - bool enqueue_timer(const time_type& time, timer_op* op, void* token) + bool enqueue_timer(const time_type& time, per_timer_data& timer, timer_op* op) { - // Ensure that there is space for the timer in the heap. We reserve here so - // that the push_back below will not throw due to a reallocation failure. - heap_.reserve(heap_.size() + 1); - - // Insert the new timer into the hash. - typedef typename hash_map<void*, timer>::iterator iterator; - typedef typename hash_map<void*, timer>::value_type value_type; - std::pair<iterator, bool> result = - timers_.insert(value_type(token, timer())); - result.first->second.op_queue_.push(op); - if (result.second) + // Enqueue the timer object. + if (timer.prev_ == 0 && &timer != timers_) { - // Put the new timer at the correct position in the heap. - result.first->second.time_ = time; - result.first->second.heap_index_ = heap_.size(); - result.first->second.token_ = token; - heap_.push_back(&result.first->second); - up_heap(heap_.size() - 1); + if (this->is_positive_infinity(time)) + { + // No heap entry is required for timers that never expire. + timer.heap_index_ = (std::numeric_limits<std::size_t>::max)(); + } + else + { + // Put the new timer at the correct position in the heap. This is done + // first since push_back() can throw due to allocation failure. + timer.heap_index_ = heap_.size(); + heap_entry entry = { time, &timer }; + heap_.push_back(entry); + up_heap(heap_.size() - 1); + } + + // Insert the new timer into the linked list of active timers. + timer.next_ = timers_; + timer.prev_ = 0; + if (timers_) + timers_->prev_ = &timer; + timers_ = &timer; } - return (heap_[0] == &result.first->second); + // Enqueue the individual timer operation. + timer.op_queue_.push(op); + + // Interrupt reactor only if newly added timer is first to expire. + return timer.heap_index_ == 0 && timer.op_queue_.front() == op; } // Whether there are no timers in the queue. virtual bool empty() const { - return heap_.empty(); + return timers_ == 0; } // Get the time for the timer that is earliest in the queue. @@ -93,12 +124,14 @@ public: return max_duration; boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( - Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())); if (duration > boost::posix_time::milliseconds(max_duration)) duration = boost::posix_time::milliseconds(max_duration); - else if (duration < boost::posix_time::milliseconds(0)) + else if (duration <= boost::posix_time::milliseconds(0)) duration = boost::posix_time::milliseconds(0); + else if (duration < boost::posix_time::milliseconds(1)) + duration = boost::posix_time::milliseconds(1); return duration.total_milliseconds(); } @@ -110,12 +143,14 @@ public: return max_duration; boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( - Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())); if (duration > boost::posix_time::microseconds(max_duration)) duration = boost::posix_time::microseconds(max_duration); - else if (duration < boost::posix_time::microseconds(0)) + else if (duration <= boost::posix_time::microseconds(0)) duration = boost::posix_time::microseconds(0); + else if (duration < boost::posix_time::microseconds(1)) + duration = boost::posix_time::microseconds(1); return duration.total_microseconds(); } @@ -124,77 +159,54 @@ public: virtual void get_ready_timers(op_queue<operation>& ops) { const time_type now = Time_Traits::now(); - while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_)) + while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_)) { - timer* t = heap_[0]; - ops.push(t->op_queue_); - remove_timer(t); + per_timer_data* timer = heap_[0].timer_; + ops.push(timer->op_queue_); + remove_timer(*timer); } } // Dequeue all timers. virtual void get_all_timers(op_queue<operation>& ops) { - typename hash_map<void*, timer>::iterator i = timers_.begin(); - typename hash_map<void*, timer>::iterator end = timers_.end(); - while (i != end) + while (timers_) { - ops.push(i->second.op_queue_); - typename hash_map<void*, timer>::iterator old_i = i++; - timers_.erase(old_i); + per_timer_data* timer = timers_; + timers_ = timers_->next_; + ops.push(timer->op_queue_); + timer->next_ = 0; + timer->prev_ = 0; } heap_.clear(); - timers_.clear(); } // Cancel and dequeue the timers with the given token. - std::size_t cancel_timer(void* timer_token, op_queue<operation>& ops) + std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops) { std::size_t num_cancelled = 0; - typedef typename hash_map<void*, timer>::iterator iterator; - iterator it = timers_.find(timer_token); - if (it != timers_.end()) + if (timer.prev_ != 0 || &timer == timers_) { - while (timer_op* op = it->second.op_queue_.front()) + while (timer_op* op = timer.op_queue_.front()) { op->ec_ = asio::error::operation_aborted; - it->second.op_queue_.pop(); + timer.op_queue_.pop(); ops.push(op); ++num_cancelled; } - remove_timer(&it->second); + remove_timer(timer); } return num_cancelled; } private: - // Structure representing a single outstanding timer. - struct timer - { - timer() {} - timer(const timer&) {} - void operator=(const timer&) {} - - // The time when the timer should fire. - time_type time_; - - // The operations waiting on the timer. - op_queue<timer_op> op_queue_; - - // The index of the timer in the heap. - size_t heap_index_; - - // The token associated with the timer. - void* token_; - }; - // Move the item at the given index up the heap to its correct position. - void up_heap(size_t index) + void up_heap(std::size_t index) { - size_t parent = (index - 1) / 2; + std::size_t parent = (index - 1) / 2; while (index > 0 - && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_)) + && Time_Traits::less_than(heap_[index].time_, heap_[parent].time_)) { swap_heap(index, parent); index = parent; @@ -203,16 +215,16 @@ private: } // Move the item at the given index down the heap to its correct position. - void down_heap(size_t index) + void down_heap(std::size_t index) { - size_t child = index * 2 + 1; + std::size_t child = index * 2 + 1; while (child < heap_.size()) { - size_t min_child = (child + 1 == heap_.size() + std::size_t min_child = (child + 1 == heap_.size() || Time_Traits::less_than( - heap_[child]->time_, heap_[child + 1]->time_)) + heap_[child].time_, heap_[child + 1].time_)) ? child : child + 1; - if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_)) + if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_)) break; swap_heap(index, min_child); index = min_child; @@ -221,20 +233,20 @@ private: } // Swap two entries in the heap. - void swap_heap(size_t index1, size_t index2) + void swap_heap(std::size_t index1, std::size_t index2) { - timer* tmp = heap_[index1]; + heap_entry tmp = heap_[index1]; heap_[index1] = heap_[index2]; heap_[index2] = tmp; - heap_[index1]->heap_index_ = index1; - heap_[index2]->heap_index_ = index2; + heap_[index1].timer_->heap_index_ = index1; + heap_[index2].timer_->heap_index_ = index2; } // Remove a timer from the heap and list of timers. - void remove_timer(timer* t) + void remove_timer(per_timer_data& timer) { // Remove the timer from the heap. - size_t index = t->heap_index_; + std::size_t index = timer.heap_index_; if (!heap_.empty() && index < heap_.size()) { if (index == heap_.size() - 1) @@ -245,29 +257,112 @@ private: { swap_heap(index, heap_.size() - 1); heap_.pop_back(); - size_t parent = (index - 1) / 2; + std::size_t parent = (index - 1) / 2; if (index > 0 && Time_Traits::less_than( - heap_[index]->time_, heap_[parent]->time_)) + heap_[index].time_, heap_[parent].time_)) up_heap(index); else down_heap(index); } } - // Remove the timer from the hash. - typedef typename hash_map<void*, timer>::iterator iterator; - iterator it = timers_.find(t->token_); - if (it != timers_.end()) - timers_.erase(it); + // Remove the timer from the linked list of active timers. + if (timers_ == &timer) + timers_ = timer.next_; + if (timer.prev_) + timer.prev_->next_ = timer.next_; + if (timer.next_) + timer.next_->prev_= timer.prev_; + timer.next_ = 0; + timer.prev_ = 0; + } + + // Determine if the specified absolute time is positive infinity. + template <typename Time_Type> + static bool is_positive_infinity(const Time_Type&) + { + return false; + } + + // Determine if the specified absolute time is positive infinity. + static bool is_positive_infinity(const boost::posix_time::ptime& time) + { + return time == boost::posix_time::pos_infin; } - // A hash of timer token to linked lists of timers. - hash_map<void*, timer> timers_; + // The head of a linked list of all active timers. + per_timer_data* timers_; + + struct heap_entry + { + // The time when the timer should fire. + time_type time_; + + // The associated timer with enqueued operations. + per_timer_data* timer_; + }; // The heap of timers, with the earliest timer at the front. - std::vector<timer*> heap_; + std::vector<heap_entry> heap_; }; +#if !defined(ASIO_HEADER_ONLY) + +struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {}; + +// Template specialisation for the commonly used instantation. +template <> +class timer_queue<time_traits<boost::posix_time::ptime> > + : public timer_queue_base +{ +public: + // The time type. + typedef boost::posix_time::ptime time_type; + + // The duration type. + typedef boost::posix_time::time_duration duration_type; + + // Per-timer data. + typedef timer_queue<forwarding_posix_time_traits>::per_timer_data + per_timer_data; + + // Constructor. + ASIO_DECL timer_queue(); + + // Destructor. + ASIO_DECL virtual ~timer_queue(); + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + ASIO_DECL bool enqueue_timer(const time_type& time, + per_timer_data& timer, timer_op* op); + + // Whether there are no timers in the queue. + ASIO_DECL virtual bool empty() const; + + // Get the time for the timer that is earliest in the queue. + ASIO_DECL virtual long wait_duration_msec(long max_duration) const; + + // Get the time for the timer that is earliest in the queue. + ASIO_DECL virtual long wait_duration_usec(long max_duration) const; + + // Dequeue all timers not later than the current time. + ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops); + + // Dequeue all timers. + ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops); + + // Cancel and dequeue the timers with the given token. + ASIO_DECL std::size_t cancel_timer( + per_timer_data& timer, op_queue<operation>& ops); + +private: + timer_queue<forwarding_posix_time_traits> impl_; +}; + +#endif // !defined(ASIO_HEADER_ONLY) + } // namespace detail } // namespace asio diff --git a/ext/asio/asio/detail/timer_queue_base.hpp b/ext/asio/asio/detail/timer_queue_base.hpp index f978667535..0e8d4c7868 100644 --- a/ext/asio/asio/detail/timer_queue_base.hpp +++ b/ext/asio/asio/detail/timer_queue_base.hpp @@ -1,8 +1,8 @@ // -// timer_queue_base.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/operation.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/timer_queue_fwd.hpp b/ext/asio/asio/detail/timer_queue_fwd.hpp index 53172448bc..0cca96703c 100644 --- a/ext/asio/asio/detail/timer_queue_fwd.hpp +++ b/ext/asio/asio/detail/timer_queue_fwd.hpp @@ -1,8 +1,8 @@ // -// timer_queue_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - namespace asio { namespace detail { @@ -26,6 +24,4 @@ class timer_queue; } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_TIMER_QUEUE_FWD_HPP diff --git a/ext/asio/asio/detail/timer_queue_set.hpp b/ext/asio/asio/detail/timer_queue_set.hpp index 6860867074..9e8d428414 100644 --- a/ext/asio/asio/detail/timer_queue_set.hpp +++ b/ext/asio/asio/detail/timer_queue_set.hpp @@ -1,8 +1,8 @@ // -// timer_queue_set.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -26,82 +27,28 @@ class timer_queue_set { public: // Constructor. - timer_queue_set() - : first_(0) - { - } + ASIO_DECL timer_queue_set(); // Add a timer queue to the set. - void insert(timer_queue_base* q) - { - q->next_ = first_; - first_ = q; - } + ASIO_DECL void insert(timer_queue_base* q); // Remove a timer queue from the set. - void erase(timer_queue_base* q) - { - if (first_) - { - if (q == first_) - { - first_ = q->next_; - q->next_ = 0; - return; - } - - for (timer_queue_base* p = first_; p->next_; p = p->next_) - { - if (p->next_ == q) - { - p->next_ = q->next_; - q->next_ = 0; - return; - } - } - } - } + ASIO_DECL void erase(timer_queue_base* q); // Determine whether all queues are empty. - bool all_empty() const - { - for (timer_queue_base* p = first_; p; p = p->next_) - if (!p->empty()) - return false; - return true; - } + ASIO_DECL bool all_empty() const; // Get the wait duration in milliseconds. - long wait_duration_msec(long max_duration) const - { - long min_duration = max_duration; - for (timer_queue_base* p = first_; p; p = p->next_) - min_duration = p->wait_duration_msec(min_duration); - return min_duration; - } + ASIO_DECL long wait_duration_msec(long max_duration) const; // Get the wait duration in microseconds. - long wait_duration_usec(long max_duration) const - { - long min_duration = max_duration; - for (timer_queue_base* p = first_; p; p = p->next_) - min_duration = p->wait_duration_usec(min_duration); - return min_duration; - } + ASIO_DECL long wait_duration_usec(long max_duration) const; // Dequeue all ready timers. - void get_ready_timers(op_queue<operation>& ops) - { - for (timer_queue_base* p = first_; p; p = p->next_) - p->get_ready_timers(ops); - } + ASIO_DECL void get_ready_timers(op_queue<operation>& ops); // Dequeue all timers. - void get_all_timers(op_queue<operation>& ops) - { - for (timer_queue_base* p = first_; p; p = p->next_) - p->get_all_timers(ops); - } + ASIO_DECL void get_all_timers(op_queue<operation>& ops); private: timer_queue_base* first_; @@ -112,4 +59,8 @@ private: #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/timer_queue_set.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/ext/asio/asio/detail/timer_scheduler.hpp b/ext/asio/asio/detail/timer_scheduler.hpp index 6822d3f793..1222e630e1 100644 --- a/ext/asio/asio/detail/timer_scheduler.hpp +++ b/ext/asio/asio/detail/timer_scheduler.hpp @@ -1,8 +1,8 @@ // -// timer_scheduler.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,8 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/timer_scheduler_fwd.hpp" #if defined(ASIO_HAS_IOCP) @@ -31,6 +30,4 @@ # include "asio/detail/select_reactor.hpp" #endif -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/ext/asio/asio/detail/timer_scheduler_fwd.hpp b/ext/asio/asio/detail/timer_scheduler_fwd.hpp index d766a87fb2..5fced5005f 100644 --- a/ext/asio/asio/detail/timer_scheduler_fwd.hpp +++ b/ext/asio/asio/detail/timer_scheduler_fwd.hpp @@ -1,8 +1,8 @@ // -// timer_scheduler_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/dev_poll_reactor_fwd.hpp" -#include "asio/detail/epoll_reactor_fwd.hpp" -#include "asio/detail/kqueue_reactor_fwd.hpp" -#include "asio/detail/select_reactor_fwd.hpp" -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_service_fwd.hpp" +#elif defined(ASIO_HAS_EPOLL) +# include "asio/detail/epoll_reactor_fwd.hpp" +#elif defined(ASIO_HAS_KQUEUE) +# include "asio/detail/kqueue_reactor_fwd.hpp" +#elif defined(ASIO_HAS_DEV_POLL) +# include "asio/detail/dev_poll_reactor_fwd.hpp" +#else +# include "asio/detail/select_reactor_fwd.hpp" +#endif namespace asio { namespace detail { @@ -35,12 +41,10 @@ typedef kqueue_reactor timer_scheduler; #elif defined(ASIO_HAS_DEV_POLL) typedef dev_poll_reactor timer_scheduler; #else -typedef select_reactor<false> timer_scheduler; +typedef select_reactor timer_scheduler; #endif } // namespace detail } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/ext/asio/asio/detail/tss_ptr.hpp b/ext/asio/asio/detail/tss_ptr.hpp index ac67d9f0ce..0218f5f779 100644 --- a/ext/asio/asio/detail/tss_ptr.hpp +++ b/ext/asio/asio/detail/tss_ptr.hpp @@ -1,8 +1,8 @@ // -// tss_ptr.hpp -// ~~~~~~~~~~~ +// detail/tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_tss_ptr.hpp" @@ -31,6 +27,8 @@ # error Only Windows and POSIX are supported! #endif +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/detail/wait_handler.hpp b/ext/asio/asio/detail/wait_handler.hpp new file mode 100644 index 0000000000..0df16cb6a9 --- /dev/null +++ b/ext/asio/asio/detail/wait_handler.hpp @@ -0,0 +1,76 @@ +// +// detail/wait_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WAIT_HANDLER_HPP +#define ASIO_DETAIL_WAIT_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/timer_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class wait_handler : public timer_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(wait_handler); + + wait_handler(Handler h) + : timer_op(&wait_handler::do_complete), + handler_(h) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + wait_handler* h(static_cast<wait_handler*>(base)); + ptr p = { boost::addressof(h->handler_), h, h }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(h->handler_, h->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WAIT_HANDLER_HPP diff --git a/ext/asio/asio/detail/weak_ptr.hpp b/ext/asio/asio/detail/weak_ptr.hpp new file mode 100644 index 0000000000..35dca19a41 --- /dev/null +++ b/ext/asio/asio/detail/weak_ptr.hpp @@ -0,0 +1,39 @@ +// +// detail/weak_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WEAK_PTR_HPP +#define ASIO_DETAIL_WEAK_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <boost/version.hpp> + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# include <memory> +#else +# include <boost/weak_ptr.hpp> +#endif + +namespace asio { +namespace detail { + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +using std::weak_ptr; +#else +using boost::weak_ptr; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_WEAK_PTR_HPP diff --git a/ext/asio/asio/detail/win_event.hpp b/ext/asio/asio/detail/win_event.hpp index cabb2c389c..71ad7e0b5a 100644 --- a/ext/asio/asio/detail/win_event.hpp +++ b/ext/asio/asio/detail/win_event.hpp @@ -1,8 +1,8 @@ // -// win_event.hpp -// ~~~~~~~~~~~~~ +// detail/win_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" -#include "asio/system_error.hpp" +#include <boost/assert.hpp> #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" -#include <boost/assert.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { @@ -41,19 +33,7 @@ class win_event { public: // Constructor. - win_event() - : event_(::CreateEvent(0, true, false, 0)) - { - if (!event_) - { - DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "event"); - boost::throw_exception(e); - } - } + ASIO_DECL win_event(); // Destructor. ~win_event() @@ -105,8 +85,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // ASIO_DETAIL_WIN_EVENT_HPP diff --git a/ext/asio/asio/detail/win_fd_set_adapter.hpp b/ext/asio/asio/detail/win_fd_set_adapter.hpp index 012a10ff76..0cb9d8c9d8 100644 --- a/ext/asio/asio/detail/win_fd_set_adapter.hpp +++ b/ext/asio/asio/detail/win_fd_set_adapter.hpp @@ -1,8 +1,8 @@ // -// win_fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/socket_types.hpp" -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -81,8 +83,8 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/ext/asio/asio/detail/win_fenced_block.hpp b/ext/asio/asio/detail/win_fenced_block.hpp index 6338488f91..011f44b23a 100644 --- a/ext/asio/asio/detail/win_fenced_block.hpp +++ b/ext/asio/asio/detail/win_fenced_block.hpp @@ -1,8 +1,8 @@ // -// win_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -35,7 +33,10 @@ public: // Constructor. win_fenced_block() { -#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier)) # if defined(_M_IX86) # pragma warning(push) # pragma warning(disable:4793) @@ -43,15 +44,18 @@ public: __asm { xchg barrier, eax } # pragma warning(pop) # endif // defined(_M_IX86) -#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +#else MemoryBarrier(); -#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +#endif } // Destructor. ~win_fenced_block() { -#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier)) # if defined(_M_IX86) # pragma warning(push) # pragma warning(disable:4793) @@ -59,17 +63,17 @@ public: __asm { xchg barrier, eax } # pragma warning(pop) # endif // defined(_M_IX86) -#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +#else MemoryBarrier(); -#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +#endif } }; } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) - #include "asio/detail/pop_options.hpp" +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + #endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/ext/asio/asio/detail/win_iocp_handle_read_op.hpp b/ext/asio/asio/detail/win_iocp_handle_read_op.hpp new file mode 100644 index 0000000000..fb358bed7b --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_handle_read_op.hpp @@ -0,0 +1,101 @@ +// +// detail/win_iocp_handle_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Handler> +class win_iocp_handle_read_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); + + win_iocp_handle_read_op(const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_handle_read_op::do_complete), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + ec = asio::error::eof; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_handle_service.hpp b/ext/asio/asio/detail/win_iocp_handle_service.hpp index bfc159ce72..34f725f163 100644 --- a/ext/asio/asio/detail/win_iocp_handle_service.hpp +++ b/ext/asio/asio/detail/win_iocp_handle_service.hpp @@ -1,8 +1,8 @@ // -// win_iocp_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,26 +16,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) -#include "asio/detail/push_options.hpp" #include <boost/cstdint.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" +#include "asio/detail/win_iocp_handle_read_op.hpp" +#include "asio/detail/win_iocp_handle_write_op.hpp" #include "asio/detail/win_iocp_io_service.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -76,75 +73,20 @@ public: implementation_type* prev_; }; - win_iocp_handle_service(asio::io_service& io_service) - : iocp_service_(asio::use_service<win_iocp_io_service>(io_service)), - mutex_(), - impl_list_(0) - { - } + ASIO_DECL win_iocp_handle_service(asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - // Close all implementations, causing all operations to complete. - asio::detail::mutex::scoped_lock lock(mutex_); - implementation_type* impl = impl_list_; - while (impl) - { - close_for_destruction(*impl); - impl = impl->next_; - } - } + ASIO_DECL void shutdown_service(); // Construct a new handle implementation. - void construct(implementation_type& impl) - { - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - - // Insert implementation into linked list of all implementations. - asio::detail::mutex::scoped_lock lock(mutex_); - impl.next_ = impl_list_; - impl.prev_ = 0; - if (impl_list_) - impl_list_->prev_ = &impl; - impl_list_ = &impl; - } + ASIO_DECL void construct(implementation_type& impl); // Destroy a handle implementation. - void destroy(implementation_type& impl) - { - close_for_destruction(impl); - - // Remove implementation from linked list of all implementations. - asio::detail::mutex::scoped_lock lock(mutex_); - if (impl_list_ == &impl) - impl_list_ = impl.next_; - if (impl.prev_) - impl.prev_->next_ = impl.next_; - if (impl.next_) - impl.next_->prev_= impl.prev_; - impl.next_ = 0; - impl.prev_ = 0; - } + ASIO_DECL void destroy(implementation_type& impl); // Assign a native handle to a handle implementation. - asio::error_code assign(implementation_type& impl, - const native_type& native_handle, asio::error_code& ec) - { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - if (iocp_service_.register_handle(native_handle, ec)) - return ec; - - impl.handle_ = native_handle; - ec = asio::error_code(); - return ec; - } + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_type& native_handle, asio::error_code& ec); // Determine whether the handle is open. bool is_open(const implementation_type& impl) const @@ -153,26 +95,8 @@ public: } // Destroy a handle implementation. - asio::error_code close(implementation_type& impl, - asio::error_code& ec) - { - if (is_open(impl)) - { - if (!::CloseHandle(impl.handle_)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - } - - ec = asio::error_code(); - return ec; - } + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); // Get the native handle representation. native_type native(const implementation_type& impl) const @@ -181,106 +105,8 @@ public: } // Cancel all operations associated with the handle. - asio::error_code cancel(implementation_type& impl, - asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - } - else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( - ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) - { - // The version of Windows supports cancellation from any thread. - typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; - if (!cancel_io_ex(impl.handle_, 0)) - { - DWORD last_error = ::GetLastError(); - if (last_error == ERROR_NOT_FOUND) - { - // ERROR_NOT_FOUND means that there were no operations to be - // cancelled. We swallow this error to match the behaviour on other - // platforms. - ec = asio::error_code(); - } - else - { - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - } - else - { - ec = asio::error_code(); - } - } - else if (impl.safe_cancellation_thread_id_ == 0) - { - // No operations have been started, so there's nothing to cancel. - ec = asio::error_code(); - } - else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) - { - // Asynchronous operations have been started from the current thread only, - // so it is safe to try to cancel them using CancelIo. - if (!::CancelIo(impl.handle_)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - else - { - ec = asio::error_code(); - } - } - else - { - // Asynchronous operations have been started from more than one thread, - // so cancellation is not safe. - ec = asio::error::operation_not_supported; - } - - return ec; - } - - class overlapped_wrapper - : public OVERLAPPED - { - public: - explicit overlapped_wrapper(asio::error_code& ec) - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - - // Create a non-signalled manual-reset event, for GetOverlappedResult. - hEvent = ::CreateEvent(0, TRUE, FALSE, 0); - if (hEvent) - { - // As documented in GetQueuedCompletionStatus, setting the low order - // bit of this event prevents our synchronous writes from being treated - // as completion port events. - *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1; - } - else - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - } - - ~overlapped_wrapper() - { - if (hEvent) - { - ::CloseHandle(hEvent); - } - } - }; + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); // Write the given data. Returns the number of bytes written. template <typename ConstBufferSequence> @@ -296,109 +122,13 @@ public: size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - asio::const_buffer buffer = buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence>::first(buffers); - // A request to write 0 bytes on a handle is a no-op. - if (asio::buffer_size(buffer) == 0) - { - ec = asio::error_code(); - return 0; - } - - overlapped_wrapper overlapped(ec); - if (ec) - { - return 0; - } - - // Write the data. - overlapped.Offset = offset & 0xFFFFFFFF; - overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - asio::buffer_cast<LPCVOID>(buffer), - static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error != ERROR_IO_PENDING) - { - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - } - - // Wait for the operation to complete. - DWORD bytes_transferred = 0; - ok = ::GetOverlappedResult(impl.handle_, - &overlapped, &bytes_transferred, TRUE); - if (!ok) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - - ec = asio::error_code(); - return bytes_transferred; + return do_write(impl, offset, buffer, ec); } - template <typename ConstBufferSequence, typename Handler> - class write_op : public operation - { - public: - write_op(const ConstBufferSequence& buffers, Handler handler) - : operation(&write_op::do_complete), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - write_op* o(static_cast<write_op*>(base)); - typedef handler_alloc_traits<Handler, write_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::validate(o->buffers_); -#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - ConstBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> @@ -415,15 +145,16 @@ public: const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef write_op<ConstBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler); + typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(buffers, handler); start_write_op(impl, offset, buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::first(buffers), ptr.get()); - ptr.release(); + ConstBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; } // Read some data. Returns the number of bytes received. @@ -439,129 +170,13 @@ public: size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - asio::mutable_buffer buffer = buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence>::first(buffers); - // A request to read 0 bytes on a stream handle is a no-op. - if (asio::buffer_size(buffer) == 0) - { - ec = asio::error_code(); - return 0; - } - - overlapped_wrapper overlapped(ec); - if (ec) - { - return 0; - } - - // Read some data. - overlapped.Offset = offset & 0xFFFFFFFF; - overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - asio::buffer_cast<LPVOID>(buffer), - static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) - { - if (last_error == ERROR_HANDLE_EOF) - { - ec = asio::error::eof; - } - else - { - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - return 0; - } - } - - // Wait for the operation to complete. - DWORD bytes_transferred = 0; - ok = ::GetOverlappedResult(impl.handle_, - &overlapped, &bytes_transferred, TRUE); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error == ERROR_HANDLE_EOF) - { - ec = asio::error::eof; - } - else - { - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - return 0; - } - - ec = asio::error_code(); - return bytes_transferred; + return do_read(impl, offset, buffer, ec); } - template <typename MutableBufferSequence, typename Handler> - class read_op : public operation - { - public: - read_op(const MutableBufferSequence& buffers, Handler handler) - : operation(&read_op::do_complete), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - read_op* o(static_cast<read_op*>(base)); - typedef handler_alloc_traits<Handler, read_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::validate(o->buffers_); -#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_HANDLE_EOF) - { - ec = asio::error::eof; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - MutableBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. template <typename MutableBufferSequence, typename Handler> @@ -579,15 +194,16 @@ public: const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef read_op<MutableBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler); + typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(buffers, handler); start_read_op(impl, offset, buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::first(buffers), ptr.get()); - ptr.release(); + MutableBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; } private: @@ -613,113 +229,42 @@ private: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); + // Helper class for waiting for synchronous operations to complete. + class overlapped_wrapper; + + // Helper function to perform a synchronous write operation. + ASIO_DECL size_t do_write(implementation_type& impl, + boost::uint64_t offset, const asio::const_buffer& buffer, + asio::error_code& ec); + // Helper function to start a write operation. - void start_write_op(implementation_type& impl, boost::uint64_t offset, - const asio::const_buffer& buffer, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); + ASIO_DECL void start_write_op(implementation_type& impl, + boost::uint64_t offset, const asio::const_buffer& buffer, + operation* op); - if (!is_open(impl)) - { - iocp_service_.on_completion(op, asio::error::bad_descriptor); - } - else if (asio::buffer_size(buffer) == 0) - { - // A request to write 0 bytes on a handle is a no-op. - iocp_service_.on_completion(op); - } - else - { - DWORD bytes_transferred = 0; - op->Offset = offset & 0xFFFFFFFF; - op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - asio::buffer_cast<LPCVOID>(buffer), - static_cast<DWORD>(asio::buffer_size(buffer)), - &bytes_transferred, op); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING - && last_error != ERROR_MORE_DATA) - { - iocp_service_.on_completion(op, last_error, bytes_transferred); - } - else - { - iocp_service_.on_pending(op); - } - } - } + // Helper function to perform a synchronous write operation. + ASIO_DECL size_t do_read(implementation_type& impl, + boost::uint64_t offset, const asio::mutable_buffer& buffer, + asio::error_code& ec); // Helper function to start a read operation. - void start_read_op(implementation_type& impl, boost::uint64_t offset, - const asio::mutable_buffer& buffer, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - { - iocp_service_.on_completion(op, asio::error::bad_descriptor); - } - else if (asio::buffer_size(buffer) == 0) - { - // A request to read 0 bytes on a handle is a no-op. - iocp_service_.on_completion(op); - } - else - { - DWORD bytes_transferred = 0; - op->Offset = offset & 0xFFFFFFFF; - op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - asio::buffer_cast<LPVOID>(buffer), - static_cast<DWORD>(asio::buffer_size(buffer)), - &bytes_transferred, op); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING - && last_error != ERROR_MORE_DATA) - { - iocp_service_.on_completion(op, last_error, bytes_transferred); - } - else - { - iocp_service_.on_pending(op); - } - } - } + ASIO_DECL void start_read_op(implementation_type& impl, + boost::uint64_t offset, const asio::mutable_buffer& buffer, + operation* op); // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id(implementation_type& impl) - { -#if defined(ASIO_ENABLE_CANCELIO) - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#else // defined(ASIO_ENABLE_CANCELIO) - (void)impl; -#endif // defined(ASIO_ENABLE_CANCELIO) - } + ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); // Helper function to close a handle when the associated object is being // destroyed. - void close_for_destruction(implementation_type& impl) - { - if (is_open(impl)) - { - ::CloseHandle(impl.handle_); - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - } - } + ASIO_DECL void close_for_destruction(implementation_type& impl); // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // Mutex to protect access to the linked list of implementations. - asio::detail::mutex mutex_; + mutex mutex_; // The head of a linked list of all implementations. implementation_type* impl_list_; @@ -728,8 +273,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_IOCP) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_handle_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP diff --git a/ext/asio/asio/detail/win_iocp_handle_write_op.hpp b/ext/asio/asio/detail/win_iocp_handle_write_op.hpp new file mode 100644 index 0000000000..ddfe8fc2a8 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_handle_write_op.hpp @@ -0,0 +1,97 @@ +// +// detail/win_iocp_handle_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Handler> +class win_iocp_handle_write_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); + + win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler handler) + : operation(&win_iocp_handle_write_op::do_complete), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_io_service.hpp b/ext/asio/asio/detail/win_iocp_io_service.hpp index fd899c1146..c8974b60cd 100644 --- a/ext/asio/asio/detail/win_iocp_io_service.hpp +++ b/ext/asio/asio/detail/win_iocp_io_service.hpp @@ -1,8 +1,8 @@ // -// win_iocp_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,33 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) -#include "asio/detail/push_options.hpp" -#include <boost/limits.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - +#include <boost/scoped_ptr.hpp> #include "asio/io_service.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/call_stack.hpp" -#include "asio/detail/completion_handler.hpp" -#include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" -#include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/win_iocp_io_service_fwd.hpp" #include "asio/detail/win_iocp_operation.hpp" +#include "asio/detail/thread.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -52,69 +43,13 @@ class win_iocp_io_service : public asio::detail::service_base<win_iocp_io_service> { public: - typedef win_iocp_operation operation; - // Constructor. - win_iocp_io_service(asio::io_service& io_service) - : asio::detail::service_base<win_iocp_io_service>(io_service), - iocp_(), - outstanding_work_(0), - stopped_(0), - shutdown_(0), - timer_thread_(0), - timer_interrupt_issued_(false) - { - } + ASIO_DECL win_iocp_io_service(asio::io_service& io_service); - void init(size_t concurrency_hint) - { - iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, - static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0)))); - if (!iocp_.handle) - { - DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "iocp"); - boost::throw_exception(e); - } - } + ASIO_DECL void init(size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - ::InterlockedExchange(&shutdown_, 1); - - while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) - { - op_queue<operation> ops; - timer_queues_.get_all_timers(ops); - ops.push(completed_ops_); - if (!ops.empty()) - { - while (operation* op = ops.front()) - { - ops.pop(); - ::InterlockedDecrement(&outstanding_work_); - op->destroy(); - } - } - else - { - DWORD bytes_transferred = 0; - dword_ptr_t completion_key = 0; - LPOVERLAPPED overlapped = 0; - ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, max_timeout); - if (overlapped) - { - ::InterlockedDecrement(&outstanding_work_); - static_cast<operation*>(overlapped)->destroy(); - } - } - } - } + ASIO_DECL void shutdown_service(); // Initialise the task. Nothing to do here. void init_task() @@ -122,106 +57,23 @@ public: } // Register a handle with the IO completion port. - asio::error_code register_handle( - HANDLE handle, asio::error_code& ec) - { - if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - else - { - ec = asio::error_code(); - } - return ec; - } + ASIO_DECL asio::error_code register_handle( + HANDLE handle, asio::error_code& ec); // Run the event loop until stopped or no more work. - size_t run(asio::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = asio::error_code(); - return 0; - } - - call_stack<win_iocp_io_service>::context ctx(this); - - size_t n = 0; - while (do_one(true, ec)) - if (n != (std::numeric_limits<size_t>::max)()) - ++n; - return n; - } + ASIO_DECL size_t run(asio::error_code& ec); // Run until stopped or one operation is performed. - size_t run_one(asio::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = asio::error_code(); - return 0; - } - - call_stack<win_iocp_io_service>::context ctx(this); - - return do_one(true, ec); - } + ASIO_DECL size_t run_one(asio::error_code& ec); // Poll for operations without blocking. - size_t poll(asio::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = asio::error_code(); - return 0; - } - - call_stack<win_iocp_io_service>::context ctx(this); - - size_t n = 0; - while (do_one(false, ec)) - if (n != (std::numeric_limits<size_t>::max)()) - ++n; - return n; - } + ASIO_DECL size_t poll(asio::error_code& ec); // Poll for one operation without blocking. - size_t poll_one(asio::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = asio::error_code(); - return 0; - } - - call_stack<win_iocp_io_service>::context ctx(this); - - return do_one(false, ec); - } + ASIO_DECL size_t poll_one(asio::error_code& ec); // Stop the event processing loop. - void stop() - { - if (::InterlockedExchange(&stopped_, 1) == 0) - { - if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) - { - DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "pqcs"); - boost::throw_exception(e); - } - } - } + ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. void reset() @@ -244,34 +96,15 @@ public: // Request invocation of the given handler. template <typename Handler> - void dispatch(Handler handler) - { - if (call_stack<win_iocp_io_service>::contains(this)) - { - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - else - post(handler); - } + void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template <typename Handler> - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - post_immediate_completion(ptr.get()); - ptr.release(); - } + void post(Handler handler); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. - void post_immediate_completion(operation* op) + void post_immediate_completion(win_iocp_operation* op) { work_started(); post_deferred_completion(op); @@ -279,170 +112,50 @@ public: // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. - void post_deferred_completion(operation* op) - { - // Flag the operation as ready. - op->ready_ = 1; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + ASIO_DECL void post_deferred_completion(win_iocp_operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operations. - void post_deferred_completions(op_queue<operation>& ops) - { - while (operation* op = ops.front()) - { - ops.pop(); - - // Flag the operation as ready. - op->ready_ = 1; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - completed_ops_.push(ops); - } - } - } + ASIO_DECL void post_deferred_completions( + op_queue<win_iocp_operation>& ops); // Called after starting an overlapped I/O operation that did not complete // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_pending(operation* op) - { - if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) - { - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } - } + ASIO_DECL void on_pending(win_iocp_operation* op); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_completion(operation* op, - DWORD last_error = 0, DWORD bytes_transferred = 0) - { - // Flag that the operation is ready for invocation. - op->ready_ = 1; - - // Store results in the OVERLAPPED structure. - op->Internal = asio::error::get_system_category(); - op->Offset = last_error; - op->OffsetHigh = bytes_transferred; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + ASIO_DECL void on_completion(win_iocp_operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_completion(operation* op, - const asio::error_code& ec, DWORD bytes_transferred = 0) - { - // Flag that the operation is ready for invocation. - op->ready_ = 1; - - // Store results in the OVERLAPPED structure. - op->Internal = ec.category(); - op->Offset = ec.value(); - op->OffsetHigh = bytes_transferred; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + ASIO_DECL void on_completion(win_iocp_operation* op, + const asio::error_code& ec, DWORD bytes_transferred = 0); // Add a new timer queue to the service. template <typename Time_Traits> - void add_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue<Time_Traits>& timer_queue); // Remove a timer queue from the service. template <typename Time_Traits> - void remove_timer_queue(timer_queue<Time_Traits>& timer_queue) - { - asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> - void schedule_timer(timer_queue<Time_Traits>& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - // If the service has been shut down we silently discard the timer. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return; - - asio::detail::mutex::scoped_lock lock(timer_mutex_); - bool interrupt = timer_queue.enqueue_timer(time, op, token); - work_started(); - if (interrupt && !timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } - } + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op); // Cancel the timer associated with the given token. Returns the number of // handlers that have been posted or dispatched. template <typename Time_Traits> - std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token) - { - // If the service has been shut down we silently ignore the cancellation. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return 0; - - asio::detail::mutex::scoped_lock lock(timer_mutex_); - op_queue<operation> ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - post_deferred_completions(ops); - if (n > 0 && !timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } - return n; - } + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer); private: #if defined(WINVER) && (WINVER < 0x0500) @@ -456,181 +169,30 @@ private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). - size_t do_one(bool block, asio::error_code& ec) - { - long this_thread_id = static_cast<long>(::GetCurrentThreadId()); - - for (;;) - { - // Try to acquire responsibility for dispatching timers. - bool dispatching_timers = (::InterlockedCompareExchange( - &timer_thread_, this_thread_id, 0) == 0); - - // Calculate timeout for GetQueuedCompletionStatus call. - DWORD timeout = max_timeout; - if (dispatching_timers) - { - asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_interrupt_issued_ = false; - timeout = get_timeout(); - } - - // Get the next operation from the queue. - DWORD bytes_transferred = 0; - dword_ptr_t completion_key = 0; - LPOVERLAPPED overlapped = 0; - ::SetLastError(0); - BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? timeout : 0); - DWORD last_error = ::GetLastError(); - - // Dispatch any pending timers. - if (dispatching_timers) - { - asio::detail::mutex::scoped_lock lock(timer_mutex_); - op_queue<operation> ops; - ops.push(completed_ops_); - timer_queues_.get_ready_timers(ops); - post_deferred_completions(ops); - } - - if (!ok && overlapped == 0) - { - if (block && last_error == WAIT_TIMEOUT) - { - // Relinquish responsibility for dispatching timers. - if (dispatching_timers) - { - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - - continue; - } - - // Transfer responsibility for dispatching timers to another thread. - if (dispatching_timers && ::InterlockedCompareExchange( - &timer_thread_, 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - ec = asio::error_code(); - return 0; - } - else if (overlapped) - { - operation* op = static_cast<operation*>(overlapped); - asio::error_code result_ec(last_error, - asio::error::get_system_category()); - - // Transfer responsibility for dispatching timers to another thread. - if (dispatching_timers && ::InterlockedCompareExchange( - &timer_thread_, 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - // We may have been passed the last_error and bytes_transferred in the - // OVERLAPPED structure itself. - if (completion_key == overlapped_contains_result) - { - result_ec = asio::error_code(static_cast<int>(op->Offset), - static_cast<asio::error_category>(op->Internal)); - bytes_transferred = op->OffsetHigh; - } - - // Otherwise ensure any result has been saved into the OVERLAPPED - // structure. - else - { - op->Internal = result_ec.category(); - op->Offset = result_ec.value(); - op->OffsetHigh = bytes_transferred; - } - - // Dispatch the operation only if ready. The operation may not be ready - // if the initiating function (e.g. a call to WSARecv) has not yet - // returned. This is because the initiating function still wants access - // to the operation's OVERLAPPED structure. - if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) - { - // Ensure the count of outstanding work is decremented on block exit. - work_finished_on_block_exit on_exit = { this }; - (void)on_exit; - - op->complete(*this, result_ec, bytes_transferred); - ec = asio::error_code(); - return 1; - } - } - else if (completion_key == transfer_timer_dispatching) - { - // Woken up to try to acquire responsibility for dispatching timers. - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - else if (completion_key == steal_timer_dispatching) - { - // Woken up to steal responsibility for dispatching timers. - ::InterlockedExchange(&timer_thread_, 0); - } - else - { - // Relinquish responsibility for dispatching timers. If the io_service - // is not being stopped then the thread will get an opportunity to - // reacquire timer responsibility on the next loop iteration. - if (dispatching_timers) - { - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - - // The stopped_ flag is always checked to ensure that any leftover - // interrupts from a previous run invocation are ignored. - if (::InterlockedExchangeAdd(&stopped_, 0) != 0) - { - // Wake up next thread that is blocked on GetQueuedCompletionStatus. - if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) - { - last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - - ec = asio::error_code(); - return 0; - } - } - } - } + ASIO_DECL size_t do_one(bool block, asio::error_code& ec); - // Get the timeout value for the GetQueuedCompletionStatus call. The timeout - // value is returned as a number of milliseconds. We will wait no longer than - // 1000 milliseconds. - DWORD get_timeout() - { - return timer_queues_.wait_duration_msec(max_timeout); - } + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); // Helper class to call work_finished() on block exit. - struct work_finished_on_block_exit - { - ~work_finished_on_block_exit() - { - io_service_->work_finished(); - } + struct work_finished_on_block_exit; - win_iocp_io_service* io_service_; + // Helper class for managing a HANDLE. + struct auto_handle + { + HANDLE handle; + auto_handle() : handle(0) {} + ~auto_handle() { if (handle) ::CloseHandle(handle); } }; // The IO completion port used for queueing operations. - struct iocp_holder - { - HANDLE handle; - iocp_holder() : handle(0) {} - ~iocp_holder() { if (handle) ::CloseHandle(handle); } - } iocp_; + auto_handle iocp_; // The count of unfinished work. long outstanding_work_; @@ -643,44 +205,61 @@ private: enum { - // Maximum GetQueuedCompletionStatus timeout, in milliseconds. - max_timeout = 500, + // Timeout to use with GetQueuedCompletionStatus. Some versions of windows + // have a "bug" where a call to GetQueuedCompletionStatus can appear stuck + // even though there are events waiting on the queue. Using a timeout helps + // to work around the issue. + gqcs_timeout = 500, + + // Maximum waitable timer timeout, in milliseconds. + max_timeout_msec = 5 * 60 * 1000, - // Completion key value to indicate that responsibility for dispatching - // timers is being cooperatively transferred from one thread to another. - transfer_timer_dispatching = 1, + // Maximum waitable timer timeout, in microseconds. + max_timeout_usec = max_timeout_msec * 1000, - // Completion key value to indicate that responsibility for dispatching - // timers should be stolen from another thread. - steal_timer_dispatching = 2, + // Completion key value used to wake up a thread to dispatch timers or + // completed operations. + wake_for_dispatch = 1, // Completion key value to indicate that an operation has posted with the // original last_error and bytes_transferred values stored in the fields of // the OVERLAPPED structure. - overlapped_contains_result = 3 + overlapped_contains_result = 2 }; - // The thread that's currently in charge of dispatching timers. - long timer_thread_; + // Function object for processing timeouts in a background thread. + struct timer_thread_function; + friend struct timer_thread_function; + + // Background thread used for processing timeouts. + boost::scoped_ptr<thread> timer_thread_; + + // A waitable timer object used for waiting for timeouts. + auto_handle waitable_timer_; - // Mutex for protecting access to the timer queues. - mutex timer_mutex_; + // Non-zero if timers or completed operations need to be dispatched. + long dispatch_required_; - // Whether a thread has been interrupted to process a new timeout. - bool timer_interrupt_issued_; + // Mutex for protecting access to the timer queues and completed operations. + mutex dispatch_mutex_; // The timer queues. timer_queue_set timer_queues_; // The operations that are ready to dispatch. - op_queue<operation> completed_ops_; + op_queue<win_iocp_operation> completed_ops_; }; } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_IOCP) - #include "asio/detail/pop_options.hpp" +#include "asio/detail/impl/win_iocp_io_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_io_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP diff --git a/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp b/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp index 29d2a05481..9f03743d2b 100644 --- a/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp +++ b/ext/asio/asio/detail/win_iocp_io_service_fwd.hpp @@ -1,8 +1,8 @@ // -// win_iocp_io_service_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,22 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/detail/socket_types.hpp" - -// This service is only supported on Win32 (NT4 and later). -#if !defined(ASIO_DISABLE_IOCP) -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) -#if !defined(UNDER_CE) - -// Define this to indicate that IOCP is supported on the target platform. -#define ASIO_HAS_IOCP 1 +#if defined(ASIO_HAS_IOCP) namespace asio { namespace detail { @@ -41,11 +28,6 @@ class win_iocp_overlapped_ptr; } // namespace detail } // namespace asio -#endif // !defined(UNDER_CE) -#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#endif // !defined(ASIO_DISABLE_IOCP) - -#include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP diff --git a/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp b/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp new file mode 100644 index 0000000000..e39fff7c75 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_null_buffers_op.hpp @@ -0,0 +1,112 @@ +// +// detail/win_iocp_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class win_iocp_null_buffers_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); + + win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, + Handler handler) + : reactor_op(&win_iocp_null_buffers_op::do_perform, + &win_iocp_null_buffers_op::do_complete), + cancel_token_(cancel_token), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_operation.hpp b/ext/asio/asio/detail/win_iocp_operation.hpp index ac8106255a..649edd1a88 100644 --- a/ext/asio/asio/detail/win_iocp_operation.hpp +++ b/ext/asio/asio/detail/win_iocp_operation.hpp @@ -1,8 +1,8 @@ // -// win_iocp_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) -#include "asio/error_code.hpp" #include "asio/detail/op_queue.hpp" +#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -82,8 +83,8 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_IOCP) - #include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/ext/asio/asio/detail/win_iocp_overlapped_op.hpp b/ext/asio/asio/detail/win_iocp_overlapped_op.hpp new file mode 100644 index 0000000000..f2b7ddf624 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_overlapped_op.hpp @@ -0,0 +1,84 @@ +// +// detail/win_iocp_overlapped_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class win_iocp_overlapped_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); + + win_iocp_overlapped_op(Handler handler) + : operation(&win_iocp_overlapped_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp b/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp index 47a3f70cf1..919affe414 100644 --- a/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp @@ -1,8 +1,8 @@ // -// win_iocp_overlapped_ptr.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) -#include "asio/detail/fenced_block.hpp" +#include <boost/utility/addressof.hpp> +#include "asio/io_service.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/win_iocp_overlapped_op.hpp" #include "asio/detail/win_iocp_io_service.hpp" -#include "asio/detail/win_iocp_operation.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { @@ -74,13 +76,15 @@ public: template <typename Handler> void reset(asio::io_service& io_service, Handler handler) { - typedef overlapped_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); + typedef win_iocp_overlapped_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); io_service.impl_.work_started(); reset(); - ptr_ = ptr.release(); + ptr_ = p.p; + p.v = p.p = 0; iocp_service_ = &io_service.impl_; } @@ -122,44 +126,6 @@ public: } private: - template <typename Handler> - struct overlapped_op : public win_iocp_operation - { - overlapped_op(Handler handler) - : win_iocp_operation(&overlapped_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - overlapped_op* o(static_cast<overlapped_op*>(base)); - typedef handler_alloc_traits<Handler, overlapped_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - win_iocp_operation* ptr_; win_iocp_io_service* iocp_service_; }; @@ -167,8 +133,8 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_IOCP) - #include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP diff --git a/ext/asio/asio/detail/win_iocp_serial_port_service.hpp b/ext/asio/asio/detail/win_iocp_serial_port_service.hpp index ed5f75e91c..bf3a692d55 100644 --- a/ext/asio/asio/detail/win_iocp_serial_port_service.hpp +++ b/ext/asio/asio/detail/win_iocp_serial_port_service.hpp @@ -1,8 +1,8 @@ // -// win_iocp_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,21 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <cstring> -#include <string> -#include "asio/detail/pop_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" -#if defined(ASIO_HAS_IOCP) +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) +#include <string> #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/win_iocp_handle_service.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -38,133 +34,56 @@ namespace detail { class win_iocp_serial_port_service { public: - // The native type of a stream handle. + // The native type of a serial port. typedef win_iocp_handle_service::native_type native_type; - // The implementation type of the stream handle. + // The implementation type of the serial port. typedef win_iocp_handle_service::implementation_type implementation_type; - win_iocp_serial_port_service(asio::io_service& io_service) - : handle_service_(io_service) - { - } + // Constructor. + ASIO_DECL win_iocp_serial_port_service( + asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } + ASIO_DECL void shutdown_service(); - // Construct a new handle implementation. + // Construct a new serial port implementation. void construct(implementation_type& impl) { handle_service_.construct(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. void destroy(implementation_type& impl) { handle_service_.destroy(impl); } // Open the serial port using the specified device name. - asio::error_code open(implementation_type& impl, - const std::string& device, asio::error_code& ec) - { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - // For convenience, add a leading \\.\ sequence if not already present. - std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; - - // Open a handle to the serial port. - ::HANDLE handle = ::CreateFileA(name.c_str(), - GENERIC_READ | GENERIC_WRITE, 0, 0, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if (handle == INVALID_HANDLE_VALUE) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - // Determine the initial serial port parameters. - using namespace std; // For memcpy. - ::DCB dcb; - memset(&dcb, 0, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - if (!::GetCommState(handle, &dcb)) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(handle); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - // Set some default serial port parameters. This implementation does not - // support changing these, so they might as well be in a known state. - dcb.fBinary = TRUE; // Win32 only supports binary mode. - dcb.fDsrSensitivity = FALSE; - dcb.fNull = FALSE; // Do not ignore NULL characters. - dcb.fAbortOnError = FALSE; // Ignore serial framing errors. - if (!::SetCommState(handle, &dcb)) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(handle); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - // Set up timeouts so that the serial port will behave similarly to a - // network socket. Reads wait for at least one byte, then return with - // whatever they have. Writes return once everything is out the door. - ::COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = 1; - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - if (!::SetCommTimeouts(handle, &timeouts)) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(handle); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - // We're done. Take ownership of the serial port handle. - if (handle_service_.assign(impl, handle, ec)) - ::CloseHandle(handle); - return ec; - } + ASIO_DECL asio::error_code open(implementation_type& impl, + const std::string& device, asio::error_code& ec); - // Assign a native handle to a handle implementation. + // Assign a native handle to a serial port implementation. asio::error_code assign(implementation_type& impl, const native_type& native_handle, asio::error_code& ec) { return handle_service_.assign(impl, native_handle, ec); } - // Determine whether the handle is open. + // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return handle_service_.is_open(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return handle_service_.close(impl, ec); } - // Get the native handle representation. + // Get the native serial port representation. native_type native(implementation_type& impl) { return handle_service_.native(impl); @@ -182,32 +101,9 @@ public: asio::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, asio::error_code& ec) { - using namespace std; // For memcpy. - - ::DCB dcb; - memset(&dcb, 0, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - if (!::GetCommState(handle_service_.native(impl), &dcb)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - if (option.store(dcb, ec)) - return ec; - - if (!::SetCommState(handle_service_.native(impl), &dcb)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - ec = asio::error_code(); - return ec; + return do_set_option(impl, + &win_iocp_serial_port_service::store_option<SettableSerialPortOption>, + &option, ec); } // Get an option from the serial port. @@ -215,20 +111,9 @@ public: asio::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, asio::error_code& ec) const { - using namespace std; // For memcpy. - - ::DCB dcb; - memset(&dcb, 0, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - if (!::GetCommState(handle_service_.native(impl), &dcb)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return ec; - } - - return option.load(dcb, ec); + return do_get_option(impl, + &win_iocp_serial_port_service::load_option<GettableSerialPortOption>, + &option, ec); } // Send a break sequence to the serial port. @@ -274,6 +159,41 @@ public: } private: + // Function pointer type for storing a serial port option. + typedef asio::error_code (*store_function_type)( + const void*, ::DCB&, asio::error_code&); + + // Helper function template to store a serial port option. + template <typename SettableSerialPortOption> + static asio::error_code store_option(const void* option, + ::DCB& storage, asio::error_code& ec) + { + return static_cast<const SettableSerialPortOption*>(option)->store( + storage, ec); + } + + // Helper function to set a serial port option. + ASIO_DECL asio::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, asio::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef asio::error_code (*load_function_type)( + void*, const ::DCB&, asio::error_code&); + + // Helper function template to load a serial port option. + template <typename GettableSerialPortOption> + static asio::error_code load_option(void* option, + const ::DCB& storage, asio::error_code& ec) + { + return static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + } + + // Helper function to get a serial port option. + ASIO_DECL asio::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, asio::error_code& ec) const; + // The implementation used for initiating asynchronous operations. win_iocp_handle_service handle_service_; }; @@ -281,8 +201,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_IOCP) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_serial_port_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + #endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP diff --git a/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp b/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp new file mode 100644 index 0000000000..a71c7c0de5 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_socket_accept_op.hpp @@ -0,0 +1,158 @@ +// +// detail/win_iocp_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/win_iocp_socket_service_base.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Socket, typename Protocol, typename Handler> +class win_iocp_socket_accept_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); + + win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, + socket_type socket, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler handler) + : operation(&win_iocp_socket_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(handler) + { + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Socket::native_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, ec); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp b/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp new file mode 100644 index 0000000000..3ab4fcb4d5 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_socket_recv_op.hpp @@ -0,0 +1,108 @@ +// +// detail/win_iocp_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Handler> +class win_iocp_socket_recv_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); + + win_iocp_socket_recv_op(socket_ops::state_type state, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_recv_op::do_complete), + state_(state), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(o->buffers_), + ec, bytes_transferred); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::state_type state_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp b/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp new file mode 100644 index 0000000000..d1e2ecec58 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -0,0 +1,116 @@ +// +// detail/win_iocp_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Endpoint, typename Handler> +class win_iocp_socket_recvfrom_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); + + win_iocp_socket_recvfrom_op(Endpoint& endpoint, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_recvfrom_op::do_complete), + endpoint_(endpoint), + endpoint_size_(static_cast<int>(endpoint.capacity())), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + int& endpoint_size() + { + return endpoint_size_; + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_recvfrom_op* o( + static_cast<win_iocp_socket_recvfrom_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); + + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Endpoint& endpoint_; + int endpoint_size_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_socket_send_op.hpp b/ext/asio/asio/detail/win_iocp_socket_send_op.hpp new file mode 100644 index 0000000000..56f3f2d304 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_socket_send_op.hpp @@ -0,0 +1,102 @@ +// +// detail/win_iocp_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/utility/addressof.hpp> +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Handler> +class win_iocp_socket_send_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); + + win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, + const ConstBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_send_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + asio::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_send(o->cancel_token_, ec); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + asio::detail::fenced_block b; + asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP diff --git a/ext/asio/asio/detail/win_iocp_socket_service.hpp b/ext/asio/asio/detail/win_iocp_socket_service.hpp index cb1d2037de..b476f8bb2b 100644 --- a/ext/asio/asio/detail/win_iocp_socket_service.hpp +++ b/ext/asio/asio/detail/win_iocp_socket_service.hpp @@ -1,8 +1,8 @@ // -// win_iocp_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,19 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/win_iocp_io_service_fwd.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) -#include "asio/detail/push_options.hpp" #include <cstring> -#include <boost/shared_ptr.hpp> -#include <boost/type_traits/is_same.hpp> -#include <boost/weak_ptr.hpp> -#include "asio/detail/pop_options.hpp" - +#include <boost/utility/addressof.hpp> #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" @@ -37,20 +30,27 @@ #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" -#include "asio/detail/null_buffers_op.hpp" #include "asio/detail/operation.hpp" +#include "asio/detail/reactive_socket_connect_op.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/win_iocp_io_service.hpp" +#include "asio/detail/win_iocp_null_buffers_op.hpp" +#include "asio/detail/win_iocp_socket_accept_op.hpp" +#include "asio/detail/win_iocp_socket_recvfrom_op.hpp" +#include "asio/detail/win_iocp_socket_send_op.hpp" +#include "asio/detail/win_iocp_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace detail { template <typename Protocol> -class win_iocp_socket_service +class win_iocp_socket_service : public win_iocp_socket_service_base { public: // The protocol type. @@ -59,10 +59,6 @@ public: // The endpoint type. typedef typename Protocol::endpoint endpoint_type; - struct noop_deleter { void operator()(void*) {} }; - typedef boost::shared_ptr<void> shared_cancel_token_type; - typedef boost::weak_ptr<void> weak_cancel_token_type; - // The native type of a socket. class native_type { @@ -92,11 +88,6 @@ public: return socket_; } - HANDLE as_handle() const - { - return reinterpret_cast<HANDLE>(socket_); - } - bool have_remote_endpoint() const { return have_remote_endpoint_; @@ -114,148 +105,44 @@ public: }; // The implementation type of the socket. - class implementation_type + struct implementation_type : + win_iocp_socket_service_base::base_implementation_type { - public: // Default constructor. implementation_type() - : socket_(invalid_socket), - flags_(0), - cancel_token_(), - protocol_(endpoint_type().protocol()), - next_(0), - prev_(0) + : protocol_(endpoint_type().protocol()), + have_remote_endpoint_(false), + remote_endpoint_() { } - private: - // Only this service will have access to the internal values. - friend class win_iocp_socket_service; - - // The native socket representation. - native_type socket_; - - enum - { - enable_connection_aborted = 1, // User wants connection_aborted errors. - close_might_block = 2, // User set linger option for blocking close. - user_set_non_blocking = 4 // The user wants a non-blocking socket. - }; - - // Flags indicating the current state of the socket. - unsigned char flags_; - - // We use a shared pointer as a cancellation token here to work around the - // broken Windows support for cancellation. MSDN says that when you call - // closesocket any outstanding WSARecv or WSASend operations will complete - // with the error ERROR_OPERATION_ABORTED. In practice they complete with - // ERROR_NETNAME_DELETED, which means you can't tell the difference between - // a local cancellation and the socket being hard-closed by the peer. - shared_cancel_token_type cancel_token_; - // The protocol associated with the socket. protocol_type protocol_; - // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; - -#if defined(ASIO_ENABLE_CANCELIO) - // The ID of the thread from which it is safe to cancel asynchronous - // operations. 0 means no asynchronous operations have been started yet. - // ~0 means asynchronous operations have been started from more than one - // thread, and cancellation is not supported for the socket. - DWORD safe_cancellation_thread_id_; -#endif // defined(ASIO_ENABLE_CANCELIO) + // Whether we have a cached remote endpoint. + bool have_remote_endpoint_; - // Pointers to adjacent socket implementations in linked list. - implementation_type* next_; - implementation_type* prev_; + // A cached remote endpoint. + endpoint_type remote_endpoint_; }; // Constructor. win_iocp_socket_service(asio::io_service& io_service) - : io_service_(io_service), - iocp_service_(use_service<win_iocp_io_service>(io_service)), - reactor_(0), - mutex_(), - impl_list_(0) - { - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + : win_iocp_socket_service_base(io_service) { - // Close all implementations, causing all operations to complete. - asio::detail::mutex::scoped_lock lock(mutex_); - implementation_type* impl = impl_list_; - while (impl) - { - asio::error_code ignored_ec; - close_for_destruction(*impl); - impl = impl->next_; - } - } - - // Construct a new socket implementation. - void construct(implementation_type& impl) - { - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(ASIO_ENABLE_CANCELIO) - - // Insert implementation into linked list of all implementations. - asio::detail::mutex::scoped_lock lock(mutex_); - impl.next_ = impl_list_; - impl.prev_ = 0; - if (impl_list_) - impl_list_->prev_ = &impl; - impl_list_ = &impl; - } - - // Destroy a socket implementation. - void destroy(implementation_type& impl) - { - close_for_destruction(impl); - - // Remove implementation from linked list of all implementations. - asio::detail::mutex::scoped_lock lock(mutex_); - if (impl_list_ == &impl) - impl_list_ = impl.next_; - if (impl.prev_) - impl.prev_->next_ = impl.next_; - if (impl.next_) - impl.next_->prev_= impl.prev_; - impl.next_ = 0; - impl.prev_ = 0; } // Open a new socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { - if (is_open(impl)) + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) { - ec = asio::error::already_open; - return ec; + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = false; + impl.remote_endpoint_ = endpoint_type(); } - - socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(), - protocol.protocol(), ec)); - if (sock.get() == invalid_socket) - return ec; - - HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get()); - if (iocp_service_.register_handle(sock_as_handle, ec)) - return ec; - - impl.socket_ = sock.release(); - impl.flags_ = 0; - impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter()); - impl.protocol_ = protocol; - ec = asio::error_code(); return ec; } @@ -264,247 +151,40 @@ public: const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { - if (is_open(impl)) - { - ec = asio::error::already_open; - return ec; - } - - if (iocp_service_.register_handle(native_socket.as_handle(), ec)) - return ec; - - impl.socket_ = native_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter()); - impl.protocol_ = protocol; - ec = asio::error_code(); - return ec; - } - - // Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return impl.socket_ != invalid_socket; - } - - // Destroy a socket implementation. - asio::error_code close(implementation_type& impl, - asio::error_code& ec) - { - if (is_open(impl)) + if (!do_assign(impl, protocol.type(), native_socket, ec)) { - // Check if the reactor was created, in which case we need to close the - // socket on the reactor as well to cancel any operations that might be - // running there. - reactor* r = static_cast<reactor*>( - interlocked_compare_exchange_pointer( - reinterpret_cast<void**>(&reactor_), 0, 0)); - if (r) - r->close_descriptor(impl.socket_, impl.reactor_data_); - - if (socket_ops::close(impl.socket_, ec) == socket_error_retval) - return ec; - - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(ASIO_ENABLE_CANCELIO) + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); + impl.remote_endpoint_ = native_socket.remote_endpoint(); } - - ec = asio::error_code(); return ec; } // Get the native socket representation. native_type native(implementation_type& impl) { - return impl.socket_; - } - - // Cancel all operations associated with the socket. - asio::error_code cancel(implementation_type& impl, - asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( - ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) - { - // The version of Windows supports cancellation from any thread. - typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); - if (!cancel_io_ex(sock_as_handle, 0)) - { - DWORD last_error = ::GetLastError(); - if (last_error == ERROR_NOT_FOUND) - { - // ERROR_NOT_FOUND means that there were no operations to be - // cancelled. We swallow this error to match the behaviour on other - // platforms. - ec = asio::error_code(); - } - else - { - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - } - else - { - ec = asio::error_code(); - } - } -#if defined(ASIO_ENABLE_CANCELIO) - else if (impl.safe_cancellation_thread_id_ == 0) - { - // No operations have been started, so there's nothing to cancel. - ec = asio::error_code(); - } - else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) - { - // Asynchronous operations have been started from the current thread only, - // so it is safe to try to cancel them using CancelIo. - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); - if (!::CancelIo(sock_as_handle)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - } - else - { - ec = asio::error_code(); - } - } - else - { - // Asynchronous operations have been started from more than one thread, - // so cancellation is not safe. - ec = asio::error::operation_not_supported; - } -#else // defined(ASIO_ENABLE_CANCELIO) - else - { - // Cancellation is not supported as CancelIo may not be used. - ec = asio::error::operation_not_supported; - } -#endif // defined(ASIO_ENABLE_CANCELIO) - - return ec; - } - - // Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - asio::error_code& ec) const - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return false; - } - - asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); - return ec ? false : value != 0; - } - - // Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - asio::error_code& ec) const - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); - return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value); + if (impl.have_remote_endpoint_) + return native_type(impl.socket_, impl.remote_endpoint_); + return native_type(impl.socket_); } // Bind the socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } - // Place the socket into the state where it will listen for new connections. - asio::error_code listen(implementation_type& impl, int backlog, - asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - socket_ops::listen(impl.socket_, backlog, ec); - return ec; - } - // Set a socket option. template <typename Option> asio::error_code set_option(implementation_type& impl, const Option& option, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = asio::error::invalid_argument; - } - else - { - if (*reinterpret_cast<const int*>(option.data(impl.protocol_))) - impl.flags_ |= implementation_type::enable_connection_aborted; - else - impl.flags_ &= ~implementation_type::enable_connection_aborted; - ec = asio::error_code(); - } - return ec; - } - else - { - if (option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_LINGER) - { - const ::linger* linger_option = - reinterpret_cast<const ::linger*>(option.data(impl.protocol_)); - if (linger_option->l_onoff != 0 && linger_option->l_linger != 0) - impl.flags_ |= implementation_type::close_might_block; - else - impl.flags_ &= ~implementation_type::close_might_block; - } - - socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_), ec); - return ec; - } + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } // Set a socket option. @@ -512,65 +192,12 @@ public: asio::error_code get_option(const implementation_type& impl, Option& option, asio::error_code& ec) const { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = asio::error::invalid_argument; - } - else - { - int* target = reinterpret_cast<int*>(option.data(impl.protocol_)); - if (impl.flags_ & implementation_type::enable_connection_aborted) - *target = 1; - else - *target = 0; - option.resize(impl.protocol_, sizeof(int)); - ec = asio::error_code(); - } - return ec; - } - else - { - size_t size = option.size(impl.protocol_); - socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size, ec); - if (!ec) - option.resize(impl.protocol_, size); - return ec; - } - } - - // Perform an IO control command on the socket. - template <typename IO_Control_Command> - asio::error_code io_control(implementation_type& impl, - IO_Control_Command& command, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - socket_ops::ioctl(impl.socket_, command.name(), - static_cast<ioctl_arg_type*>(command.data()), ec); - - if (!ec && command.name() == static_cast<int>(FIONBIO)) - { - if (*static_cast<ioctl_arg_type*>(command.data())) - impl.flags_ |= implementation_type::user_set_non_blocking; - else - impl.flags_ &= ~implementation_type::user_set_non_blocking; - } - + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); return ec; } @@ -578,12 +205,6 @@ public: endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) @@ -596,210 +217,13 @@ public: endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; + endpoint_type endpoint = impl.remote_endpoint_; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), + &addr_len, impl.have_remote_endpoint_, ec)) return endpoint_type(); - } - - if (impl.socket_.have_remote_endpoint()) - { - // Check if socket is still connected. - DWORD connect_time = 0; - size_t connect_time_len = sizeof(connect_time); - if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME, - &connect_time, &connect_time_len, ec) == socket_error_retval) - { - return endpoint_type(); - } - if (connect_time == 0xFFFFFFFF) - { - ec = asio::error::not_connected; - return endpoint_type(); - } - - ec = asio::error_code(); - return impl.socket_.remote_endpoint(); - } - else - { - endpoint_type endpoint; - std::size_t addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) - return endpoint_type(); - endpoint.resize(addr_len); - return endpoint; - } - } - - /// Disable sends or receives on the socket. - asio::error_code shutdown(implementation_type& impl, - socket_base::shutdown_type what, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - socket_ops::shutdown(impl.socket_, what, ec); - return ec; - } - - // Send the given data to the peer. Returns the number of bytes sent. - template <typename ConstBufferSequence> - size_t send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = asio::error_code(); - return 0; - } - - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, flags, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - - ec = asio::error_code(); - return bytes_transferred; - } - - // Wait until data can be sent without blocking. - size_t send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, ec); - - return 0; - } - - template <typename ConstBufferSequence, typename Handler> - class send_op : public operation - { - public: - send_op(weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler handler) - : operation(&send_op::do_complete), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - send_op* o(static_cast<send_op*>(base)); - typedef handler_alloc_traits<Handler, send_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::validate(o->buffers_); -#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (o->cancel_token_.expired()) - ec = asio::error::operation_aborted; - else - ec = asio::error::connection_reset; - } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = asio::error::connection_refused; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - weak_cancel_token_type cancel_token_; - ConstBufferSequence buffers_; - Handler handler_; - }; - - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef send_op<ConstBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, - impl.cancel_token_, buffers, handler); - - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(buffers); - - start_send_op(impl, bufs.buffers(), bufs.count(), flags, - impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get()); - ptr.release(); - } - - // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> - void async_send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - start_reactor_op(impl, reactor::write_op, ptr.get()); - ptr.release(); + endpoint.resize(addr_len); + return endpoint; } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -809,107 +233,25 @@ public: const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(), - &bytes_transferred, flags, destination.data(), - static_cast<int>(destination.size()), 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - - ec = asio::error_code(); - return bytes_transferred; + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); } // Wait until data can be sent without blocking. size_t send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, + const endpoint_type&, socket_base::message_flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } - template <typename ConstBufferSequence, typename Handler> - class send_to_op : public operation - { - public: - send_to_op(weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler handler) - : operation(&send_to_op::do_complete), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - send_to_op* o(static_cast<send_to_op*>(base)); - typedef handler_alloc_traits<Handler, send_to_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::validate(o->buffers_); -#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = asio::error::connection_refused; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - weak_cancel_token_type cancel_token_; - ConstBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> @@ -918,233 +260,35 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef send_to_op<ConstBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, - impl.cancel_token_, buffers, handler); + typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); - start_send_to_op(impl, bufs.buffers(), - bufs.count(), destination, flags, ptr.get()); - ptr.release(); + start_send_to_op(impl, bufs.buffers(), bufs.count(), + destination.data(), static_cast<int>(destination.size()), + flags, p.p); + p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template <typename Handler> void async_send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - start_reactor_op(impl, reactor::write_op, ptr.get()); - ptr.release(); - } - - // Receive some data from the peer. Returns the number of bytes received. - template <typename MutableBufferSequence> - size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = asio::error_code(); - return 0; - } - - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, &recv_flags, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = asio::error::eof; - return 0; - } - - ec = asio::error_code(); - return bytes_transferred; - } - - // Wait until data can be received without blocking. - size_t receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags, asio::error_code& ec) - { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, ec); - - return 0; - } - - template <typename MutableBufferSequence, typename Handler> - class receive_op : public operation - { - public: - receive_op(int protocol_type, weak_cancel_token_type cancel_token, - const MutableBufferSequence& buffers, Handler handler) - : operation(&receive_op::do_complete), - protocol_type_(protocol_type), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - receive_op* o(static_cast<receive_op*>(base)); - typedef handler_alloc_traits<Handler, receive_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::validate(o->buffers_); -#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (o->cancel_token_.expired()) - ec = asio::error::operation_aborted; - else - ec = asio::error::connection_reset; - } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = asio::error::connection_refused; - } - - // Check for connection closed. - else if (!ec && bytes_transferred == 0 - && o->protocol_type_ == SOCK_STREAM - && !buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::all_empty(o->buffers_) - && !boost::is_same<MutableBufferSequence, null_buffers>::value) - { - ec = asio::error::eof; - } - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - int protocol_type_; - weak_cancel_token_type cancel_token_; - MutableBufferSequence buffers_; - Handler handler_; - }; - - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) + const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_op<MutableBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type, - impl.cancel_token_, buffers, handler); - - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(buffers); + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); - start_receive_op(impl, bufs.buffers(), bufs.count(), flags, - protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get()); - ptr.release(); - } - - // Wait until data can be received without blocking. - template <typename Handler> - void async_receive(implementation_type& impl, const null_buffers& buffers, - socket_base::message_flags flags, Handler handler) - { - if (impl.protocol_.type() == SOCK_STREAM) - { - // For stream sockets on Windows, we may issue a 0-byte overlapped - // WSARecv to wait until there is data available on the socket. - - // Allocate and construct an operation to wrap the handler. - typedef receive_op<null_buffers, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type, - impl.cancel_token_, buffers, handler); - - ::WSABUF buf = { 0, 0 }; - start_receive_op(impl, &buf, 1, flags, false, ptr.get()); - ptr.release(); - } - else - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); - - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get()); - ptr.release(); - } + start_reactor_op(impl, reactor::write_op, p.p); + p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1155,41 +299,18 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int endpoint_size = static_cast<int>(sender_endpoint.capacity()); - int result = ::WSARecvFrom(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, &recv_flags, - sender_endpoint.data(), &endpoint_size, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::get_system_category()); - return 0; - } - if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = asio::error::eof; - return 0; - } + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); - sender_endpoint.resize(static_cast<std::size_t>(endpoint_size)); + if (!ec) + sender_endpoint.resize(addr_len); - ec = asio::error_code(); - return bytes_transferred; + return bytes_recvd; } // Wait until data can be received without blocking. @@ -1197,12 +318,6 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); @@ -1212,75 +327,6 @@ public: return 0; } - template <typename MutableBufferSequence, typename Handler> - class receive_from_op : public operation - { - public: - receive_from_op(int protocol_type, endpoint_type& endpoint, - const MutableBufferSequence& buffers, Handler handler) - : operation(&receive_from_op::do_complete), - protocol_type_(protocol_type), - endpoint_(endpoint), - endpoint_size_(static_cast<int>(endpoint.capacity())), - buffers_(buffers), - handler_(handler) - { - } - - int& endpoint_size() - { - return endpoint_size_; - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - receive_from_op* o(static_cast<receive_from_op*>(base)); - typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::validate(o->buffers_); -#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = asio::error::connection_refused; - } - - // Record the size of the endpoint returned by the operation. - o->endpoint_.resize(o->endpoint_size_); - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder2<Handler, asio::error_code, std::size_t> - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - int protocol_type_; - endpoint_type& endpoint_; - int endpoint_size_; - weak_cancel_token_type cancel_token_; - MutableBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1290,19 +336,19 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_from_op<MutableBufferSequence, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr<alloc_traits> ptr(raw_ptr, - protocol_type, sender_endp, buffers, handler); + typedef win_iocp_socket_recvfrom_op< + MutableBufferSequence, endpoint_type, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); start_receive_from_op(impl, bufs.buffers(), bufs.count(), - sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get()); - ptr.release(); + sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + p.v = p.p = 0; } // Wait until data can be received without blocking. @@ -1312,19 +358,17 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, handler); + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get()); - ptr.release(); + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; } // Accept a new connection. @@ -1332,12 +376,6 @@ public: asio::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - // We cannot accept a socket that is already open. if (peer.is_open()) { @@ -1345,222 +383,22 @@ public: return ec; } - for (;;) - { - socket_holder new_socket; - std::size_t addr_len = 0; - if (peer_endpoint) - { - addr_len = peer_endpoint->capacity(); - new_socket.reset(socket_ops::accept(impl.socket_, - peer_endpoint->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); - } - - if (ec) - { - if (ec == asio::error::connection_aborted - && !(impl.flags_ & implementation_type::enable_connection_aborted)) - { - // Retry accept operation. - continue; - } - else - { - return ec; - } - } + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + // On success, assign new connection to peer socket object. + if (new_socket.get() >= 0) + { if (peer_endpoint) peer_endpoint->resize(addr_len); - - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) new_socket.release(); - return ec; - } - } - - template <typename Socket, typename Handler> - class accept_op : public operation - { - public: - accept_op(win_iocp_io_service& iocp_service, socket_type socket, - Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : operation(&accept_op::do_complete), - iocp_service_(iocp_service), - socket_(socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted), - handler_(handler) - { } - socket_holder& new_socket() - { - return new_socket_; - } - - void* output_buffer() - { - return output_buffer_; - } - - DWORD address_length() - { - return sizeof(sockaddr_storage_type) + 16; - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code ec, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - accept_op* o(static_cast<accept_op*>(base)); - typedef handler_alloc_traits<Handler, accept_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. - if (ec.value() == ERROR_NETNAME_DELETED) - { - ec = asio::error::connection_aborted; - } - - // Restart the accept operation if we got the connection_aborted error - // and the enable_connection_aborted socket option is not set. - if (ec == asio::error::connection_aborted - && !o->enable_connection_aborted_) - { - // Reset OVERLAPPED structure. - o->reset(); - - // Create a new socket for the next connection, since the AcceptEx - // call fails with WSAEINVAL if we try to reuse the same socket. - o->new_socket_.reset(); - o->new_socket_.reset(socket_ops::socket(o->protocol_.family(), - o->protocol_.type(), o->protocol_.protocol(), ec)); - if (o->new_socket_.get() != invalid_socket) - { - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(), - o->output_buffer(), 0, o->address_length(), - o->address_length(), &bytes_read, o); - DWORD last_error = ::WSAGetLastError(); - ec = asio::error_code(last_error, - asio::error::get_system_category()); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) - { - if (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED) - { - // Post this handler so that operation will be restarted again. - o->iocp_service_.work_started(); - o->iocp_service_.on_completion(o, ec); - ptr.release(); - return; - } - else - { - // Operation already complete. Continue with rest of this - // handler. - } - } - else - { - // Asynchronous operation has been successfully restarted. - o->iocp_service_.work_started(); - o->iocp_service_.on_pending(o); - ptr.release(); - return; - } - } - } - - // Get the address of the peer. - endpoint_type peer_endpoint; - if (!ec) - { - LPSOCKADDR local_addr = 0; - int local_addr_length = 0; - LPSOCKADDR remote_addr = 0; - int remote_addr_length = 0; - GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(), - o->address_length(), &local_addr, &local_addr_length, - &remote_addr, &remote_addr_length); - if (static_cast<std::size_t>(remote_addr_length) - > peer_endpoint.capacity()) - { - ec = asio::error::invalid_argument; - } - else - { - using namespace std; // For memcpy. - memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length)); - } - } - - // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname - // and getpeername will work on the accepted socket. - if (!ec) - { - SOCKET update_ctx_param = o->socket_; - socket_ops::setsockopt(o->new_socket_.get(), - SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET), ec); - } - - // If the socket was successfully accepted, transfer ownership of the - // socket to the peer object. - if (!ec) - { - o->peer_.assign(o->protocol_, - native_type(o->new_socket_.get(), peer_endpoint), ec); - if (!ec) - o->new_socket_.release(); - } - - // Pass endpoint back to caller. - if (o->peer_endpoint_) - *o->peer_endpoint_ = peer_endpoint; - - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder1<Handler, asio::error_code> - handler(o->handler_, ec); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - win_iocp_io_service& iocp_service_; - socket_type socket_; - socket_holder new_socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type* peer_endpoint_; - unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; - bool enable_connection_aborted_; - Handler handler_; - }; + return ec; + } // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. @@ -1569,442 +407,54 @@ public: endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef accept_op<Socket, Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); + typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted); - handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, impl.socket_, peer, - impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler); - start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(), - ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get()); - ptr.release(); + start_accept_op(impl, peer.is_open(), p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; } // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { - if (!is_open(impl)) - { - ec = asio::error::bad_descriptor; - return ec; - } - - // Perform the connect operation. - socket_ops::connect(impl.socket_, + socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); return ec; } - class connect_op_base : public reactor_op - { - public: - connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&connect_op_base::do_perform, complete_func), - socket_(socket) - { - } - - static bool do_perform(reactor_op* base) - { - connect_op_base* o(static_cast<connect_op_base*>(base)); - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, o->ec_) == socket_error_retval) - return true; - - // The connection failed so the handler will be posted with an error code. - if (connect_error) - { - o->ec_ = asio::error_code(connect_error, - asio::error::get_system_category()); - } - - return true; - } - - private: - socket_type socket_; - }; - - template <typename Handler> - class connect_op : public connect_op_base - { - public: - connect_op(socket_type socket, Handler handler) - : connect_op_base(socket, &connect_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - connect_op* o(static_cast<connect_op*>(base)); - typedef handler_alloc_traits<Handler, connect_op> alloc_traits; - handler_ptr<alloc_traits> ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Make a copy of the handler so that the memory can be deallocated - // before the upcall is made. Even if we're not about to make an - // upcall, a sub-object of the handler may be the true owner of the - // memory associated with the handler. Consequently, a local copy of - // the handler is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - detail::binder1<Handler, asio::error_code> - handler(o->handler_, o->ec_); - ptr.reset(); - asio::detail::fenced_block b; - asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous connect. template <typename Handler> void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef connect_op<Handler> value_type; - typedef handler_alloc_traits<Handler, value_type> alloc_traits; - raw_handler_ptr<alloc_traits> raw_ptr(handler); - handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, handler); - - start_connect_op(impl, ptr.get(), peer_endpoint); - ptr.release(); - } - -private: - // Helper function to start an asynchronous send operation. - void start_send_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, socket_base::message_flags flags, - bool noop, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (noop) - iocp_service_.on_completion(op); - else if (!is_open(impl)) - iocp_service_.on_completion(op, asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, buffers, - buffer_count, &bytes_transferred, flags, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous send_to operation. - void start_send_to_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, const endpoint_type& destination, - socket_base::message_flags flags, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); + typedef reactive_socket_connect_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); - if (!is_open(impl)) - iocp_service_.on_completion(op, asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, buffers, buffer_count, - &bytes_transferred, flags, destination.data(), - static_cast<int>(destination.size()), op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } + start_connect_op(impl, p.p, peer_endpoint.data(), + static_cast<int>(peer_endpoint.size())); + p.v = p.p = 0; } - - // Helper function to start an asynchronous receive operation. - void start_receive_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, socket_base::message_flags flags, - bool noop, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (noop) - iocp_service_.on_completion(op); - else if (!is_open(impl)) - iocp_service_.on_completion(op, asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, buffers, buffer_count, - &bytes_transferred, &recv_flags, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive_from operation. - void start_receive_from_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, endpoint_type& sender_endpoint, - socket_base::message_flags flags, int* endpoint_size, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecvFrom(impl.socket_, buffers, - buffer_count, &bytes_transferred, &recv_flags, - sender_endpoint.data(), endpoint_size, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive_from operation. - void start_accept_op(implementation_type& impl, - bool peer_is_open, socket_holder& new_socket, - void* output_buffer, DWORD address_length, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, asio::error::bad_descriptor); - else if (peer_is_open) - iocp_service_.on_completion(op, asio::error::already_open); - else - { - asio::error_code ec; - new_socket.reset(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol(), ec)); - if (new_socket.get() == invalid_socket) - iocp_service_.on_completion(op, ec); - else - { - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, - 0, address_length, address_length, &bytes_read, op); - DWORD last_error = ::WSAGetLastError(); - if (!result && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error); - else - iocp_service_.on_pending(op); - } - } - } - - // Start an asynchronous read or write operation using the the reactor. - void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op) - { - reactor& r = get_reactor(); - update_cancellation_thread_id(impl); - - if (is_open(impl)) - { - r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); - return; - } - else - op->ec_ = asio::error::bad_descriptor; - - iocp_service_.post_immediate_completion(op); - } - - // Start the asynchronous connect operation using the reactor. - void start_connect_op(implementation_type& impl, - reactor_op* op, const endpoint_type& peer_endpoint) - { - reactor& r = get_reactor(); - update_cancellation_thread_id(impl); - - if (is_open(impl)) - { - ioctl_arg_type non_blocking = 1; - if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_)) - { - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), op->ec_) != 0) - { - if (!op->ec_ - && !(impl.flags_ & implementation_type::user_set_non_blocking)) - { - non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_); - } - - if (op->ec_ == asio::error::in_progress - || op->ec_ == asio::error::would_block) - { - op->ec_ = asio::error_code(); - r.start_op(reactor::connect_op, impl.socket_, - impl.reactor_data_, op, true); - return; - } - } - } - } - else - op->ec_ = asio::error::bad_descriptor; - - iocp_service_.post_immediate_completion(op); - } - - // Helper function to close a socket when the associated object is being - // destroyed. - void close_for_destruction(implementation_type& impl) - { - if (is_open(impl)) - { - // Check if the reactor was created, in which case we need to close the - // socket on the reactor as well to cancel any operations that might be - // running there. - reactor* r = static_cast<reactor*>( - interlocked_compare_exchange_pointer( - reinterpret_cast<void**>(&reactor_), 0, 0)); - if (r) - r->close_descriptor(impl.socket_, impl.reactor_data_); - - // The socket destructor must not block. If the user has changed the - // linger option to block in the foreground, we will change it back to the - // default so that the closure is performed in the background. - if (impl.flags_ & implementation_type::close_might_block) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - asio::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - asio::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(ASIO_ENABLE_CANCELIO) - } - } - - // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id(implementation_type& impl) - { -#if defined(ASIO_ENABLE_CANCELIO) - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#else // defined(ASIO_ENABLE_CANCELIO) - (void)impl; -#endif // defined(ASIO_ENABLE_CANCELIO) - } - - // Helper function to get the reactor. If no reactor has been created yet, a - // new one is obtained from the io_service and a pointer to it is cached in - // this service. - reactor& get_reactor() - { - reactor* r = static_cast<reactor*>( - interlocked_compare_exchange_pointer( - reinterpret_cast<void**>(&reactor_), 0, 0)); - if (!r) - { - r = &(use_service<reactor>(io_service_)); - interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); - } - return *r; - } - - // Helper function to emulate InterlockedCompareExchangePointer functionality - // for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. - void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp) - { -#if defined(_M_IX86) - return reinterpret_cast<void*>(InterlockedCompareExchange( - reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch), - reinterpret_cast<LONG>(cmp))); -#else - return InterlockedCompareExchangePointer(dest, exch, cmp); -#endif - } - - // Helper function to emulate InterlockedExchangePointer functionality for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. - void* interlocked_exchange_pointer(void** dest, void* val) - { -#if defined(_M_IX86) - return reinterpret_cast<void*>(InterlockedExchange( - reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val))); -#else - return InterlockedExchangePointer(dest, val); -#endif - } - - // The io_service used to obtain the reactor, if required. - asio::io_service& io_service_; - - // The IOCP service used for running asynchronous operations and dispatching - // handlers. - win_iocp_io_service& iocp_service_; - - // The reactor used for performing connect operations. This object is created - // only if needed. - reactor* reactor_; - - // Mutex to protect access to the linked list of implementations. - asio::detail::mutex mutex_; - - // The head of a linked list of all implementations. - implementation_type* impl_list_; }; } // namespace detail } // namespace asio -#endif // defined(ASIO_HAS_IOCP) - #include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_IOCP) + #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP diff --git a/ext/asio/asio/detail/win_iocp_socket_service_base.hpp b/ext/asio/asio/detail/win_iocp_socket_service_base.hpp new file mode 100644 index 0000000000..62010b3d14 --- /dev/null +++ b/ext/asio/asio/detail/win_iocp_socket_service_base.hpp @@ -0,0 +1,385 @@ +// +// detail/win_iocp_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/addressof.hpp> +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/win_iocp_io_service.hpp" +#include "asio/detail/win_iocp_null_buffers_op.hpp" +#include "asio/detail/win_iocp_socket_send_op.hpp" +#include "asio/detail/win_iocp_socket_recv_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_socket_service_base +{ +public: + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // We use a shared pointer as a cancellation token here to work around the + // broken Windows support for cancellation. MSDN says that when you call + // closesocket any outstanding WSARecv or WSASend operations will complete + // with the error ERROR_OPERATION_ABORTED. In practice they complete with + // ERROR_NETNAME_DELETED, which means you can't tell the difference between + // a local cancellation and the socket being hard-closed by the peer. + socket_ops::shared_cancel_token_type cancel_token_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + +#if defined(ASIO_ENABLE_CANCELIO) + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the socket. + DWORD safe_cancellation_thread_id_; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL win_iocp_socket_service_base( + asio::io_service& io_service); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown_service(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast<ioctl_arg_type*>(command.data()), ec); + return ec; + } + + /// Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. Returns the number of bytes sent. + template <typename ConstBufferSequence> + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + start_reactor_op(impl, reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { boost::addressof(handler), + asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Helper function to restart an asynchronous accept operation. + ASIO_DECL void restart_accept_op(socket_type s, + socket_holder& new_socket, int family, int type, int protocol, + void* output_buffer, DWORD address_length, operation* op); + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int family, int type, + int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + socket_type native_socket, asio::error_code& ec); + + // Helper function to start an asynchronous send operation. + ASIO_DECL void start_send_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous send_to operation. + ASIO_DECL void start_send_to_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op); + + // Helper function to start an asynchronous receive operation. + ASIO_DECL void start_receive_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous null_buffers receive operation. + ASIO_DECL void start_null_buffers_receive_op( + base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op); + + // Helper function to start an asynchronous receive_from operation. + ASIO_DECL void start_receive_from_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op); + + // Helper function to start an asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op); + + // Start an asynchronous read or write operation using the the reactor. + ASIO_DECL void start_reactor_op(base_implementation_type& impl, + int op_type, reactor_op* op); + + // Start the asynchronous connect operation using the reactor. + ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, std::size_t addrlen); + + // Helper function to close a socket when the associated object is being + // destroyed. + ASIO_DECL void close_for_destruction(base_implementation_type& impl); + + // Update the ID of the thread from which cancellation is safe. + ASIO_DECL void update_cancellation_thread_id( + base_implementation_type& impl); + + // Helper function to get the reactor. If no reactor has been created yet, a + // new one is obtained from the io_service and a pointer to it is cached in + // this service. + ASIO_DECL reactor& get_reactor(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); + + // The io_service used to obtain the reactor, if required. + asio::io_service& io_service_; + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_service& iocp_service_; + + // The reactor used for performing connect operations. This object is created + // only if needed. + reactor* reactor_; + + // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP diff --git a/ext/asio/asio/detail/win_mutex.hpp b/ext/asio/asio/detail/win_mutex.hpp index 1280a4e402..59ad6976cd 100644 --- a/ext/asio/asio/detail/win_mutex.hpp +++ b/ext/asio/asio/detail/win_mutex.hpp @@ -1,8 +1,8 @@ // -// win_mutex.hpp -// ~~~~~~~~~~~~~ +// detail/win_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" -#include "asio/detail/socket_types.hpp" #include "asio/detail/scoped_lock.hpp" +#include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { @@ -43,18 +35,7 @@ public: typedef asio::detail::scoped_lock<win_mutex> scoped_lock; // Constructor. - win_mutex() - { - int error = do_init(); - if (error != 0) - { - asio::system_error e( - asio::error_code(error, - asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } - } + ASIO_DECL win_mutex(); // Destructor. ~win_mutex() @@ -78,35 +59,7 @@ private: // Initialisation must be performed in a separate function to the constructor // since the compiler does not support the use of structured exceptions and // C++ exceptions in the same function. - int do_init() - { -#if defined(__MINGW32__) - // Not sure if MinGW supports structured exception handling, so for now - // we'll just call the Windows API and hope. -# if defined(UNDER_CE) - ::InitializeCriticalSection(&crit_section_); -# else - ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); -# endif - return 0; -#else - __try - { -# if defined(UNDER_CE) - ::InitializeCriticalSection(&crit_section_); -# else - ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); -# endif - } - __except(GetExceptionCode() == STATUS_NO_MEMORY - ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - return ERROR_OUTOFMEMORY; - } - - return 0; -#endif - } + ASIO_DECL int do_init(); ::CRITICAL_SECTION crit_section_; }; @@ -114,8 +67,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // ASIO_DETAIL_WIN_MUTEX_HPP diff --git a/ext/asio/asio/detail/win_thread.hpp b/ext/asio/asio/detail/win_thread.hpp index 9bf0665c5e..e73d1a4965 100644 --- a/ext/asio/asio/detail/win_thread.hpp +++ b/ext/asio/asio/detail/win_thread.hpp @@ -1,8 +1,8 @@ // -// win_thread.hpp -// ~~~~~~~~~~~~~~ +// detail/win_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,34 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include <memory> -#include <process.h> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { -unsigned int __stdcall win_thread_function(void* arg); +ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) -void __stdcall apc_function(ULONG data); +ASIO_DECL void __stdcall apc_function(ULONG data); #else -void __stdcall apc_function(ULONG_PTR data); +ASIO_DECL void __stdcall apc_function(ULONG_PTR data); #endif template <typename T> @@ -73,92 +63,26 @@ class win_thread public: // Constructor. template <typename Function> - win_thread(Function f) - : exit_event_(0) + win_thread(Function f, unsigned int stack_size = 0) + : thread_(0), + exit_event_(0) { - std::auto_ptr<func_base> arg(new func<Function>(f)); - - ::HANDLE entry_event = 0; - arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); - if (!entry_event) - { - DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "thread.entry_event"); - boost::throw_exception(e); - } - - arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); - if (!exit_event_) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(entry_event); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "thread.exit_event"); - boost::throw_exception(e); - } - - unsigned int thread_id = 0; - thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0, - win_thread_function, arg.get(), 0, &thread_id)); - if (!thread_) - { - DWORD last_error = ::GetLastError(); - if (entry_event) - ::CloseHandle(entry_event); - if (exit_event_) - ::CloseHandle(exit_event_); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); - } - arg.release(); - - if (entry_event) - { - ::WaitForSingleObject(entry_event, INFINITE); - ::CloseHandle(entry_event); - } + start_thread(new func<Function>(f), stack_size); } // Destructor. - ~win_thread() - { - ::CloseHandle(thread_); - - // The exit_event_ handle is deliberately allowed to leak here since it - // is an error for the owner of an internal thread not to join() it. - } + ASIO_DECL ~win_thread(); // Wait for the thread to exit. - void join() - { - ::WaitForSingleObject(exit_event_, INFINITE); - ::CloseHandle(exit_event_); - if (terminate_threads()) - { - ::TerminateThread(thread_, 0); - } - else - { - ::QueueUserAPC(apc_function, thread_, 0); - ::WaitForSingleObject(thread_, INFINITE); - } - } + ASIO_DECL void join(); private: - friend unsigned int __stdcall win_thread_function(void* arg); + friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) - friend void __stdcall apc_function(ULONG); + friend ASIO_DECL void __stdcall apc_function(ULONG); #else - friend void __stdcall apc_function(ULONG_PTR); + friend ASIO_DECL void __stdcall apc_function(ULONG_PTR); #endif class func_base @@ -170,6 +94,12 @@ private: ::HANDLE exit_event_; }; + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + template <typename Function> class func : public func_base @@ -189,44 +119,21 @@ private: Function f_; }; + ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); + ::HANDLE thread_; ::HANDLE exit_event_; }; -inline unsigned int __stdcall win_thread_function(void* arg) -{ - std::auto_ptr<win_thread::func_base> func( - static_cast<win_thread::func_base*>(arg)); - - ::SetEvent(func->entry_event_); - - func->run(); - - // Signal that the thread has finished its work, but rather than returning go - // to sleep to put the thread into a well known state. If the thread is being - // joined during global object destruction then it may be killed using - // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx - // call will be interrupted using QueueUserAPC and the thread will shut down - // cleanly. - HANDLE exit_event = func->exit_event_; - func.reset(); - ::SetEvent(exit_event); - ::SleepEx(INFINITE, TRUE); - - return 0; -} - -#if defined(WINVER) && (WINVER < 0x0500) -inline void __stdcall apc_function(ULONG) {} -#else -inline void __stdcall apc_function(ULONG_PTR) {} -#endif - } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_thread.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + #endif // ASIO_DETAIL_WIN_THREAD_HPP diff --git a/ext/asio/asio/detail/win_tss_ptr.hpp b/ext/asio/asio/detail/win_tss_ptr.hpp index 5a4ed33cc2..fb055f6c43 100644 --- a/ext/asio/asio/detail/win_tss_ptr.hpp +++ b/ext/asio/asio/detail/win_tss_ptr.hpp @@ -1,8 +1,8 @@ // -// win_tss_ptr.hpp -// ~~~~~~~~~~~~~~~ +// detail/win_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,50 +15,30 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" -#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { +// Helper function to create thread-specific storage. +ASIO_DECL DWORD win_tss_ptr_create(); + template <typename T> class win_tss_ptr : private noncopyable { public: -#if defined(UNDER_CE) - enum { out_of_indexes = 0xFFFFFFFF }; -#else - enum { out_of_indexes = TLS_OUT_OF_INDEXES }; -#endif - // Constructor. win_tss_ptr() + : tss_key_(win_tss_ptr_create()) { - tss_key_ = ::TlsAlloc(); - if (tss_key_ == out_of_indexes) - { - DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "tss"); - boost::throw_exception(e); - } } // Destructor. @@ -88,8 +68,12 @@ private: } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_tss_ptr.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // ASIO_DETAIL_WIN_TSS_PTR_HPP diff --git a/ext/asio/asio/detail/wince_thread.hpp b/ext/asio/asio/detail/wince_thread.hpp index 0b6de488a2..1dc999075c 100644 --- a/ext/asio/asio/detail/wince_thread.hpp +++ b/ext/asio/asio/detail/wince_thread.hpp @@ -1,8 +1,8 @@ // -// wince_thread.hpp -// ~~~~~~~~~~~~~~~~ +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && defined(UNDER_CE) -#include "asio/error.hpp" -#include "asio/system_error.hpp" +#include <memory> #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" #include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include <memory> -#include "asio/detail/pop_options.hpp" namespace asio { namespace detail { @@ -53,11 +47,9 @@ public: if (!thread_) { DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); } arg.release(); } @@ -117,8 +109,8 @@ inline DWORD WINAPI wince_thread_function(LPVOID arg) } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) - #include "asio/detail/pop_options.hpp" +#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) + #endif // ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/ext/asio/asio/detail/winsock_init.hpp b/ext/asio/asio/detail/winsock_init.hpp index ae5c4bf598..a410859f3b 100644 --- a/ext/asio/asio/detail/winsock_init.hpp +++ b/ext/asio/asio/detail/winsock_init.hpp @@ -1,8 +1,8 @@ // -// winsock_init.hpp -// ~~~~~~~~~~~~~~~~ +// detail/winsock_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,106 +15,76 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/push_options.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/noncopyable.hpp" -#include "asio/detail/socket_types.hpp" namespace asio { namespace detail { -template <int Major = 2, int Minor = 0> -class winsock_init - : private noncopyable +class winsock_init_base { -private: - // Structure to perform the actual initialisation. - struct do_init +protected: + // Structure to track result of initialisation and number of uses. POD is used + // to ensure that the values are zero-initialised prior to any code being run. + struct data { - do_init() - { - WSADATA wsa_data; - result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data); - } - - ~do_init() - { - ::WSACleanup(); - } - - int result() const - { - return result_; - } - - // Helper function to manage a do_init singleton. The static instance of the - // winsock_init object ensures that this function is always called before - // main, and therefore before any other threads can get started. The do_init - // instance must be static in this function to ensure that it gets - // initialised before any other global objects try to use it. - static boost::shared_ptr<do_init> instance() - { - static boost::shared_ptr<do_init> init(new do_init); - return init; - } - - private: - int result_; + long init_count_; + long result_; }; + ASIO_DECL static void startup(data& d, + unsigned char major, unsigned char minor); + + ASIO_DECL static void cleanup(data& d); + + ASIO_DECL static void throw_on_error(data& d); +}; + +template <int Major = 2, int Minor = 0> +class winsock_init : private winsock_init_base +{ public: - // Constructor. - winsock_init() - : ref_(do_init::instance()) + winsock_init(bool allow_throw = true) + { + startup(data_, Major, Minor); + if (allow_throw) + throw_on_error(data_); + } + + winsock_init(const winsock_init&) { - // Check whether winsock was successfully initialised. This check is not - // performed for the global instance since there will be nobody around to - // catch the exception. - if (this != &instance_ && ref_->result() != 0) - { - asio::system_error e( - asio::error_code(ref_->result(), - asio::error::get_system_category()), - "winsock"); - boost::throw_exception(e); - } + startup(data_, Major, Minor); + throw_on_error(data_); } - // Destructor. ~winsock_init() { + cleanup(data_); } private: - // Instance to force initialisation of winsock at global scope. - static winsock_init instance_; - - // Reference to singleton do_init object to ensure that winsock does not get - // cleaned up until the last user has finished with it. - boost::shared_ptr<do_init> ref_; + static data data_; }; template <int Major, int Minor> -winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_; +winsock_init_base::data winsock_init<Major, Minor>::data_; + +// Static variable to ensure that winsock is initialised before main, and +// therefore before any other threads can get started. +static const winsock_init<>& winsock_init_instance = winsock_init<>(false); } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winsock_init.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // ASIO_DETAIL_WINSOCK_INIT_HPP diff --git a/ext/asio/asio/detail/wrapped_handler.hpp b/ext/asio/asio/detail/wrapped_handler.hpp index e40a7f1585..bcebf6ee1d 100644 --- a/ext/asio/asio/detail/wrapped_handler.hpp +++ b/ext/asio/asio/detail/wrapped_handler.hpp @@ -1,8 +1,8 @@ // -// wrapped_handler.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/wrapped_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/type_traits/add_reference.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -34,9 +30,7 @@ class wrapped_handler public: typedef void result_type; - wrapped_handler( - typename boost::add_reference<Dispatcher>::type dispatcher, - Handler handler) + wrapped_handler(Dispatcher dispatcher, Handler handler) : dispatcher_(dispatcher), handler_(handler) { diff --git a/ext/asio/asio/error.hpp b/ext/asio/asio/error.hpp index 73caac6abd..138b5d789c 100644 --- a/ext/asio/asio/error.hpp +++ b/ext/asio/asio/error.hpp @@ -2,7 +2,7 @@ // error.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <cerrno> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error_code.hpp" -#include "asio/detail/socket_types.hpp" +#include "asio/detail/config.hpp" +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include <winerror.h> +#else +# include <cerrno> +# include <netdb.h> +#endif #if defined(GENERATING_DOCUMENTATION) /// INTERNAL ONLY. @@ -50,6 +48,8 @@ # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif +#include "asio/detail/push_options.hpp" + namespace asio { namespace error { @@ -212,7 +212,21 @@ enum ssl_errors { }; -// boostify: error category definitions go here. +// boostify: error category definitions start here. + +} // namespace error +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace error { + +// boostify: error category definitions end here. inline asio::error_code make_error_code(basic_errors e) { @@ -247,14 +261,16 @@ inline asio::error_code make_error_code(ssl_errors e) } // namespace error } // namespace asio +#include "asio/detail/pop_options.hpp" + #undef ASIO_NATIVE_ERROR #undef ASIO_SOCKET_ERROR #undef ASIO_NETDB_ERROR #undef ASIO_GETADDRINFO_ERROR #undef ASIO_WIN_OR_POSIX -#include "asio/impl/error_code.ipp" - -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/error.ipp" +#endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_ERROR_HPP diff --git a/ext/asio/asio/error_code.hpp b/ext/asio/asio/error_code.hpp index 6657f3f2ee..1af449bda1 100644 --- a/ext/asio/asio/error_code.hpp +++ b/ext/asio/asio/error_code.hpp @@ -2,7 +2,7 @@ // error_code.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <string> -#include "asio/detail/pop_options.hpp" #if defined(GENERATING_DOCUMENTATION) # define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined @@ -30,6 +26,8 @@ # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif +#include "asio/detail/push_options.hpp" + namespace asio { namespace error @@ -106,7 +104,7 @@ public: } /// Get the message associated with the error. - std::string message() const; + ASIO_DECL std::string message() const; struct unspecified_bool_type_t { @@ -114,14 +112,12 @@ public: typedef void (*unspecified_bool_type)(unspecified_bool_type_t); - static void unspecified_bool_true(unspecified_bool_type_t) - { - } + static void unspecified_bool_true(unspecified_bool_type_t) {} /// Operator returns non-null if there is a non-success error code. operator unspecified_bool_type() const { - if (value_ == 0) + if (!value_) return 0; else return &error_code::unspecified_bool_true; @@ -130,7 +126,7 @@ public: /// Operator to test if the error represents success. bool operator!() const { - return value_ == 0; + return !value_; } /// Equality operator to compare two error objects. @@ -155,10 +151,12 @@ private: } // namespace asio -#undef ASIO_WIN_OR_POSIX +#include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" +#undef ASIO_WIN_OR_POSIX -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/error_code.ipp" +#endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_ERROR_CODE_HPP diff --git a/ext/asio/asio/handler_alloc_hook.hpp b/ext/asio/asio/handler_alloc_hook.hpp index 87783cdfa5..dd930b6936 100644 --- a/ext/asio/asio/handler_alloc_hook.hpp +++ b/ext/asio/asio/handler_alloc_hook.hpp @@ -2,7 +2,7 @@ // handler_alloc_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <cstddef> #include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { diff --git a/ext/asio/asio/handler_invoke_hook.hpp b/ext/asio/asio/handler_invoke_hook.hpp index b3d7e45440..ef22359b13 100644 --- a/ext/asio/asio/handler_invoke_hook.hpp +++ b/ext/asio/asio/handler_invoke_hook.hpp @@ -2,7 +2,7 @@ // handler_invoke_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include "asio/detail/config.hpp" + #include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/impl/error.ipp b/ext/asio/asio/impl/error.ipp new file mode 100644 index 0000000000..54388b31ae --- /dev/null +++ b/ext/asio/asio/impl/error.ipp @@ -0,0 +1,33 @@ +// +// impl/error.ipp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_ERROR_IPP +#define ASIO_IMPL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace error { + +// boostify: error category function definitions go here. + +} // namespace error +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_ERROR_IPP diff --git a/ext/asio/asio/impl/error_code.ipp b/ext/asio/asio/impl/error_code.ipp index 614925dd41..ed37a17dd3 100644 --- a/ext/asio/asio/impl/error_code.ipp +++ b/ext/asio/asio/impl/error_code.ipp @@ -1,50 +1,55 @@ // -// error_code.ipp -// ~~~~~~~~~~~~~~ +// impl/error_code.ipp +// ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef ASIO_ERROR_CODE_IPP -#define ASIO_ERROR_CODE_IPP +#ifndef ASIO_IMPL_ERROR_CODE_IPP +#define ASIO_IMPL_ERROR_CODE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <cerrno> -#include <cstring> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" +#include "asio/detail/config.hpp" #include "asio/detail/local_free_on_block_exit.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/error.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { -inline std::string error_code::message() const +std::string error_code::message() const { - if (*this == error::already_open) - return "Already open."; - if (*this == error::not_found) - return "Not found."; - if (*this == error::fd_set_failure) - return "The descriptor does not fit into the select call's fd_set."; + if (category_ == error::get_misc_category()) + { + if (value_ == error::already_open) + return "Already open."; + if (value_ == error::not_found) + return "Not found."; + if (value_ == error::fd_set_failure) + return "The descriptor does not fit into the select call's fd_set."; + if (value_ == error::not_found) + return "Element not found."; +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + if (value_ == error::eof) + return "End of file."; +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + } if (category_ == error::get_ssl_category()) return "SSL error."; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_type value = value_; - if (category() != error::get_system_category() && *this != error::eof) - return "asio error"; - if (*this == error::eof) + if (category_ == error::get_misc_category() && value_ == error::eof) value = ERROR_HANDLE_EOF; + else if (category_ != error::get_system_category()) + return "asio error"; char* msg = 0; DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM @@ -60,29 +65,31 @@ inline std::string error_code::message() const else return "asio error"; #else // defined(BOOST_WINDOWS) - if (*this == error::eof) - return "End of file."; - if (*this == error::host_not_found) - return "Host not found (authoritative)."; - if (*this == error::host_not_found_try_again) - return "Host not found (non-authoritative), try again later."; - if (*this == error::no_recovery) - return "A non-recoverable error occurred during database lookup."; - if (*this == error::no_data) - return "The query is valid, but it does not have associated data."; - if (*this == error::not_found) - return "Element not found."; + if (category_ == error::get_netdb_category()) + { + if (value_ == error::host_not_found) + return "Host not found (authoritative)."; + if (value_ == error::host_not_found_try_again) + return "Host not found (non-authoritative), try again later."; + if (value_ == error::no_recovery) + return "A non-recoverable error occurred during database lookup."; + if (value_ == error::no_data) + return "The query is valid, but it does not have associated data."; + } + if (category_ == error::get_addrinfo_category()) + { + if (value_ == error::service_not_found) + return "Service not found."; + if (value_ == error::socket_type_not_supported) + return "Socket type not supported."; + } + if (category_ != error::get_system_category()) + return "asio error"; #if !defined(__sun) - if (*this == error::operation_aborted) + if (value_ == error::operation_aborted) return "Operation aborted."; #endif // !defined(__sun) - if (*this == error::service_not_found) - return "Service not found."; - if (*this == error::socket_type_not_supported) - return "Socket type not supported."; - if (category() != error::get_system_category()) - return "asio error"; -#if defined(__sun) || defined(__QNX__) +#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) using namespace std; return strerror(value_); #elif defined(__MACH__) && defined(__APPLE__) \ @@ -102,4 +109,4 @@ inline std::string error_code::message() const #include "asio/detail/pop_options.hpp" -#endif // ASIO_ERROR_CODE_IPP +#endif // ASIO_IMPL_ERROR_CODE_IPP diff --git a/ext/asio/asio/impl/io_service.hpp b/ext/asio/asio/impl/io_service.hpp new file mode 100644 index 0000000000..f0c1730692 --- /dev/null +++ b/ext/asio/asio/impl/io_service.hpp @@ -0,0 +1,132 @@ +// +// impl/io_service.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_IO_SERVICE_HPP +#define ASIO_IMPL_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/service_registry.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Service> +inline Service& use_service(io_service& ios) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<io_service::service*>(static_cast<Service*>(0)); + (void)static_cast<const io_service::id*>(&Service::id); + + return ios.service_registry_->template use_service<Service>(); +} + +template <typename Service> +inline void add_service(io_service& ios, Service* svc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<io_service::service*>(static_cast<Service*>(0)); + (void)static_cast<const io_service::id*>(&Service::id); + + ios.service_registry_->template add_service<Service>(svc); +} + +template <typename Service> +inline bool has_service(io_service& ios) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<io_service::service*>(static_cast<Service*>(0)); + (void)static_cast<const io_service::id*>(&Service::id); + + return ios.service_registry_->template has_service<Service>(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_service.hpp" +#else +# include "asio/detail/task_io_service.hpp" +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Handler> +inline void io_service::dispatch(Handler handler) +{ + impl_.dispatch(handler); +} + +template <typename Handler> +inline void io_service::post(Handler handler) +{ + impl_.post(handler); +} + +template <typename Handler> +#if defined(GENERATING_DOCUMENTATION) +unspecified +#else +inline detail::wrapped_handler<io_service&, Handler> +#endif +io_service::wrap(Handler handler) +{ + return detail::wrapped_handler<io_service&, Handler>(*this, handler); +} + +inline io_service::work::work(asio::io_service& io_service) + : io_service_(io_service) +{ + io_service_.impl_.work_started(); +} + +inline io_service::work::work(const work& other) + : io_service_(other.io_service_) +{ + io_service_.impl_.work_started(); +} + +inline io_service::work::~work() +{ + io_service_.impl_.work_finished(); +} + +inline asio::io_service& io_service::work::io_service() +{ + return io_service_; +} + +inline asio::io_service& io_service::work::get_io_service() +{ + return io_service_; +} + +inline asio::io_service& io_service::service::io_service() +{ + return owner_; +} + +inline asio::io_service& io_service::service::get_io_service() +{ + return owner_; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_IO_SERVICE_HPP diff --git a/ext/asio/asio/impl/io_service.ipp b/ext/asio/asio/impl/io_service.ipp index c3fed3b820..eb19b8ffd0 100644 --- a/ext/asio/asio/impl/io_service.ipp +++ b/ext/asio/asio/impl/io_service.ipp @@ -1,26 +1,23 @@ // -// io_service.ipp -// ~~~~~~~~~~~~~~ +// impl/io_service.ipp +// ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef ASIO_IO_SERVICE_IPP -#define ASIO_IO_SERVICE_IPP +#ifndef ASIO_IMPL_IO_SERVICE_IPP +#define ASIO_IMPL_IO_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <boost/limits.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/io_service.hpp" #include "asio/detail/service_registry.hpp" #include "asio/detail/throw_error.hpp" @@ -28,31 +25,32 @@ # include "asio/detail/win_iocp_io_service.hpp" #else # include "asio/detail/task_io_service.hpp" -# include "asio/detail/reactor.hpp" #endif +#include "asio/detail/push_options.hpp" + namespace asio { -inline io_service::io_service() +io_service::io_service() : service_registry_(new asio::detail::service_registry(*this)), impl_(service_registry_->use_service<impl_type>()) { impl_.init((std::numeric_limits<std::size_t>::max)()); } -inline io_service::io_service(std::size_t concurrency_hint) +io_service::io_service(std::size_t concurrency_hint) : service_registry_(new asio::detail::service_registry(*this)), impl_(service_registry_->use_service<impl_type>()) { impl_.init(concurrency_hint); } -inline io_service::~io_service() +io_service::~io_service() { delete service_registry_; } -inline std::size_t io_service::run() +std::size_t io_service::run() { asio::error_code ec; std::size_t s = impl_.run(ec); @@ -60,12 +58,12 @@ inline std::size_t io_service::run() return s; } -inline std::size_t io_service::run(asio::error_code& ec) +std::size_t io_service::run(asio::error_code& ec) { return impl_.run(ec); } -inline std::size_t io_service::run_one() +std::size_t io_service::run_one() { asio::error_code ec; std::size_t s = impl_.run_one(ec); @@ -73,12 +71,12 @@ inline std::size_t io_service::run_one() return s; } -inline std::size_t io_service::run_one(asio::error_code& ec) +std::size_t io_service::run_one(asio::error_code& ec) { return impl_.run_one(ec); } -inline std::size_t io_service::poll() +std::size_t io_service::poll() { asio::error_code ec; std::size_t s = impl_.poll(ec); @@ -86,12 +84,12 @@ inline std::size_t io_service::poll() return s; } -inline std::size_t io_service::poll(asio::error_code& ec) +std::size_t io_service::poll(asio::error_code& ec) { return impl_.poll(ec); } -inline std::size_t io_service::poll_one() +std::size_t io_service::poll_one() { asio::error_code ec; std::size_t s = impl_.poll_one(ec); @@ -99,126 +97,43 @@ inline std::size_t io_service::poll_one() return s; } -inline std::size_t io_service::poll_one(asio::error_code& ec) +std::size_t io_service::poll_one(asio::error_code& ec) { return impl_.poll_one(ec); } -inline void io_service::stop() +void io_service::stop() { impl_.stop(); } -inline void io_service::reset() +void io_service::reset() { impl_.reset(); } -template <typename Handler> -inline void io_service::dispatch(Handler handler) -{ - impl_.dispatch(handler); -} - -template <typename Handler> -inline void io_service::post(Handler handler) -{ - impl_.post(handler); -} - -template <typename Handler> -#if defined(GENERATING_DOCUMENTATION) -unspecified -#else -inline detail::wrapped_handler<io_service&, Handler> -#endif -io_service::wrap(Handler handler) -{ - return detail::wrapped_handler<io_service&, Handler>(*this, handler); -} - -inline io_service::work::work(asio::io_service& io_service) - : io_service_(io_service) -{ - io_service_.impl_.work_started(); -} - -inline io_service::work::work(const work& other) - : io_service_(other.io_service_) -{ - io_service_.impl_.work_started(); -} - -inline io_service::work::~work() -{ - io_service_.impl_.work_finished(); -} - -inline asio::io_service& io_service::work::io_service() -{ - return io_service_; -} - -inline asio::io_service& io_service::work::get_io_service() -{ - return io_service_; -} - -inline io_service::service::service(asio::io_service& owner) +io_service::service::service(asio::io_service& owner) : owner_(owner), next_(0) { } -inline io_service::service::~service() -{ -} - -inline asio::io_service& io_service::service::io_service() -{ - return owner_; -} - -inline asio::io_service& io_service::service::get_io_service() +io_service::service::~service() { - return owner_; } -template <typename Service> -inline Service& use_service(io_service& ios) +service_already_exists::service_already_exists() + : std::logic_error("Service already exists.") { - // Check that Service meets the necessary type requirements. - (void)static_cast<io_service::service*>(static_cast<Service*>(0)); - (void)static_cast<const io_service::id*>(&Service::id); - - return ios.service_registry_->template use_service<Service>(); } -template <typename Service> -void add_service(io_service& ios, Service* svc) +invalid_service_owner::invalid_service_owner() + : std::logic_error("Invalid service owner.") { - // Check that Service meets the necessary type requirements. - (void)static_cast<io_service::service*>(static_cast<Service*>(0)); - (void)static_cast<const io_service::id*>(&Service::id); - - if (&ios != &svc->io_service()) - boost::throw_exception(invalid_service_owner()); - if (!ios.service_registry_->template add_service<Service>(svc)) - boost::throw_exception(service_already_exists()); -} - -template <typename Service> -bool has_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast<io_service::service*>(static_cast<Service*>(0)); - (void)static_cast<const io_service::id*>(&Service::id); - - return ios.service_registry_->template has_service<Service>(); } } // namespace asio #include "asio/detail/pop_options.hpp" -#endif // ASIO_IO_SERVICE_IPP +#endif // ASIO_IMPL_IO_SERVICE_IPP diff --git a/ext/asio/asio/impl/read.hpp b/ext/asio/asio/impl/read.hpp new file mode 100644 index 0000000000..bd5d7b533e --- /dev/null +++ b/ext/asio/asio/impl/read.hpp @@ -0,0 +1,386 @@ +// +// impl/read.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_READ_HPP +#define ASIO_IMPL_READ_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename SyncReadStream, typename MutableBufferSequence, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::error_code(); + asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> tmp(buffers); + std::size_t total_transferred = 0; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + while (tmp.begin() != tmp.end()) + { + std::size_t bytes_transferred = s.read_some(tmp, ec); + tmp.consume(bytes_transferred); + total_transferred += bytes_transferred; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + } + return total_transferred; +} + +template <typename SyncReadStream, typename MutableBufferSequence> +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncReadStream, typename MutableBufferSequence, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#if !defined(BOOST_NO_IOSTREAM) + +template <typename SyncReadStream, typename Allocator, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = read_size_helper(b, max_size); + while (bytes_available > 0) + { + std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); + b.commit(bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = read_size_helper(b, max_size); + } + return total_transferred; +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, b, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncReadStream, typename Allocator, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, b, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncReadStream, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> + class read_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + stream_.async_read_some(buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename CompletionCondition, typename ReadHandler> + class read_op<AsyncReadStream, asio::mutable_buffers_1, + CompletionCondition, ReadHandler> + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_op(AsyncReadStream& stream, + const asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, + ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + stream_.async_read_some(asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == asio::buffer_size(buffer_)) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + asio::mutable_buffer buffer_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_op<AsyncReadStream, MutableBufferSequence, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_op<AsyncReadStream, MutableBufferSequence, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename MutableBufferSequence, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_op<AsyncReadStream, MutableBufferSequence, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> +inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler handler) +{ + detail::read_op<AsyncReadStream, MutableBufferSequence, + CompletionCondition, ReadHandler>( + s, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); +} + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename ReadHandler> +inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + ReadHandler handler) +{ + async_read(s, buffers, transfer_all(), handler); +} + +#if !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> + class read_streambuf_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_streambuf_op(AsyncReadStream& stream, + basic_streambuf<Allocator>& streambuf, + CompletionCondition completion_condition, ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + streambuf_(streambuf), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, bytes_available; + switch (start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + for (;;) + { + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + asio::basic_streambuf<Allocator>& streambuf_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_streambuf_op<AsyncReadStream, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_streambuf_op<AsyncReadStream, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename Allocator, typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_streambuf_op<AsyncReadStream, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> +inline void async_read(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, ReadHandler handler) +{ + detail::read_streambuf_op<AsyncReadStream, + Allocator, CompletionCondition, ReadHandler>( + s, b, completion_condition, handler)( + asio::error_code(), 0, 1); +} + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline void async_read(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, ReadHandler handler) +{ + async_read(s, b, transfer_all(), handler); +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_READ_HPP diff --git a/ext/asio/asio/impl/read_at.hpp b/ext/asio/asio/impl/read_at.hpp new file mode 100644 index 0000000000..da57fe36aa --- /dev/null +++ b/ext/asio/asio/impl/read_at.hpp @@ -0,0 +1,410 @@ +// +// impl/read_at.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_READ_AT_HPP +#define ASIO_IMPL_READ_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, + typename CompletionCondition> +std::size_t read_at(SyncRandomAccessReadDevice& d, + boost::uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::error_code(); + asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> tmp(buffers); + std::size_t total_transferred = 0; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + while (tmp.begin() != tmp.end()) + { + std::size_t bytes_transferred = d.read_some_at( + offset + total_transferred, tmp, ec); + tmp.consume(bytes_transferred); + total_transferred += bytes_transferred; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + } + return total_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + boost::uint64_t offset, const MutableBufferSequence& buffers) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, buffers, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, + typename CompletionCondition> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + boost::uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, buffers, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#if !defined(BOOST_NO_IOSTREAM) + +template <typename SyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition> +std::size_t read_at(SyncRandomAccessReadDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = read_size_helper(b, max_size); + while (bytes_available > 0) + { + std::size_t bytes_transferred = d.read_some_at( + offset + total_transferred, b.prepare(bytes_available), ec); + b.commit(bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = read_size_helper(b, max_size); + } + return total_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename Allocator> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, b, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, b, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition, + typename ReadHandler> + class read_at_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_at_op(AsyncRandomAccessReadDevice& device, + boost::uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffers_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + device_.async_read_some_at( + offset_ + total_transferred_, buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + boost::uint64_t offset_; + asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncRandomAccessReadDevice, + typename CompletionCondition, typename ReadHandler> + class read_at_op<AsyncRandomAccessReadDevice, + asio::mutable_buffers_1, CompletionCondition, ReadHandler> + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_at_op(AsyncRandomAccessReadDevice& device, + boost::uint64_t offset, const asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + asio::buffer(buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == asio::buffer_size(buffer_)) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + boost::uint64_t offset_; + asio::mutable_buffer buffer_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition, + typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> +inline void async_read_at(AsyncRandomAccessReadDevice& d, + boost::uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler handler) +{ + detail::read_at_op<AsyncRandomAccessReadDevice, + MutableBufferSequence, CompletionCondition, ReadHandler>( + d, offset, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); +} + +template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, + typename ReadHandler> +inline void async_read_at(AsyncRandomAccessReadDevice& d, + boost::uint64_t offset, const MutableBufferSequence& buffers, + ReadHandler handler) +{ + async_read_at(d, offset, buffers, transfer_all(), handler); +} + +#if !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + class read_at_streambuf_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_at_streambuf_op(AsyncRandomAccessReadDevice& device, + boost::uint64_t offset, basic_streambuf<Allocator>& streambuf, + CompletionCondition completion_condition, ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + streambuf_(streambuf), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, bytes_available; + switch (start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), *this); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + boost::uint64_t offset_; + asio::basic_streambuf<Allocator>& streambuf_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessReadDevice, + typename Allocator, typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> +inline void async_read_at(AsyncRandomAccessReadDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, ReadHandler handler) +{ + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Allocator, CompletionCondition, ReadHandler>( + d, offset, b, completion_condition, handler)( + asio::error_code(), 0, 1); +} + +template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename ReadHandler> +inline void async_read_at(AsyncRandomAccessReadDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + ReadHandler handler) +{ + async_read_at(d, offset, b, transfer_all(), handler); +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_READ_AT_HPP diff --git a/ext/asio/asio/impl/read_until.hpp b/ext/asio/asio/impl/read_until.hpp new file mode 100644 index 0000000000..ceacca7fdd --- /dev/null +++ b/ext/asio/asio/impl/read_until.hpp @@ -0,0 +1,902 @@ +// +// impl/read_until.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_READ_UNTIL_HPP +#define ASIO_IMPL_READ_UNTIL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include <string> +#include <vector> +#include <utility> +#include <boost/limits.hpp> +#include "asio/buffer.hpp" +#include "asio/buffers_iterator.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncReadStream, typename Allocator> +std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim, + asio::error_code& ec) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + iterator iter = std::find(start, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = asio::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const std::string& delim) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +namespace detail +{ + // Algorithm that finds a subsequence of equal values in a sequence. Returns + // (iterator,true) if a full match was found, in which case the iterator + // points to the beginning of the match. Returns (iterator,false) if a + // partial match was found at the end of the first sequence, in which case + // the iterator points to the beginning of the partial match. Returns + // (last1,false) if no full or partial match was found. + template <typename Iterator1, typename Iterator2> + std::pair<Iterator1, bool> partial_search( + Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) + { + Iterator1 test_iter1 = iter1; + Iterator2 test_iter2 = first2; + for (;; ++test_iter1, ++test_iter2) + { + if (test_iter2 == last2) + return std::make_pair(iter1, true); + if (test_iter1 == last1) + { + if (test_iter2 != first2) + return std::make_pair(iter1, false); + else + break; + } + if (*test_iter1 != *test_iter2) + break; + } + } + return std::make_pair(last1, false); + } +} // namespace detail + +template <typename SyncReadStream, typename Allocator> +std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const std::string& delim, + asio::error_code& ec) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair<iterator, bool> result = detail::partial_search( + start, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = asio::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, expr, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncReadStream, typename Allocator> +std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + asio::error_code& ec) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + boost::match_results<iterator, + typename std::vector<boost::sub_match<iterator> >::allocator_type> + match_results; + if (regex_search(start, end, match_results, expr, + boost::match_default | boost::match_partial)) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = asio::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename Allocator, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, asio::error_code& ec, + typename boost::enable_if<is_match_condition<MatchCondition> >::type*) +{ + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair<iterator, bool> result = match_condition(start, end); + if (result.second) + { + // Full match. We're done. + ec = asio::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename Allocator, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, + typename boost::enable_if<is_match_condition<MatchCondition> >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, match_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +namespace detail +{ + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + class read_until_delim_op + { + public: + read_until_delim_op(AsyncReadStream& stream, + asio::basic_streambuf<Allocator>& streambuf, + char delim, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + delim_(delim), + search_position_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + iterator iter = std::find(start, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + asio::basic_streambuf<Allocator>& streambuf_; + char delim_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op<AsyncReadStream, + Allocator, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op<AsyncReadStream, + Allocator, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, typename Allocator, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_delim_op<AsyncReadStream, + Allocator, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim, ReadHandler handler) +{ + detail::read_until_delim_op< + AsyncReadStream, Allocator, ReadHandler>( + s, b, delim, handler)( + asio::error_code(), 0, 1); +} + +namespace detail +{ + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + class read_until_delim_string_op + { + public: + read_until_delim_string_op(AsyncReadStream& stream, + asio::basic_streambuf<Allocator>& streambuf, + const std::string& delim, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + delim_(delim), + search_position_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair<iterator, bool> result = detail::partial_search( + start, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + asio::basic_streambuf<Allocator>& streambuf_; + std::string delim_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op<AsyncReadStream, + Allocator, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op<AsyncReadStream, + Allocator, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename Allocator, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op<AsyncReadStream, + Allocator, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const std::string& delim, + ReadHandler handler) +{ + detail::read_until_delim_string_op< + AsyncReadStream, Allocator, ReadHandler>( + s, b, delim, handler)( + asio::error_code(), 0, 1); +} + +namespace detail +{ + template <typename AsyncReadStream, typename Allocator, + typename RegEx, typename ReadHandler> + class read_until_expr_op + { + public: + read_until_expr_op(AsyncReadStream& stream, + asio::basic_streambuf<Allocator>& streambuf, + const boost::regex& expr, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + expr_(expr), + search_position_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + boost::match_results<iterator, + typename std::vector<boost::sub_match<iterator> >::allocator_type> + match_results; + bool match = regex_search(start, end, match_results, expr_, + boost::match_default | boost::match_partial); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + asio::basic_streambuf<Allocator>& streambuf_; + RegEx expr_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename Allocator, + typename RegEx, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op<AsyncReadStream, + Allocator, RegEx, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename Allocator, + typename RegEx, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_expr_op<AsyncReadStream, + Allocator, RegEx, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, typename Allocator, + typename RegEx, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_expr_op<AsyncReadStream, + Allocator, RegEx, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + ReadHandler handler) +{ + detail::read_until_expr_op<AsyncReadStream, + Allocator, boost::regex, ReadHandler>( + s, b, expr, handler)( + asio::error_code(), 0, 1); +} + +namespace detail +{ + template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> + class read_until_match_op + { + public: + read_until_match_op(AsyncReadStream& stream, + asio::basic_streambuf<Allocator>& streambuf, + MatchCondition match_condition, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + match_condition_(match_condition), + search_position_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename asio::basic_streambuf< + Allocator>::const_buffers_type const_buffers_type; + typedef asio::buffers_iterator<const_buffers_type> iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair<iterator, bool> result = match_condition_(start, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + asio::basic_streambuf<Allocator>& streambuf_; + MatchCondition match_condition_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op<AsyncReadStream, + Allocator, MatchCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op<AsyncReadStream, + Allocator, MatchCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_match_op<AsyncReadStream, + Allocator, MatchCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, ReadHandler handler, + typename boost::enable_if<is_match_condition<MatchCondition> >::type*) +{ + detail::read_until_match_op< + AsyncReadStream, Allocator, MatchCondition, ReadHandler>( + s, b, match_condition, handler)( + asio::error_code(), 0, 1); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_READ_UNTIL_HPP diff --git a/ext/asio/asio/impl/serial_port_base.hpp b/ext/asio/asio/impl/serial_port_base.hpp new file mode 100644 index 0000000000..758e65251e --- /dev/null +++ b/ext/asio/asio/impl/serial_port_base.hpp @@ -0,0 +1,59 @@ +// +// impl/serial_port_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_SERIAL_PORT_BASE_HPP +#define ASIO_IMPL_SERIAL_PORT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline serial_port_base::baud_rate::baud_rate(unsigned int rate) + : value_(rate) +{ +} + +inline unsigned int serial_port_base::baud_rate::value() const +{ + return value_; +} + +inline serial_port_base::flow_control::type +serial_port_base::flow_control::value() const +{ + return value_; +} + +inline serial_port_base::parity::type serial_port_base::parity::value() const +{ + return value_; +} + +inline serial_port_base::stop_bits::type +serial_port_base::stop_bits::value() const +{ + return value_; +} + +inline unsigned int serial_port_base::character_size::value() const +{ + return value_; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP diff --git a/ext/asio/asio/impl/serial_port_base.ipp b/ext/asio/asio/impl/serial_port_base.ipp index 64ab6a45a0..4d3204dab3 100644 --- a/ext/asio/asio/impl/serial_port_base.ipp +++ b/ext/asio/asio/impl/serial_port_base.ipp @@ -1,40 +1,43 @@ // -// serial_port_base.ipp -// ~~~~~~~~~~~~~~~~~~~~ +// impl/serial_port_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef ASIO_SERIAL_PORT_BASE_IPP -#define ASIO_SERIAL_PORT_BASE_IPP +#ifndef ASIO_IMPL_SERIAL_PORT_BASE_IPP +#define ASIO_IMPL_SERIAL_PORT_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" +#if defined(ASIO_HAS_SERIAL_PORT) + +#include <stdexcept> #include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" +#include "asio/serial_port_base.hpp" -namespace asio { +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_OPTION_STORAGE implementation_defined +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# define ASIO_OPTION_STORAGE DCB +#else +# define ASIO_OPTION_STORAGE termios +#endif -inline serial_port_base::baud_rate::baud_rate(unsigned int rate) - : value_(rate) -{ -} +#include "asio/detail/push_options.hpp" -inline unsigned int serial_port_base::baud_rate::value() const -{ - return value_; -} +namespace asio { -inline asio::error_code serial_port_base::baud_rate::store( +asio::error_code serial_port_base::baud_rate::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -122,7 +125,7 @@ inline asio::error_code serial_port_base::baud_rate::store( return ec; } -inline asio::error_code serial_port_base::baud_rate::load( +asio::error_code serial_port_base::baud_rate::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -204,7 +207,7 @@ inline asio::error_code serial_port_base::baud_rate::load( return ec; } -inline serial_port_base::flow_control::flow_control( +serial_port_base::flow_control::flow_control( serial_port_base::flow_control::type t) : value_(t) { @@ -215,13 +218,7 @@ inline serial_port_base::flow_control::flow_control( } } -inline serial_port_base::flow_control::type -serial_port_base::flow_control::value() const -{ - return value_; -} - -inline asio::error_code serial_port_base::flow_control::store( +asio::error_code serial_port_base::flow_control::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -255,12 +252,16 @@ inline asio::error_code serial_port_base::flow_control::store( storage.c_iflag &= ~(IXOFF | IXON); # if defined(_BSD_SOURCE) storage.c_cflag &= ~CRTSCTS; +# elif defined(__QNXNTO__) + storage.c_cflag &= ~(IHFLOW | OHFLOW); # endif break; case software: storage.c_iflag |= IXOFF | IXON; # if defined(_BSD_SOURCE) storage.c_cflag &= ~CRTSCTS; +# elif defined(__QNXNTO__) + storage.c_cflag &= ~(IHFLOW | OHFLOW); # endif break; case hardware: @@ -268,6 +269,10 @@ inline asio::error_code serial_port_base::flow_control::store( storage.c_iflag &= ~(IXOFF | IXON); storage.c_cflag |= CRTSCTS; break; +# elif defined(__QNXNTO__) + storage.c_iflag &= ~(IXOFF | IXON); + storage.c_cflag |= (IHFLOW | OHFLOW); + break; # else ec = asio::error::operation_not_supported; return ec; @@ -280,7 +285,7 @@ inline asio::error_code serial_port_base::flow_control::store( return ec; } -inline asio::error_code serial_port_base::flow_control::load( +asio::error_code serial_port_base::flow_control::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -306,6 +311,11 @@ inline asio::error_code serial_port_base::flow_control::load( { value_ = hardware; } +# elif defined(__QNXNTO__) + else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW) + { + value_ = hardware; + } # endif else { @@ -316,7 +326,7 @@ inline asio::error_code serial_port_base::flow_control::load( return ec; } -inline serial_port_base::parity::parity(serial_port_base::parity::type t) +serial_port_base::parity::parity(serial_port_base::parity::type t) : value_(t) { if (t != none && t != odd && t != even) @@ -326,12 +336,7 @@ inline serial_port_base::parity::parity(serial_port_base::parity::type t) } } -inline serial_port_base::parity::type serial_port_base::parity::value() const -{ - return value_; -} - -inline asio::error_code serial_port_base::parity::store( +asio::error_code serial_port_base::parity::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -378,7 +383,7 @@ inline asio::error_code serial_port_base::parity::store( return ec; } -inline asio::error_code serial_port_base::parity::load( +asio::error_code serial_port_base::parity::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -415,7 +420,7 @@ inline asio::error_code serial_port_base::parity::load( return ec; } -inline serial_port_base::stop_bits::stop_bits( +serial_port_base::stop_bits::stop_bits( serial_port_base::stop_bits::type t) : value_(t) { @@ -426,13 +431,7 @@ inline serial_port_base::stop_bits::stop_bits( } } -inline serial_port_base::stop_bits::type -serial_port_base::stop_bits::value() const -{ - return value_; -} - -inline asio::error_code serial_port_base::stop_bits::store( +asio::error_code serial_port_base::stop_bits::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -468,7 +467,7 @@ inline asio::error_code serial_port_base::stop_bits::store( return ec; } -inline asio::error_code serial_port_base::stop_bits::load( +asio::error_code serial_port_base::stop_bits::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -495,7 +494,7 @@ inline asio::error_code serial_port_base::stop_bits::load( return ec; } -inline serial_port_base::character_size::character_size(unsigned int t) +serial_port_base::character_size::character_size(unsigned int t) : value_(t) { if (t < 5 || t > 8) @@ -505,12 +504,7 @@ inline serial_port_base::character_size::character_size(unsigned int t) } } -inline unsigned int serial_port_base::character_size::value() const -{ - return value_; -} - -inline asio::error_code serial_port_base::character_size::store( +asio::error_code serial_port_base::character_size::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -530,7 +524,7 @@ inline asio::error_code serial_port_base::character_size::store( return ec; } -inline asio::error_code serial_port_base::character_size::load( +asio::error_code serial_port_base::character_size::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -554,4 +548,8 @@ inline asio::error_code serial_port_base::character_size::load( #include "asio/detail/pop_options.hpp" -#endif // ASIO_SERIAL_PORT_BASE_IPP +#undef ASIO_OPTION_STORAGE + +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP diff --git a/ext/asio/asio/impl/src.cpp b/ext/asio/asio/impl/src.cpp new file mode 100644 index 0000000000..1dac400b66 --- /dev/null +++ b/ext/asio/asio/impl/src.cpp @@ -0,0 +1,25 @@ +// +// impl/src.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#if defined(_MSC_VER) \ + || defined(__BORLANDC__) \ + || defined(__DMC__) +# pragma message ( \ + "This file is deprecated. " \ + "Please #include <asio/impl/src.hpp> instead.") +#elif defined(__GNUC__) \ + || defined(__HP_aCC) \ + || defined(__SUNPRO_CC) \ + || defined(__IBMCPP__) +# warning "This file is deprecated." +# warning "Please #include <asio/impl/src.hpp> instead." +#endif + +#include "asio/impl/src.hpp" diff --git a/ext/asio/asio/impl/src.hpp b/ext/asio/asio/impl/src.hpp new file mode 100644 index 0000000000..b37eabddb8 --- /dev/null +++ b/ext/asio/asio/impl/src.hpp @@ -0,0 +1,65 @@ +// +// impl/src.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_SRC_HPP +#define ASIO_IMPL_SRC_HPP + +#define ASIO_SOURCE + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HEADER_ONLY) +# error Do not compile Asio library source with ASIO_HEADER_ONLY defined +#endif + +#include "asio/impl/error.ipp" +#include "asio/impl/error_code.ipp" +#include "asio/impl/io_service.ipp" +#include "asio/impl/serial_port_base.ipp" +#include "asio/detail/impl/descriptor_ops.ipp" +#include "asio/detail/impl/dev_poll_reactor.ipp" +#include "asio/detail/impl/epoll_reactor.ipp" +#include "asio/detail/impl/eventfd_select_interrupter.ipp" +#include "asio/detail/impl/kqueue_reactor.ipp" +#include "asio/detail/impl/pipe_select_interrupter.ipp" +#include "asio/detail/impl/posix_event.ipp" +#include "asio/detail/impl/posix_mutex.ipp" +#include "asio/detail/impl/posix_thread.ipp" +#include "asio/detail/impl/posix_tss_ptr.ipp" +#include "asio/detail/impl/reactive_descriptor_service.ipp" +#include "asio/detail/impl/reactive_serial_port_service.ipp" +#include "asio/detail/impl/reactive_socket_service_base.ipp" +#include "asio/detail/impl/resolver_service_base.ipp" +#include "asio/detail/impl/select_reactor.ipp" +#include "asio/detail/impl/service_registry.ipp" +#include "asio/detail/impl/socket_ops.ipp" +#include "asio/detail/impl/socket_select_interrupter.ipp" +#include "asio/detail/impl/strand_service.ipp" +#include "asio/detail/impl/task_io_service.ipp" +#include "asio/detail/impl/throw_error.ipp" +#include "asio/detail/impl/timer_queue.ipp" +#include "asio/detail/impl/timer_queue_set.ipp" +#include "asio/detail/impl/win_iocp_handle_service.ipp" +#include "asio/detail/impl/win_iocp_io_service.ipp" +#include "asio/detail/impl/win_iocp_serial_port_service.ipp" +#include "asio/detail/impl/win_iocp_socket_service_base.ipp" +#include "asio/detail/impl/win_event.ipp" +#include "asio/detail/impl/win_mutex.ipp" +#include "asio/detail/impl/win_thread.ipp" +#include "asio/detail/impl/win_tss_ptr.ipp" +#include "asio/detail/impl/winsock_init.ipp" +#include "asio/ip/impl/address.ipp" +#include "asio/ip/impl/address_v4.ipp" +#include "asio/ip/impl/address_v6.ipp" +#include "asio/ip/impl/host_name.ipp" +#include "asio/ip/detail/impl/endpoint.ipp" +#include "asio/local/detail/impl/endpoint.ipp" + +#endif // ASIO_IMPL_SRC_HPP diff --git a/ext/asio/asio/impl/write.hpp b/ext/asio/asio/impl/write.hpp new file mode 100644 index 0000000000..91cb65ecbf --- /dev/null +++ b/ext/asio/asio/impl/write.hpp @@ -0,0 +1,396 @@ +// +// impl/write.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_WRITE_HPP +#define ASIO_IMPL_WRITE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename SyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::error_code(); + asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> tmp(buffers); + std::size_t total_transferred = 0; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + while (tmp.begin() != tmp.end()) + { + std::size_t bytes_transferred = s.write_some(tmp, ec); + tmp.consume(bytes_transferred); + total_transferred += bytes_transferred; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + } + return total_transferred; +} + +template <typename SyncWriteStream, typename ConstBufferSequence> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#if !defined(BOOST_NO_IOSTREAM) + +template <typename SyncWriteStream, typename Allocator, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename Allocator> +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, b, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename Allocator, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, b, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> + class write_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + stream_.async_write_some(buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncWriteStream& stream_; + asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, + typename CompletionCondition, typename WriteHandler> + class write_op<AsyncWriteStream, asio::mutable_buffers_1, + CompletionCondition, WriteHandler> + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_op(AsyncWriteStream& stream, + const asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + stream_.async_write_some(asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == asio::buffer_size(buffer_)) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncWriteStream& stream_; + asio::mutable_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, + typename CompletionCondition, typename WriteHandler> + class write_op<AsyncWriteStream, asio::const_buffers_1, + CompletionCondition, WriteHandler> + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_op(AsyncWriteStream& stream, + const asio::const_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + stream_.async_write_some(asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == asio::buffer_size(buffer_)) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncWriteStream& stream_; + asio::const_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_op<AsyncWriteStream, ConstBufferSequence, + CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_op<AsyncWriteStream, ConstBufferSequence, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename ConstBufferSequence, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_op<AsyncWriteStream, ConstBufferSequence, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> +inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler handler) +{ + detail::write_op<AsyncWriteStream, ConstBufferSequence, + CompletionCondition, WriteHandler>( + s, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); +} + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename WriteHandler> +inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + WriteHandler handler) +{ + async_write(s, buffers, transfer_all(), handler); +} + +#if !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncWriteStream, typename Allocator, + typename WriteHandler> + class write_streambuf_handler + { + public: + write_streambuf_handler(asio::basic_streambuf<Allocator>& streambuf, + WriteHandler handler) + : streambuf_(streambuf), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + const std::size_t bytes_transferred) + { + streambuf_.consume(bytes_transferred); + handler_(ec, bytes_transferred); + } + + //private: + asio::basic_streambuf<Allocator>& streambuf_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, typename Allocator, + typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_streambuf_handler<AsyncWriteStream, + Allocator, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename Allocator, + typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_streambuf_handler<AsyncWriteStream, + Allocator, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, typename Allocator, + typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_streambuf_handler<AsyncWriteStream, + Allocator, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncWriteStream, typename Allocator, + typename CompletionCondition, typename WriteHandler> +inline void async_write(AsyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, WriteHandler handler) +{ + async_write(s, b.data(), completion_condition, + detail::write_streambuf_handler< + AsyncWriteStream, Allocator, WriteHandler>(b, handler)); +} + +template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> +inline void async_write(AsyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, WriteHandler handler) +{ + async_write(s, b, transfer_all(), handler); +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_WRITE_HPP diff --git a/ext/asio/asio/impl/write_at.hpp b/ext/asio/asio/impl/write_at.hpp new file mode 100644 index 0000000000..1de6800801 --- /dev/null +++ b/ext/asio/asio/impl/write_at.hpp @@ -0,0 +1,417 @@ +// +// impl/write_at.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_WRITE_AT_HPP +#define ASIO_IMPL_WRITE_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition> +std::size_t write_at(SyncRandomAccessWriteDevice& d, + boost::uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::error_code(); + asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> tmp(buffers); + std::size_t total_transferred = 0; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + while (tmp.begin() != tmp.end()) + { + std::size_t bytes_transferred = d.write_some_at( + offset + total_transferred, tmp, ec); + tmp.consume(bytes_transferred); + total_transferred += bytes_transferred; + tmp.prepare(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + } + return total_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + boost::uint64_t offset, const ConstBufferSequence& buffers) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, buffers, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + boost::uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, buffers, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#if !defined(BOOST_NO_IOSTREAM) + +template <typename SyncRandomAccessWriteDevice, typename Allocator, + typename CompletionCondition> +std::size_t write_at(SyncRandomAccessWriteDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + std::size_t bytes_transferred = write_at( + d, offset, b.data(), completion_condition, ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename Allocator> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename Allocator, + typename CompletionCondition> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, b, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> + class write_at_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffers_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + device_.async_write_some_at( + offset_ + total_transferred_, buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template <typename AsyncRandomAccessWriteDevice, + typename CompletionCondition, typename WriteHandler> + class write_at_op<AsyncRandomAccessWriteDevice, + asio::mutable_buffers_1, CompletionCondition, WriteHandler> + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + device_.async_write_some_at(offset_ + total_transferred_, + asio::buffer(buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == asio::buffer_size(buffer_)) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + asio::mutable_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template <typename AsyncRandomAccessWriteDevice, + typename CompletionCondition, typename WriteHandler> + class write_at_op<AsyncRandomAccessWriteDevice, asio::const_buffers_1, + CompletionCondition, WriteHandler> + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const asio::const_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffer_(buffers), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (start) + { + case 1: + n = this->check_for_completion(ec, total_transferred_); + for (;;) + { + device_.async_write_some_at(offset_ + total_transferred_, + asio::buffer(buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check_for_completion(ec, total_transferred_)) == 0 + || total_transferred_ == asio::buffer_size(buffer_)) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + asio::const_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> +inline void async_write_at(AsyncRandomAccessWriteDevice& d, + boost::uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler handler) +{ + detail::write_at_op<AsyncRandomAccessWriteDevice, + ConstBufferSequence, CompletionCondition, WriteHandler>( + d, offset, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); +} + +template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename WriteHandler> +inline void async_write_at(AsyncRandomAccessWriteDevice& d, + boost::uint64_t offset, const ConstBufferSequence& buffers, + WriteHandler handler) +{ + async_write_at(d, offset, buffers, transfer_all(), handler); +} + +#if !defined(BOOST_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncRandomAccessWriteDevice, + typename Allocator, typename WriteHandler> + class write_at_streambuf_op + { + public: + write_at_streambuf_op( + asio::basic_streambuf<Allocator>& streambuf, + WriteHandler handler) + : streambuf_(streambuf), + handler_(handler) + { + } + + void operator()(const asio::error_code& ec, + const std::size_t bytes_transferred) + { + streambuf_.consume(bytes_transferred); + handler_(ec, bytes_transferred); + } + + //private: + asio::basic_streambuf<Allocator>& streambuf_; + WriteHandler handler_; + }; + + template <typename AsyncRandomAccessWriteDevice, typename Allocator, + typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_at_streambuf_op<AsyncRandomAccessWriteDevice, + Allocator, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessWriteDevice, typename Allocator, + typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_at_streambuf_op<AsyncRandomAccessWriteDevice, + Allocator, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessWriteDevice, + typename Allocator, typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_at_streambuf_op<AsyncRandomAccessWriteDevice, + Allocator, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template <typename AsyncRandomAccessWriteDevice, typename Allocator, + typename CompletionCondition, typename WriteHandler> +inline void async_write_at(AsyncRandomAccessWriteDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, WriteHandler handler) +{ + async_write_at(d, offset, b.data(), completion_condition, + detail::write_at_streambuf_op< + AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler)); +} + +template <typename AsyncRandomAccessWriteDevice, typename Allocator, + typename WriteHandler> +inline void async_write_at(AsyncRandomAccessWriteDevice& d, + boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, + WriteHandler handler) +{ + async_write_at(d, offset, b, transfer_all(), handler); +} + +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_WRITE_AT_HPP diff --git a/ext/asio/asio/io_service.hpp b/ext/asio/asio/io_service.hpp index 62d9e54f9c..4fc3e05fb5 100644 --- a/ext/asio/asio/io_service.hpp +++ b/ext/asio/asio/io_service.hpp @@ -2,7 +2,7 @@ // io_service.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,25 +15,29 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <stdexcept> #include <typeinfo> -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error_code.hpp" #include "asio/detail/noncopyable.hpp" -#include "asio/detail/reactor_fwd.hpp" #include "asio/detail/service_registry_fwd.hpp" -#include "asio/detail/signal_init.hpp" -#include "asio/detail/task_io_service_fwd.hpp" -#include "asio/detail/win_iocp_io_service_fwd.hpp" -#include "asio/detail/winsock_init.hpp" #include "asio/detail/wrapped_handler.hpp" +#include "asio/error_code.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_service_fwd.hpp" +#else +# include "asio/detail/task_io_service_fwd.hpp" +#endif + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include "asio/detail/winsock_init.hpp" +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) +# include "asio/detail/signal_init.hpp" +#endif + +#include "asio/detail/push_options.hpp" namespace asio { @@ -45,7 +49,7 @@ template <typename Service> bool has_service(io_service& ios); #if defined(ASIO_HAS_IOCP) namespace detail { typedef win_iocp_io_service io_service_impl; } #else -namespace detail { typedef task_io_service<reactor> io_service_impl; } +namespace detail { typedef task_io_service io_service_impl; } #endif /// Provides core I/O functionality. @@ -196,7 +200,7 @@ public: class strand; /// Constructor. - io_service(); + ASIO_DECL io_service(); /// Constructor. /** @@ -205,7 +209,7 @@ public: * @param concurrency_hint A suggestion to the implementation on how many * threads it should allow to run simultaneously. */ - explicit io_service(std::size_t concurrency_hint); + ASIO_DECL explicit io_service(std::size_t concurrency_hint); /// Destructor. /** @@ -239,7 +243,7 @@ public: * destructor defined above destroys all handlers, causing all @c shared_ptr * references to all connection objects to be destroyed. */ - ~io_service(); + ASIO_DECL ~io_service(); /// Run the io_service object's event processing loop. /** @@ -265,7 +269,7 @@ public: * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ - std::size_t run(); + ASIO_DECL std::size_t run(); /// Run the io_service object's event processing loop. /** @@ -291,7 +295,7 @@ public: * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ - std::size_t run(asio::error_code& ec); + ASIO_DECL std::size_t run(asio::error_code& ec); /// Run the io_service object's event processing loop to execute at most one /// handler. @@ -303,7 +307,7 @@ public: * * @throws asio::system_error Thrown on failure. */ - std::size_t run_one(); + ASIO_DECL std::size_t run_one(); /// Run the io_service object's event processing loop to execute at most one /// handler. @@ -315,7 +319,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t run_one(asio::error_code& ec); + ASIO_DECL std::size_t run_one(asio::error_code& ec); /// Run the io_service object's event processing loop to execute ready /// handlers. @@ -327,7 +331,7 @@ public: * * @throws asio::system_error Thrown on failure. */ - std::size_t poll(); + ASIO_DECL std::size_t poll(); /// Run the io_service object's event processing loop to execute ready /// handlers. @@ -339,7 +343,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t poll(asio::error_code& ec); + ASIO_DECL std::size_t poll(asio::error_code& ec); /// Run the io_service object's event processing loop to execute one ready /// handler. @@ -351,7 +355,7 @@ public: * * @throws asio::system_error Thrown on failure. */ - std::size_t poll_one(); + ASIO_DECL std::size_t poll_one(); /// Run the io_service object's event processing loop to execute one ready /// handler. @@ -363,7 +367,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t poll_one(asio::error_code& ec); + ASIO_DECL std::size_t poll_one(asio::error_code& ec); /// Stop the io_service object's event processing loop. /** @@ -372,7 +376,7 @@ public: * return as soon as possible. Subsequent calls to run(), run_one(), poll() * or poll_one() will return immediately until reset() is called. */ - void stop(); + ASIO_DECL void stop(); /// Reset the io_service in preparation for a subsequent run() invocation. /** @@ -385,7 +389,7 @@ public: * This function must not be called while there are any unfinished calls to * the run(), run_one(), poll() or poll_one() functions. */ - void reset(); + ASIO_DECL void reset(); /// Request the io_service to invoke the given handler. /** @@ -605,10 +609,10 @@ protected: /** * @param owner The io_service object that owns the service. */ - service(asio::io_service& owner); + ASIO_DECL service(asio::io_service& owner); /// Destructor. - virtual ~service(); + ASIO_DECL virtual ~service(); private: /// Destroy all user-defined handler objects owned by the service. @@ -631,10 +635,7 @@ class service_already_exists : public std::logic_error { public: - service_already_exists() - : std::logic_error("Service already exists.") - { - } + ASIO_DECL service_already_exists(); }; /// Exception thrown when trying to add a service object to an io_service where @@ -643,16 +644,44 @@ class invalid_service_owner : public std::logic_error { public: - invalid_service_owner() - : std::logic_error("Invalid service owner.") + ASIO_DECL invalid_service_owner(); +}; + +namespace detail { + +// Special derived service id type to keep classes header-file only. +template <typename Type> +class service_id + : public asio::io_service::id +{ +}; + +// Special service base class to keep classes header-file only. +template <typename Type> +class service_base + : public asio::io_service::service +{ +public: + static asio::detail::service_id<Type> id; + + // Constructor. + service_base(asio::io_service& io_service) + : asio::io_service::service(io_service) { } }; -} // namespace asio +template <typename Type> +asio::detail::service_id<Type> service_base<Type>::id; -#include "asio/impl/io_service.ipp" +} // namespace detail +} // namespace asio #include "asio/detail/pop_options.hpp" +#include "asio/impl/io_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/io_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_IO_SERVICE_HPP diff --git a/ext/asio/asio/ip/address.hpp b/ext/asio/asio/ip/address.hpp index 92ee4ae43d..47683dbda6 100644 --- a/ext/asio/asio/ip/address.hpp +++ b/ext/asio/asio/ip/address.hpp @@ -1,8 +1,8 @@ // -// address.hpp -// ~~~~~~~~~~~ +// ip/address.hpp +// ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,21 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <string> +#include "asio/error_code.hpp" +#include "asio/ip/address_v4.hpp" +#include "asio/ip/address_v6.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> #if !defined(BOOST_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_NO_IOSTREAM) -#include <string> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" -#include "asio/ip/address_v4.hpp" -#include "asio/ip/address_v6.hpp" -#include "asio/detail/throw_error.hpp" +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { @@ -47,63 +43,27 @@ class address { public: /// Default constructor. - address() - : type_(ipv4), - ipv4_address_(), - ipv6_address_() - { - } + ASIO_DECL address(); /// Construct an address from an IPv4 address. - address(const asio::ip::address_v4& ipv4_address) - : type_(ipv4), - ipv4_address_(ipv4_address), - ipv6_address_() - { - } + ASIO_DECL address(const asio::ip::address_v4& ipv4_address); /// Construct an address from an IPv6 address. - address(const asio::ip::address_v6& ipv6_address) - : type_(ipv6), - ipv4_address_(), - ipv6_address_(ipv6_address) - { - } + ASIO_DECL address(const asio::ip::address_v6& ipv6_address); /// Copy constructor. - address(const address& other) - : type_(other.type_), - ipv4_address_(other.ipv4_address_), - ipv6_address_(other.ipv6_address_) - { - } + ASIO_DECL address(const address& other); /// Assign from another address. - address& operator=(const address& other) - { - type_ = other.type_; - ipv4_address_ = other.ipv4_address_; - ipv6_address_ = other.ipv6_address_; - return *this; - } + ASIO_DECL address& operator=(const address& other); /// Assign from an IPv4 address. - address& operator=(const asio::ip::address_v4& ipv4_address) - { - type_ = ipv4; - ipv4_address_ = ipv4_address; - ipv6_address_ = asio::ip::address_v6(); - return *this; - } + ASIO_DECL address& operator=( + const asio::ip::address_v4& ipv4_address); /// Assign from an IPv6 address. - address& operator=(const asio::ip::address_v6& ipv6_address) - { - type_ = ipv6; - ipv4_address_ = asio::ip::address_v4(); - ipv6_address_ = ipv6_address; - return *this; - } + ASIO_DECL address& operator=( + const asio::ip::address_v6& ipv6_address); /// Get whether the address is an IP version 4 address. bool is_v4() const @@ -118,127 +78,63 @@ public: } /// Get the address as an IP version 4 address. - asio::ip::address_v4 to_v4() const - { - if (type_ != ipv4) - { - asio::system_error e( - asio::error::address_family_not_supported); - boost::throw_exception(e); - } - return ipv4_address_; - } + ASIO_DECL asio::ip::address_v4 to_v4() const; /// Get the address as an IP version 6 address. - asio::ip::address_v6 to_v6() const - { - if (type_ != ipv6) - { - asio::system_error e( - asio::error::address_family_not_supported); - boost::throw_exception(e); - } - return ipv6_address_; - } + ASIO_DECL asio::ip::address_v6 to_v6() const; /// Get the address as a string in dotted decimal format. - std::string to_string() const - { - if (type_ == ipv6) - return ipv6_address_.to_string(); - return ipv4_address_.to_string(); - } + ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. - std::string to_string(asio::error_code& ec) const - { - if (type_ == ipv6) - return ipv6_address_.to_string(ec); - return ipv4_address_.to_string(ec); - } + ASIO_DECL std::string to_string(asio::error_code& ec) const; /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const char* str) - { - asio::error_code ec; - address addr = from_string(str, ec); - asio::detail::throw_error(ec); - return addr; - } + ASIO_DECL static address from_string(const char* str); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const char* str, asio::error_code& ec) - { - asio::ip::address_v6 ipv6_address = - asio::ip::address_v6::from_string(str, ec); - if (!ec) - { - address tmp; - tmp.type_ = ipv6; - tmp.ipv6_address_ = ipv6_address; - return tmp; - } - - asio::ip::address_v4 ipv4_address = - asio::ip::address_v4::from_string(str, ec); - if (!ec) - { - address tmp; - tmp.type_ = ipv4; - tmp.ipv4_address_ = ipv4_address; - return tmp; - } - - return address(); - } + ASIO_DECL static address from_string( + const char* str, asio::error_code& ec); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const std::string& str) - { - return from_string(str.c_str()); - } + ASIO_DECL static address from_string(const std::string& str); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - static address from_string(const std::string& str, - asio::error_code& ec) + ASIO_DECL static address from_string( + const std::string& str, asio::error_code& ec); + + /// Compare two addresses for equality. + ASIO_DECL friend bool operator==(const address& a1, const address& a2); + + /// Compare two addresses for inequality. + friend bool operator!=(const address& a1, const address& a2) { - return from_string(str.c_str(), ec); + return !(a1 == a2); } - /// Compare two addresses for equality. - friend bool operator==(const address& a1, const address& a2) + /// Compare addresses for ordering. + ASIO_DECL friend bool operator<(const address& a1, const address& a2); + + /// Compare addresses for ordering. + friend bool operator>(const address& a1, const address& a2) { - if (a1.type_ != a2.type_) - return false; - if (a1.type_ == ipv6) - return a1.ipv6_address_ == a2.ipv6_address_; - return a1.ipv4_address_ == a2.ipv4_address_; + return a2 < a1; } - /// Compare two addresses for inequality. - friend bool operator!=(const address& a1, const address& a2) + /// Compare addresses for ordering. + friend bool operator<=(const address& a1, const address& a2) { - if (a1.type_ != a2.type_) - return true; - if (a1.type_ == ipv6) - return a1.ipv6_address_ != a2.ipv6_address_; - return a1.ipv4_address_ != a2.ipv4_address_; + return !(a2 < a1); } /// Compare addresses for ordering. - friend bool operator<(const address& a1, const address& a2) + friend bool operator>=(const address& a1, const address& a2) { - if (a1.type_ < a2.type_) - return true; - if (a1.type_ > a2.type_) - return false; - if (a1.type_ == ipv6) - return a1.ipv6_address_ < a2.ipv6_address_; - return a1.ipv4_address_ < a2.ipv4_address_; + return !(a1 < a2); } private: @@ -268,11 +164,7 @@ private: */ template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( - std::basic_ostream<Elem, Traits>& os, const address& addr) -{ - os << addr.to_string(); - return os; -} + std::basic_ostream<Elem, Traits>& os, const address& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -281,4 +173,9 @@ std::basic_ostream<Elem, Traits>& operator<<( #include "asio/detail/pop_options.hpp" +#include "asio/ip/impl/address.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/ip/impl/address.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_IP_ADDRESS_HPP diff --git a/ext/asio/asio/ip/address_v4.hpp b/ext/asio/asio/ip/address_v4.hpp index 1b495560fe..7567ef9b42 100644 --- a/ext/asio/asio/ip/address_v4.hpp +++ b/ext/asio/asio/ip/address_v4.hpp @@ -1,8 +1,8 @@ // -// address_v4.hpp -// ~~~~~~~~~~~~~~ +// ip/address_v4.hpp +// ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,24 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <string> +#include <boost/array.hpp> +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/error_code.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> #if !defined(BOOST_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_NO_IOSTREAM) -#include <climits> -#include <string> -#include <stdexcept> -#include <boost/array.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" -#include "asio/detail/socket_ops.hpp" -#include "asio/detail/socket_types.hpp" -#include "asio/detail/throw_error.hpp" +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { @@ -59,34 +53,10 @@ public: } /// Construct an address from raw bytes. - explicit address_v4(const bytes_type& bytes) - { -#if UCHAR_MAX > 0xFF - if (bytes[0] > 0xFF || bytes[1] > 0xFF - || bytes[2] > 0xFF || bytes[3] > 0xFF) - { - std::out_of_range ex("address_v4 from bytes_type"); - boost::throw_exception(ex); - } -#endif // UCHAR_MAX > 0xFF - - using namespace std; // For memcpy. - memcpy(&addr_.s_addr, bytes.elems, 4); - } + ASIO_DECL explicit address_v4(const bytes_type& bytes); /// Construct an address from a unsigned long in host byte order. - explicit address_v4(unsigned long addr) - { -#if ULONG_MAX > 0xFFFFFFFF - if (addr > 0xFFFFFFFF) - { - std::out_of_range ex("address_v4 from unsigned long"); - boost::throw_exception(ex); - } -#endif // ULONG_MAX > 0xFFFFFFFF - - addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr); - } + ASIO_DECL explicit address_v4(unsigned long addr); /// Copy constructor. address_v4(const address_v4& other) @@ -102,96 +72,42 @@ public: } /// Get the address in bytes, in network byte order. - bytes_type to_bytes() const - { - using namespace std; // For memcpy. - bytes_type bytes; - memcpy(bytes.elems, &addr_.s_addr, 4); - return bytes; - } + ASIO_DECL bytes_type to_bytes() const; /// Get the address as an unsigned long in host byte order - unsigned long to_ulong() const - { - return asio::detail::socket_ops::network_to_host_long(addr_.s_addr); - } + ASIO_DECL unsigned long to_ulong() const; /// Get the address as a string in dotted decimal format. - std::string to_string() const - { - asio::error_code ec; - std::string addr = to_string(ec); - asio::detail::throw_error(ec); - return addr; - } + ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. - std::string to_string(asio::error_code& ec) const - { - char addr_str[asio::detail::max_addr_v4_str_len]; - const char* addr = - asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, - asio::detail::max_addr_v4_str_len, 0, ec); - if (addr == 0) - return std::string(); - return addr; - } + ASIO_DECL std::string to_string(asio::error_code& ec) const; /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const char* str) - { - asio::error_code ec; - address_v4 addr = from_string(str, ec); - asio::detail::throw_error(ec); - return addr; - } + ASIO_DECL static address_v4 from_string(const char* str); /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const char* str, asio::error_code& ec) - { - address_v4 tmp; - if (asio::detail::socket_ops::inet_pton( - AF_INET, str, &tmp.addr_, 0, ec) <= 0) - return address_v4(); - return tmp; - } + ASIO_DECL static address_v4 from_string( + const char* str, asio::error_code& ec); /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const std::string& str) - { - return from_string(str.c_str()); - } + ASIO_DECL static address_v4 from_string(const std::string& str); /// Create an address from an IP address string in dotted decimal form. - static address_v4 from_string(const std::string& str, - asio::error_code& ec) - { - return from_string(str.c_str(), ec); - } + ASIO_DECL static address_v4 from_string( + const std::string& str, asio::error_code& ec); /// Determine whether the address is a class A address. - bool is_class_a() const - { - return IN_CLASSA(to_ulong()); - } + ASIO_DECL bool is_class_a() const; /// Determine whether the address is a class B address. - bool is_class_b() const - { - return IN_CLASSB(to_ulong()); - } + ASIO_DECL bool is_class_b() const; /// Determine whether the address is a class C address. - bool is_class_c() const - { - return IN_CLASSC(to_ulong()); - } + ASIO_DECL bool is_class_c() const; /// Determine whether the address is a multicast address. - bool is_multicast() const - { - return IN_MULTICAST(to_ulong()); - } + ASIO_DECL bool is_multicast() const; /// Compare two addresses for equality. friend bool operator==(const address_v4& a1, const address_v4& a2) @@ -249,23 +165,12 @@ public: /// Obtain an address object that represents the broadcast address that /// corresponds to the specified address and netmask. - static address_v4 broadcast(const address_v4& addr, const address_v4& mask) - { - return address_v4(addr.to_ulong() | ~mask.to_ulong()); - } + ASIO_DECL static address_v4 broadcast( + const address_v4& addr, const address_v4& mask); /// Obtain the netmask that corresponds to the address, based on its address /// class. - static address_v4 netmask(const address_v4& addr) - { - if (addr.is_class_a()) - return address_v4(0xFF000000); - if (addr.is_class_b()) - return address_v4(0xFFFF0000); - if (addr.is_class_c()) - return address_v4(0xFFFFFF00); - return address_v4(0xFFFFFFFF); - } + ASIO_DECL static address_v4 netmask(const address_v4& addr); private: // The underlying IPv4 address. @@ -288,22 +193,7 @@ private: */ template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( - std::basic_ostream<Elem, Traits>& os, const address_v4& addr) -{ - asio::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; -} + std::basic_ostream<Elem, Traits>& os, const address_v4& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -312,4 +202,9 @@ std::basic_ostream<Elem, Traits>& operator<<( #include "asio/detail/pop_options.hpp" +#include "asio/ip/impl/address_v4.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/ip/impl/address_v4.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_IP_ADDRESS_V4_HPP diff --git a/ext/asio/asio/ip/address_v6.hpp b/ext/asio/asio/ip/address_v6.hpp index 8d2c08393d..261c6514eb 100644 --- a/ext/asio/asio/ip/address_v6.hpp +++ b/ext/asio/asio/ip/address_v6.hpp @@ -1,8 +1,8 @@ // -// address_v6.hpp -// ~~~~~~~~~~~~~~ +// ip/address_v6.hpp +// ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,26 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <string> +#include <boost/array.hpp> +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/error_code.hpp" +#include "asio/ip/address_v4.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> #if !defined(BOOST_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_NO_IOSTREAM) -#include <cstring> -#include <string> -#include <stdexcept> -#include <typeinfo> -#include <boost/array.hpp> -#include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" -#include "asio/detail/socket_ops.hpp" -#include "asio/detail/socket_types.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/ip/address_v4.hpp" +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { @@ -55,46 +48,17 @@ public: typedef boost::array<unsigned char, 16> bytes_type; /// Default constructor. - address_v6() - : scope_id_(0) - { - asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; - addr_ = tmp_addr; - } + ASIO_DECL address_v6(); /// Construct an address from raw bytes and scope ID. - explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0) - : scope_id_(scope_id) - { -#if UCHAR_MAX > 0xFF - for (std::size_t i = 0; i < bytes.size(); ++i) - { - if (bytes[i] > 0xFF) - { - std::out_of_range ex("address_v6 from bytes_type"); - boost::throw_exception(ex); - } - } -#endif // UCHAR_MAX > 0xFF - - using namespace std; // For memcpy. - memcpy(addr_.s6_addr, bytes.elems, 16); - } + ASIO_DECL explicit address_v6(const bytes_type& bytes, + unsigned long scope_id = 0); /// Copy constructor. - address_v6(const address_v6& other) - : addr_(other.addr_), - scope_id_(other.scope_id_) - { - } + ASIO_DECL address_v6(const address_v6& other); /// Assign from another address. - address_v6& operator=(const address_v6& other) - { - addr_ = other.addr_; - scope_id_ = other.scope_id_; - return *this; - } + ASIO_DECL address_v6& operator=(const address_v6& other); /// The scope ID of the address. /** @@ -115,217 +79,80 @@ public: } /// Get the address in bytes, in network byte order. - bytes_type to_bytes() const - { - using namespace std; // For memcpy. - bytes_type bytes; - memcpy(bytes.elems, addr_.s6_addr, 16); - return bytes; - } + ASIO_DECL bytes_type to_bytes() const; /// Get the address as a string. - std::string to_string() const - { - asio::error_code ec; - std::string addr = to_string(ec); - asio::detail::throw_error(ec); - return addr; - } + ASIO_DECL std::string to_string() const; /// Get the address as a string. - std::string to_string(asio::error_code& ec) const - { - char addr_str[asio::detail::max_addr_v6_str_len]; - const char* addr = - asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, - asio::detail::max_addr_v6_str_len, scope_id_, ec); - if (addr == 0) - return std::string(); - return addr; - } + ASIO_DECL std::string to_string(asio::error_code& ec) const; /// Create an address from an IP address string. - static address_v6 from_string(const char* str) - { - asio::error_code ec; - address_v6 addr = from_string(str, ec); - asio::detail::throw_error(ec); - return addr; - } + ASIO_DECL static address_v6 from_string(const char* str); /// Create an address from an IP address string. - static address_v6 from_string(const char* str, asio::error_code& ec) - { - address_v6 tmp; - if (asio::detail::socket_ops::inet_pton( - AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) - return address_v6(); - return tmp; - } + ASIO_DECL static address_v6 from_string( + const char* str, asio::error_code& ec); /// Create an address from an IP address string. - static address_v6 from_string(const std::string& str) - { - return from_string(str.c_str()); - } + ASIO_DECL static address_v6 from_string(const std::string& str); /// Create an address from an IP address string. - static address_v6 from_string(const std::string& str, - asio::error_code& ec) - { - return from_string(str.c_str(), ec); - } + ASIO_DECL static address_v6 from_string( + const std::string& str, asio::error_code& ec); /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address. - address_v4 to_v4() const - { - if (!is_v4_mapped() && !is_v4_compatible()) - { - std::bad_cast ex; - boost::throw_exception(ex); - } - - address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], - addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; - return address_v4(v4_bytes); - } + ASIO_DECL address_v4 to_v4() const; /// Determine whether the address is a loopback address. - bool is_loopback() const - { -#if defined(__BORLANDC__) - return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) - && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) - && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) - && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) - && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) - && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) - && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) - && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); -#else - using namespace asio::detail; - return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; -#endif - } + ASIO_DECL bool is_loopback() const; /// Determine whether the address is unspecified. - bool is_unspecified() const - { -#if defined(__BORLANDC__) - return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) - && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) - && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) - && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) - && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) - && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) - && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) - && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); -#else - using namespace asio::detail; - return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; -#endif - } + ASIO_DECL bool is_unspecified() const; /// Determine whether the address is link local. - bool is_link_local() const - { - using namespace asio::detail; - return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; - } + ASIO_DECL bool is_link_local() const; /// Determine whether the address is site local. - bool is_site_local() const - { - using namespace asio::detail; - return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; - } + ASIO_DECL bool is_site_local() const; /// Determine whether the address is a mapped IPv4 address. - bool is_v4_mapped() const - { - using namespace asio::detail; - return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; - } + ASIO_DECL bool is_v4_mapped() const; /// Determine whether the address is an IPv4-compatible address. - bool is_v4_compatible() const - { - using namespace asio::detail; - return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; - } + ASIO_DECL bool is_v4_compatible() const; /// Determine whether the address is a multicast address. - bool is_multicast() const - { - using namespace asio::detail; - return IN6_IS_ADDR_MULTICAST(&addr_) != 0; - } + ASIO_DECL bool is_multicast() const; /// Determine whether the address is a global multicast address. - bool is_multicast_global() const - { - using namespace asio::detail; - return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; - } + ASIO_DECL bool is_multicast_global() const; /// Determine whether the address is a link-local multicast address. - bool is_multicast_link_local() const - { - using namespace asio::detail; - return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; - } + ASIO_DECL bool is_multicast_link_local() const; /// Determine whether the address is a node-local multicast address. - bool is_multicast_node_local() const - { - using namespace asio::detail; - return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; - } + ASIO_DECL bool is_multicast_node_local() const; /// Determine whether the address is a org-local multicast address. - bool is_multicast_org_local() const - { - using namespace asio::detail; - return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; - } + ASIO_DECL bool is_multicast_org_local() const; /// Determine whether the address is a site-local multicast address. - bool is_multicast_site_local() const - { - using namespace asio::detail; - return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; - } + ASIO_DECL bool is_multicast_site_local() const; /// Compare two addresses for equality. - friend bool operator==(const address_v6& a1, const address_v6& a2) - { - using namespace std; // For memcmp. - return memcmp(&a1.addr_, &a2.addr_, - sizeof(asio::detail::in6_addr_type)) == 0 - && a1.scope_id_ == a2.scope_id_; - } + ASIO_DECL friend bool operator==( + const address_v6& a1, const address_v6& a2); /// Compare two addresses for inequality. friend bool operator!=(const address_v6& a1, const address_v6& a2) { - using namespace std; // For memcmp. - return memcmp(&a1.addr_, &a2.addr_, - sizeof(asio::detail::in6_addr_type)) != 0 - || a1.scope_id_ != a2.scope_id_; + return !(a1 == a2); } /// Compare addresses for ordering. - friend bool operator<(const address_v6& a1, const address_v6& a2) - { - using namespace std; // For memcmp. - int memcmp_result = memcmp(&a1.addr_, &a2.addr_, - sizeof(asio::detail::in6_addr_type)); - if (memcmp_result < 0) - return true; - if (memcmp_result > 0) - return false; - return a1.scope_id_ < a2.scope_id_; - } + ASIO_DECL friend bool operator<( + const address_v6& a1, const address_v6& a2); /// Compare addresses for ordering. friend bool operator>(const address_v6& a1, const address_v6& a2) @@ -352,31 +179,13 @@ public: } /// Obtain an address object that represents the loopback address. - static address_v6 loopback() - { - address_v6 tmp; - asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; - tmp.addr_ = tmp_addr; - return tmp; - } + ASIO_DECL static address_v6 loopback(); /// Create an IPv4-mapped IPv6 address. - static address_v6 v4_mapped(const address_v4& addr) - { - address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; - return address_v6(v6_bytes); - } + ASIO_DECL static address_v6 v4_mapped(const address_v4& addr); /// Create an IPv4-compatible IPv6 address. - static address_v6 v4_compatible(const address_v4& addr) - { - address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; - return address_v6(v6_bytes); - } + ASIO_DECL static address_v6 v4_compatible(const address_v4& addr); private: // The underlying IPv6 address. @@ -402,22 +211,7 @@ private: */ template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( - std::basic_ostream<Elem, Traits>& os, const address_v6& addr) -{ - asio::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; -} + std::basic_ostream<Elem, Traits>& os, const address_v6& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -426,4 +220,9 @@ std::basic_ostream<Elem, Traits>& operator<<( #include "asio/detail/pop_options.hpp" +#include "asio/ip/impl/address_v6.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/ip/impl/address_v6.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_IP_ADDRESS_V6_HPP diff --git a/ext/asio/asio/ip/basic_endpoint.hpp b/ext/asio/asio/ip/basic_endpoint.hpp index 4ad3f682b7..5e5ef0b01c 100644 --- a/ext/asio/asio/ip/basic_endpoint.hpp +++ b/ext/asio/asio/ip/basic_endpoint.hpp @@ -1,8 +1,8 @@ // -// basic_endpoint.hpp -// ~~~~~~~~~~~~~~~~~~ +// ip/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,25 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include "asio/ip/address.hpp" +#include "asio/ip/detail/endpoint.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include <boost/detail/workaround.hpp> -#include <cstring> #if !defined(BOOST_NO_IOSTREAM) -# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include <ostream> -# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include <sstream> +# include <iosfwd> #endif // !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" -#include "asio/ip/address.hpp" -#include "asio/detail/socket_ops.hpp" -#include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { @@ -67,11 +57,8 @@ public: /// Default constructor. basic_endpoint() - : data_() + : impl_() { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = 0; - data_.v4.sin_addr.s_addr = INADDR_ANY; } /// Construct an endpoint using a port number, specified in the host's byte @@ -91,74 +78,35 @@ public: * @endcode */ basic_endpoint(const InternetProtocol& protocol, unsigned short port_num) - : data_() + : impl_(protocol.family(), port_num) { - using namespace std; // For memcpy. - if (protocol.family() == PF_INET) - { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = - asio::detail::socket_ops::host_to_network_short(port_num); - data_.v4.sin_addr.s_addr = INADDR_ANY; - } - else - { - data_.v6.sin6_family = AF_INET6; - data_.v6.sin6_port = - asio::detail::socket_ops::host_to_network_short(port_num); - data_.v6.sin6_flowinfo = 0; - asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; - data_.v6.sin6_addr = tmp_addr; - data_.v6.sin6_scope_id = 0; - } } /// Construct an endpoint using a port number and an IP address. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. basic_endpoint(const asio::ip::address& addr, unsigned short port_num) - : data_() + : impl_(addr, port_num) { - using namespace std; // For memcpy. - if (addr.is_v4()) - { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = - asio::detail::socket_ops::host_to_network_short(port_num); - data_.v4.sin_addr.s_addr = - asio::detail::socket_ops::host_to_network_long( - addr.to_v4().to_ulong()); - } - else - { - data_.v6.sin6_family = AF_INET6; - data_.v6.sin6_port = - asio::detail::socket_ops::host_to_network_short(port_num); - data_.v6.sin6_flowinfo = 0; - asio::ip::address_v6 v6_addr = addr.to_v6(); - asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); - memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); - data_.v6.sin6_scope_id = v6_addr.scope_id(); - } } /// Copy constructor. basic_endpoint(const basic_endpoint& other) - : data_(other.data_) + : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { - data_ = other.data_; + impl_ = other.impl_; return *this; } /// The protocol associated with the endpoint. protocol_type protocol() const { - if (is_v4()) + if (impl_.is_v4()) return InternetProtocol::v4(); return InternetProtocol::v6(); } @@ -166,137 +114,104 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &data_.base; + return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { - return &data_.base; + return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { - if (is_v4()) - return sizeof(asio::detail::sockaddr_in4_type); - else - return sizeof(asio::detail::sockaddr_in6_type); + return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { - if (size > sizeof(asio::detail::sockaddr_storage_type)) - { - asio::system_error e(asio::error::invalid_argument); - boost::throw_exception(e); - } + impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { - return sizeof(asio::detail::sockaddr_storage_type); + return impl_.capacity(); } /// Get the port associated with the endpoint. The port number is always in /// the host's byte order. unsigned short port() const { - if (is_v4()) - { - return asio::detail::socket_ops::network_to_host_short( - data_.v4.sin_port); - } - else - { - return asio::detail::socket_ops::network_to_host_short( - data_.v6.sin6_port); - } + return impl_.port(); } /// Set the port associated with the endpoint. The port number is always in /// the host's byte order. void port(unsigned short port_num) { - if (is_v4()) - { - data_.v4.sin_port - = asio::detail::socket_ops::host_to_network_short(port_num); - } - else - { - data_.v6.sin6_port - = asio::detail::socket_ops::host_to_network_short(port_num); - } + impl_.port(port_num); } /// Get the IP address associated with the endpoint. asio::ip::address address() const { - using namespace std; // For memcpy. - if (is_v4()) - { - return asio::ip::address_v4( - asio::detail::socket_ops::network_to_host_long( - data_.v4.sin_addr.s_addr)); - } - else - { - asio::ip::address_v6::bytes_type bytes; - memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); - return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); - } + return impl_.address(); } /// Set the IP address associated with the endpoint. void address(const asio::ip::address& addr) { - basic_endpoint<InternetProtocol> tmp_endpoint(addr, port()); - data_ = tmp_endpoint.data_; + impl_.address(addr); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) { - return e1.address() == e2.address() && e1.port() == e2.port(); + return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) { - return e1.address() != e2.address() || e1.port() != e2.port(); + return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) { - if (e1.address() < e2.address()) - return true; - if (e1.address() != e2.address()) - return false; - return e1.port() < e2.port(); + return e1.impl_ < e2.impl_; } -private: - // Helper function to determine whether the endpoint is IPv4. - bool is_v4() const + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint<InternetProtocol>& e1, + const basic_endpoint<InternetProtocol>& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint<InternetProtocol>& e1, + const basic_endpoint<InternetProtocol>& e2) { - return data_.base.sa_family == AF_INET; + return !(e2 < e1); } - // The underlying IP socket address. - union data_union + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint<InternetProtocol>& e1, + const basic_endpoint<InternetProtocol>& e2) { - asio::detail::socket_addr_type base; - asio::detail::sockaddr_storage_type storage; - asio::detail::sockaddr_in4_type v4; - asio::detail::sockaddr_in6_type v6; - } data_; + return !(e1 < e2); + } + +private: + // The underlying IP endpoint. + asio::ip::detail::endpoint impl_; }; #if !defined(BOOST_NO_IOSTREAM) @@ -313,64 +228,10 @@ private: * * @relates asio::ip::basic_endpoint */ -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -template <typename InternetProtocol> -std::ostream& operator<<(std::ostream& os, - const basic_endpoint<InternetProtocol>& endpoint) -{ - const address& addr = endpoint.address(); - asio::error_code ec; - std::string a = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - { - std::ostringstream tmp_os; - tmp_os.imbue(std::locale::classic()); - if (addr.is_v4()) - tmp_os << a; - else - tmp_os << '[' << a << ']'; - tmp_os << ':' << endpoint.port(); - os << tmp_os.str(); - } - return os; -} -#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) template <typename Elem, typename Traits, typename InternetProtocol> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, - const basic_endpoint<InternetProtocol>& endpoint) -{ - const address& addr = endpoint.address(); - asio::error_code ec; - std::string a = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - { - std::ostringstream tmp_os; - tmp_os.imbue(std::locale::classic()); - if (addr.is_v4()) - tmp_os << a; - else - tmp_os << '[' << a << ']'; - tmp_os << ':' << endpoint.port(); - os << tmp_os.str(); - } - return os; -} -#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + const basic_endpoint<InternetProtocol>& endpoint); #endif // !defined(BOOST_NO_IOSTREAM) @@ -379,4 +240,6 @@ std::basic_ostream<Elem, Traits>& operator<<( #include "asio/detail/pop_options.hpp" +#include "asio/ip/impl/basic_endpoint.hpp" + #endif // ASIO_IP_BASIC_ENDPOINT_HPP diff --git a/ext/asio/asio/ip/basic_resolver.hpp b/ext/asio/asio/ip/basic_resolver.hpp index 43a37af392..c8847e15e6 100644 --- a/ext/asio/asio/ip/basic_resolver.hpp +++ b/ext/asio/asio/ip/basic_resolver.hpp @@ -1,8 +1,8 @@ // -// basic_resolver.hpp -// ~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/basic_io_object.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/ip/resolver_service.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/basic_resolver_entry.hpp b/ext/asio/asio/ip/basic_resolver_entry.hpp index 09b144b117..4117b7bc65 100644 --- a/ext/asio/asio/ip/basic_resolver_entry.hpp +++ b/ext/asio/asio/ip/basic_resolver_entry.hpp @@ -1,8 +1,8 @@ // -// basic_resolver_entry.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_entry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <string> #include "asio/detail/push_options.hpp" -#include <string> -#include "asio/detail/pop_options.hpp" namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/basic_resolver_iterator.hpp b/ext/asio/asio/ip/basic_resolver_iterator.hpp index 1982d62512..033b7e0b7d 100644 --- a/ext/asio/asio/ip/basic_resolver_iterator.hpp +++ b/ext/asio/asio/ip/basic_resolver_iterator.hpp @@ -1,8 +1,8 @@ // -// basic_resolver_iterator.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <boost/iterator.hpp> -#include <boost/shared_ptr.hpp> #include <cstring> #include <string> #include <vector> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/shared_ptr.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/ip/basic_resolver_entry.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ip { @@ -176,7 +174,7 @@ private: } typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; - boost::shared_ptr<values_type> values_; + asio::detail::shared_ptr<values_type> values_; std::size_t index_; }; diff --git a/ext/asio/asio/ip/basic_resolver_query.hpp b/ext/asio/asio/ip/basic_resolver_query.hpp index 3cbb335ca5..22ab643bb4 100644 --- a/ext/asio/asio/ip/basic_resolver_query.hpp +++ b/ext/asio/asio/ip/basic_resolver_query.hpp @@ -1,8 +1,8 @@ // -// basic_resolver_query.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_query.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <string> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/socket_ops.hpp" #include "asio/ip/resolver_query_base.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/detail/endpoint.hpp b/ext/asio/asio/ip/detail/endpoint.hpp new file mode 100644 index 0000000000..fbea71e01b --- /dev/null +++ b/ext/asio/asio/ip/detail/endpoint.hpp @@ -0,0 +1,140 @@ +// +// ip/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_DETAIL_ENDPOINT_HPP +#define ASIO_IP_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <string> +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/error_code.hpp" +#include "asio/ip/address.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { +namespace detail { + +// Helper class for implementating an IP endpoint. +class endpoint +{ +public: + // Default constructor. + ASIO_DECL endpoint(); + + // Construct an endpoint using a family and port number. + ASIO_DECL endpoint(int family, unsigned short port_num); + + // Construct an endpoint using an address and port number. + ASIO_DECL endpoint(const asio::ip::address& addr, + unsigned short port_num); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + return *this; + } + + // Get the underlying endpoint in the native type. + asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + if (is_v4()) + return sizeof(asio::detail::sockaddr_in4_type); + else + return sizeof(asio::detail::sockaddr_in6_type); + } + + // Set the underlying size of the endpoint in the native type. + ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(asio::detail::sockaddr_storage_type); + } + + // Get the port associated with the endpoint. + ASIO_DECL unsigned short port() const; + + // Set the port associated with the endpoint. + ASIO_DECL void port(unsigned short port_num); + + // Get the IP address associated with the endpoint. + ASIO_DECL asio::ip::address address() const; + + // Set the IP address associated with the endpoint. + ASIO_DECL void address(const asio::ip::address& addr); + + // Compare two endpoints for equality. + ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + + // Determine whether the endpoint is IPv4. + bool is_v4() const + { + return data_.base.sa_family == AF_INET; + } + +#if !defined(BOOST_NO_IOSTREAM) + // Convert to a string. + ASIO_DECL std::string to_string(asio::error_code& ec) const; +#endif // !defined(BOOST_NO_IOSTREAM) + +private: + // The underlying IP socket address. + union data_union + { + asio::detail::socket_addr_type base; + asio::detail::sockaddr_storage_type storage; + asio::detail::sockaddr_in4_type v4; + asio::detail::sockaddr_in6_type v6; + } data_; +}; + +} // namespace detail +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ip/detail/impl/endpoint.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_IP_DETAIL_ENDPOINT_HPP diff --git a/ext/asio/asio/ip/detail/impl/endpoint.ipp b/ext/asio/asio/ip/detail/impl/endpoint.ipp new file mode 100644 index 0000000000..17efb5cc19 --- /dev/null +++ b/ext/asio/asio/ip/detail/impl/endpoint.ipp @@ -0,0 +1,191 @@ +// +// ip/detail/impl/endpoint.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP +#define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstring> +#if !defined(BOOST_NO_IOSTREAM) +# include <sstream> +#endif // !defined(BOOST_NO_IOSTREAM) +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/ip/detail/endpoint.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { +namespace detail { + +endpoint::endpoint() + : data_() +{ + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = 0; + data_.v4.sin_addr.s_addr = INADDR_ANY; +} + +endpoint::endpoint(int family, unsigned short port_num) + : data_() +{ + using namespace std; // For memcpy. + if (family == PF_INET) + { + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = + asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = INADDR_ANY; + } + else + { + data_.v6.sin6_family = AF_INET6; + data_.v6.sin6_port = + asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; + data_.v6.sin6_addr = tmp_addr; + data_.v6.sin6_scope_id = 0; + } +} + +endpoint::endpoint(const asio::ip::address& addr, + unsigned short port_num) + : data_() +{ + using namespace std; // For memcpy. + if (addr.is_v4()) + { + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = + asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = + asio::detail::socket_ops::host_to_network_long( + addr.to_v4().to_ulong()); + } + else + { + data_.v6.sin6_family = AF_INET6; + data_.v6.sin6_port = + asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + asio::ip::address_v6 v6_addr = addr.to_v6(); + asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); + memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); + data_.v6.sin6_scope_id = v6_addr.scope_id(); + } +} + +void endpoint::resize(std::size_t size) +{ + if (size > sizeof(asio::detail::sockaddr_storage_type)) + { + asio::error_code ec(asio::error::invalid_argument); + asio::detail::throw_error(ec); + } +} + +unsigned short endpoint::port() const +{ + if (is_v4()) + { + return asio::detail::socket_ops::network_to_host_short( + data_.v4.sin_port); + } + else + { + return asio::detail::socket_ops::network_to_host_short( + data_.v6.sin6_port); + } +} + +void endpoint::port(unsigned short port_num) +{ + if (is_v4()) + { + data_.v4.sin_port + = asio::detail::socket_ops::host_to_network_short(port_num); + } + else + { + data_.v6.sin6_port + = asio::detail::socket_ops::host_to_network_short(port_num); + } +} + +asio::ip::address endpoint::address() const +{ + using namespace std; // For memcpy. + if (is_v4()) + { + return asio::ip::address_v4( + asio::detail::socket_ops::network_to_host_long( + data_.v4.sin_addr.s_addr)); + } + else + { + asio::ip::address_v6::bytes_type bytes; + memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); + return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); + } +} + +void endpoint::address(const asio::ip::address& addr) +{ + endpoint tmp_endpoint(addr, port()); + data_ = tmp_endpoint.data_; +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.address() == e2.address() && e1.port() == e2.port(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + if (e1.address() < e2.address()) + return true; + if (e1.address() != e2.address()) + return false; + return e1.port() < e2.port(); +} + +#if !defined(BOOST_NO_IOSTREAM) +std::string endpoint::to_string(asio::error_code& ec) const +{ + std::string a = address().to_string(ec); + if (ec) + return std::string(); + + std::ostringstream tmp_os; + tmp_os.imbue(std::locale::classic()); + if (is_v4()) + tmp_os << a; + else + tmp_os << '[' << a << ']'; + tmp_os << ':' << port(); + + return tmp_os.str(); +} +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace detail +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP diff --git a/ext/asio/asio/ip/detail/socket_option.hpp b/ext/asio/asio/ip/detail/socket_option.hpp index 00045f86d5..e370b113b2 100644 --- a/ext/asio/asio/ip/detail/socket_option.hpp +++ b/ext/asio/asio/ip/detail/socket_option.hpp @@ -1,8 +1,8 @@ // -// socket_option.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,18 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <cstring> -#include <boost/config.hpp> #include <boost/throw_exception.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/ip/address.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/ip/address.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/host_name.hpp b/ext/asio/asio/ip/host_name.hpp index f24ce1a223..8bfaae94c1 100644 --- a/ext/asio/asio/ip/host_name.hpp +++ b/ext/asio/asio/ip/host_name.hpp @@ -1,8 +1,8 @@ // -// host_name.hpp -// ~~~~~~~~~~~~~ +// ip/host_name.hpp +// ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,48 +15,28 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <string> -#include "asio/detail/pop_options.hpp" +#include "asio/error_code.hpp" -#include "asio/error.hpp" -#include "asio/detail/socket_ops.hpp" -#include "asio/detail/throw_error.hpp" +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Get the current host name. -std::string host_name(); +ASIO_DECL std::string host_name(); /// Get the current host name. -std::string host_name(asio::error_code& ec); - -inline std::string host_name() -{ - char name[1024]; - asio::error_code ec; - if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) - { - asio::detail::throw_error(ec); - return std::string(); - } - return std::string(name); -} - -inline std::string host_name(asio::error_code& ec) -{ - char name[1024]; - if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) - return std::string(); - return std::string(name); -} +ASIO_DECL std::string host_name(asio::error_code& ec); } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/ip/impl/host_name.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_IP_HOST_NAME_HPP diff --git a/ext/asio/asio/ip/icmp.hpp b/ext/asio/asio/ip/icmp.hpp index d76b4d1a6d..59df5b027f 100644 --- a/ext/asio/asio/ip/icmp.hpp +++ b/ext/asio/asio/ip/icmp.hpp @@ -1,8 +1,8 @@ // -// icmp.hpp -// ~~~~~~~~ +// ip/icmp.hpp +// ~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" +#include "asio/detail/socket_types.hpp" #include "asio/basic_raw_socket.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" -#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/impl/address.hpp b/ext/asio/asio/ip/impl/address.hpp new file mode 100644 index 0000000000..0983d24684 --- /dev/null +++ b/ext/asio/asio/ip/impl/address.hpp @@ -0,0 +1,53 @@ +// +// ip/impl/address.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_ADDRESS_HPP +#define ASIO_IP_IMPL_ADDRESS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const address& addr) +{ + asio::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream<Elem, Traits>::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // ASIO_IP_IMPL_ADDRESS_HPP diff --git a/ext/asio/asio/ip/impl/address.ipp b/ext/asio/asio/ip/impl/address.ipp new file mode 100644 index 0000000000..d51fa1a44e --- /dev/null +++ b/ext/asio/asio/ip/impl/address.ipp @@ -0,0 +1,186 @@ +// +// ip/impl/address.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_ADDRESS_IPP +#define ASIO_IP_IMPL_ADDRESS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <typeinfo> +#include <boost/throw_exception.hpp> +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/ip/address.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +address::address() + : type_(ipv4), + ipv4_address_(), + ipv6_address_() +{ +} + +address::address(const asio::ip::address_v4& ipv4_address) + : type_(ipv4), + ipv4_address_(ipv4_address), + ipv6_address_() +{ +} + +address::address(const asio::ip::address_v6& ipv6_address) + : type_(ipv6), + ipv4_address_(), + ipv6_address_(ipv6_address) +{ +} + +address::address(const address& other) + : type_(other.type_), + ipv4_address_(other.ipv4_address_), + ipv6_address_(other.ipv6_address_) +{ +} + +address& address::operator=(const address& other) +{ + type_ = other.type_; + ipv4_address_ = other.ipv4_address_; + ipv6_address_ = other.ipv6_address_; + return *this; +} + +address& address::operator=(const asio::ip::address_v4& ipv4_address) +{ + type_ = ipv4; + ipv4_address_ = ipv4_address; + ipv6_address_ = asio::ip::address_v6(); + return *this; +} + +address& address::operator=(const asio::ip::address_v6& ipv6_address) +{ + type_ = ipv6; + ipv4_address_ = asio::ip::address_v4(); + ipv6_address_ = ipv6_address; + return *this; +} + +asio::ip::address_v4 address::to_v4() const +{ + if (type_ != ipv4) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + return ipv4_address_; +} + +asio::ip::address_v6 address::to_v6() const +{ + if (type_ != ipv6) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + return ipv6_address_; +} + +std::string address::to_string() const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(); + return ipv4_address_.to_string(); +} + +std::string address::to_string(asio::error_code& ec) const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(ec); + return ipv4_address_.to_string(ec); +} + +address address::from_string(const char* str) +{ + asio::error_code ec; + address addr = from_string(str, ec); + asio::detail::throw_error(ec); + return addr; +} + +address address::from_string(const char* str, asio::error_code& ec) +{ + asio::ip::address_v6 ipv6_address = + asio::ip::address_v6::from_string(str, ec); + if (!ec) + { + address tmp; + tmp.type_ = ipv6; + tmp.ipv6_address_ = ipv6_address; + return tmp; + } + + asio::ip::address_v4 ipv4_address = + asio::ip::address_v4::from_string(str, ec); + if (!ec) + { + address tmp; + tmp.type_ = ipv4; + tmp.ipv4_address_ = ipv4_address; + return tmp; + } + + return address(); +} + +address address::from_string(const std::string& str) +{ + return from_string(str.c_str()); +} + +address address::from_string(const std::string& str, + asio::error_code& ec) +{ + return from_string(str.c_str(), ec); +} + +bool operator==(const address& a1, const address& a2) +{ + if (a1.type_ != a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ == a2.ipv6_address_; + return a1.ipv4_address_ == a2.ipv4_address_; +} + +bool operator<(const address& a1, const address& a2) +{ + if (a1.type_ < a2.type_) + return true; + if (a1.type_ > a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ < a2.ipv6_address_; + return a1.ipv4_address_ < a2.ipv4_address_; +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_IMPL_ADDRESS_IPP diff --git a/ext/asio/asio/ip/impl/address_v4.hpp b/ext/asio/asio/ip/impl/address_v4.hpp new file mode 100644 index 0000000000..bbe088211b --- /dev/null +++ b/ext/asio/asio/ip/impl/address_v4.hpp @@ -0,0 +1,53 @@ +// +// ip/impl/address_v4.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_ADDRESS_V4_HPP +#define ASIO_IP_IMPL_ADDRESS_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const address_v4& addr) +{ + asio::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream<Elem, Traits>::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // ASIO_IP_IMPL_ADDRESS_V4_HPP diff --git a/ext/asio/asio/ip/impl/address_v4.ipp b/ext/asio/asio/ip/impl/address_v4.ipp new file mode 100644 index 0000000000..b0e1c31546 --- /dev/null +++ b/ext/asio/asio/ip/impl/address_v4.ipp @@ -0,0 +1,162 @@ +// +// ip/impl/address_v4.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_ADDRESS_V4_IPP +#define ASIO_IP_IMPL_ADDRESS_V4_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <climits> +#include <stdexcept> +#include <boost/throw_exception.hpp> +#include "asio/error.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/ip/address_v4.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +address_v4::address_v4(const address_v4::bytes_type& bytes) +{ +#if UCHAR_MAX > 0xFF + if (bytes[0] > 0xFF || bytes[1] > 0xFF + || bytes[2] > 0xFF || bytes[3] > 0xFF) + { + std::out_of_range ex("address_v4 from bytes_type"); + boost::throw_exception(ex); + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(&addr_.s_addr, bytes.elems, 4); +} + +address_v4::address_v4(unsigned long addr) +{ +#if ULONG_MAX > 0xFFFFFFFF + if (addr > 0xFFFFFFFF) + { + std::out_of_range ex("address_v4 from unsigned long"); + boost::throw_exception(ex); + } +#endif // ULONG_MAX > 0xFFFFFFFF + + addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr); +} + +address_v4::bytes_type address_v4::to_bytes() const +{ + using namespace std; // For memcpy. + bytes_type bytes; + memcpy(bytes.elems, &addr_.s_addr, 4); + return bytes; +} + +unsigned long address_v4::to_ulong() const +{ + return asio::detail::socket_ops::network_to_host_long(addr_.s_addr); +} + +std::string address_v4::to_string() const +{ + asio::error_code ec; + std::string addr = to_string(ec); + asio::detail::throw_error(ec); + return addr; +} + +std::string address_v4::to_string(asio::error_code& ec) const +{ + char addr_str[asio::detail::max_addr_v4_str_len]; + const char* addr = + asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, + asio::detail::max_addr_v4_str_len, 0, ec); + if (addr == 0) + return std::string(); + return addr; +} + +address_v4 address_v4::from_string(const char* str) +{ + asio::error_code ec; + address_v4 addr = from_string(str, ec); + asio::detail::throw_error(ec); + return addr; +} + +address_v4 address_v4::from_string( + const char* str, asio::error_code& ec) +{ + address_v4 tmp; + if (asio::detail::socket_ops::inet_pton( + AF_INET, str, &tmp.addr_, 0, ec) <= 0) + return address_v4(); + return tmp; +} + +address_v4 address_v4::from_string(const std::string& str) +{ + return from_string(str.c_str()); +} + +address_v4 address_v4::from_string( + const std::string& str, asio::error_code& ec) +{ + return from_string(str.c_str(), ec); +} + +bool address_v4::is_class_a() const +{ + return IN_CLASSA(to_ulong()); +} + +bool address_v4::is_class_b() const +{ + return IN_CLASSB(to_ulong()); +} + +bool address_v4::is_class_c() const +{ + return IN_CLASSC(to_ulong()); +} + +bool address_v4::is_multicast() const +{ + return IN_MULTICAST(to_ulong()); +} + +address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask) +{ + return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); +} + +address_v4 address_v4::netmask(const address_v4& addr) +{ + if (addr.is_class_a()) + return address_v4(0xFF000000); + if (addr.is_class_b()) + return address_v4(0xFFFF0000); + if (addr.is_class_c()) + return address_v4(0xFFFFFF00); + return address_v4(0xFFFFFFFF); +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_IMPL_ADDRESS_V4_IPP diff --git a/ext/asio/asio/ip/impl/address_v6.hpp b/ext/asio/asio/ip/impl/address_v6.hpp new file mode 100644 index 0000000000..796a505c0a --- /dev/null +++ b/ext/asio/asio/ip/impl/address_v6.hpp @@ -0,0 +1,53 @@ +// +// ip/impl/address_v6.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_ADDRESS_V6_HPP +#define ASIO_IP_IMPL_ADDRESS_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const address_v6& addr) +{ + asio::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream<Elem, Traits>::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // ASIO_IP_IMPL_ADDRESS_V6_HPP diff --git a/ext/asio/asio/ip/impl/address_v6.ipp b/ext/asio/asio/ip/impl/address_v6.ipp new file mode 100644 index 0000000000..c49e7ab7bf --- /dev/null +++ b/ext/asio/asio/ip/impl/address_v6.ipp @@ -0,0 +1,284 @@ +// +// ip/impl/address_v6.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_ADDRESS_V6_IPP +#define ASIO_IP_IMPL_ADDRESS_V6_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstring> +#include <stdexcept> +#include <typeinfo> +#include <boost/throw_exception.hpp> +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/ip/address_v6.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +address_v6::address_v6() + : scope_id_(0) +{ + asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; + addr_ = tmp_addr; +} + +address_v6::address_v6(const address_v6::bytes_type& bytes, + unsigned long scope_id) + : scope_id_(scope_id) +{ +#if UCHAR_MAX > 0xFF + for (std::size_t i = 0; i < bytes.size(); ++i) + { + if (bytes[i] > 0xFF) + { + std::out_of_range ex("address_v6 from bytes_type"); + boost::throw_exception(ex); + } + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(addr_.s6_addr, bytes.elems, 16); +} + +address_v6::address_v6(const address_v6& other) + : addr_(other.addr_), + scope_id_(other.scope_id_) +{ +} + +address_v6& address_v6::operator=(const address_v6& other) +{ + addr_ = other.addr_; + scope_id_ = other.scope_id_; + return *this; +} + +address_v6::bytes_type address_v6::to_bytes() const +{ + using namespace std; // For memcpy. + bytes_type bytes; + memcpy(bytes.elems, addr_.s6_addr, 16); + return bytes; +} + +std::string address_v6::to_string() const +{ + asio::error_code ec; + std::string addr = to_string(ec); + asio::detail::throw_error(ec); + return addr; +} + +std::string address_v6::to_string(asio::error_code& ec) const +{ + char addr_str[asio::detail::max_addr_v6_str_len]; + const char* addr = + asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, + asio::detail::max_addr_v6_str_len, scope_id_, ec); + if (addr == 0) + return std::string(); + return addr; +} + +address_v6 address_v6::from_string(const char* str) +{ + asio::error_code ec; + address_v6 addr = from_string(str, ec); + asio::detail::throw_error(ec); + return addr; +} + +address_v6 address_v6::from_string( + const char* str, asio::error_code& ec) +{ + address_v6 tmp; + if (asio::detail::socket_ops::inet_pton( + AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) + return address_v6(); + return tmp; +} + +address_v6 address_v6::from_string(const std::string& str) +{ + return from_string(str.c_str()); +} + +address_v6 address_v6::from_string( + const std::string& str, asio::error_code& ec) +{ + return from_string(str.c_str(), ec); +} + +address_v4 address_v6::to_v4() const +{ + if (!is_v4_mapped() && !is_v4_compatible()) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + + address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], + addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; + return address_v4(v4_bytes); +} + +bool address_v6::is_loopback() const +{ +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); +#else + using namespace asio::detail; + return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; +#endif +} + +bool address_v6::is_unspecified() const +{ +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); +#else + using namespace asio::detail; + return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; +#endif +} + +bool address_v6::is_link_local() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; +} + +bool address_v6::is_site_local() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; +} + +bool address_v6::is_v4_mapped() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; +} + +bool address_v6::is_v4_compatible() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; +} + +bool address_v6::is_multicast() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_MULTICAST(&addr_) != 0; +} + +bool address_v6::is_multicast_global() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; +} + +bool address_v6::is_multicast_link_local() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_node_local() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_org_local() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_site_local() const +{ + using namespace asio::detail; + return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; +} + +bool operator==(const address_v6& a1, const address_v6& a2) +{ + using namespace std; // For memcmp. + return memcmp(&a1.addr_, &a2.addr_, + sizeof(asio::detail::in6_addr_type)) == 0 + && a1.scope_id_ == a2.scope_id_; +} + +bool operator<(const address_v6& a1, const address_v6& a2) +{ + using namespace std; // For memcmp. + int memcmp_result = memcmp(&a1.addr_, &a2.addr_, + sizeof(asio::detail::in6_addr_type)); + if (memcmp_result < 0) + return true; + if (memcmp_result > 0) + return false; + return a1.scope_id_ < a2.scope_id_; +} + +address_v6 address_v6::loopback() +{ + address_v6 tmp; + asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; + tmp.addr_ = tmp_addr; + return tmp; +} + +address_v6 address_v6::v4_mapped(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +address_v6 address_v6::v4_compatible(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_IMPL_ADDRESS_V6_IPP diff --git a/ext/asio/asio/ip/impl/basic_endpoint.hpp b/ext/asio/asio/ip/impl/basic_endpoint.hpp new file mode 100644 index 0000000000..db7d5fb27e --- /dev/null +++ b/ext/asio/asio/ip/impl/basic_endpoint.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_BASIC_ENDPOINT_HPP +#define ASIO_IP_IMPL_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +template <typename Elem, typename Traits, typename InternetProtocol> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, + const basic_endpoint<InternetProtocol>& endpoint) +{ + asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port()); + asio::error_code ec; + std::string s = tmp_ep.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream<Elem, Traits>::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // ASIO_IP_IMPL_BASIC_ENDPOINT_HPP diff --git a/ext/asio/asio/ip/impl/host_name.ipp b/ext/asio/asio/ip/impl/host_name.ipp new file mode 100644 index 0000000000..46b3f1bd94 --- /dev/null +++ b/ext/asio/asio/ip/impl/host_name.ipp @@ -0,0 +1,54 @@ +// +// ip/impl/host_name.ipp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_IMPL_HOST_NAME_IPP +#define ASIO_IP_IMPL_HOST_NAME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/ip/host_name.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ip { + +std::string host_name() +{ + char name[1024]; + asio::error_code ec; + if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + { + asio::detail::throw_error(ec); + return std::string(); + } + return std::string(name); +} + +std::string host_name(asio::error_code& ec) +{ + char name[1024]; + if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + return std::string(); + return std::string(name); +} + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_IMPL_HOST_NAME_IPP diff --git a/ext/asio/asio/ip/multicast.hpp b/ext/asio/asio/ip/multicast.hpp index eeedc6ce19..f2193c0817 100644 --- a/ext/asio/asio/ip/multicast.hpp +++ b/ext/asio/asio/ip/multicast.hpp @@ -1,8 +1,8 @@ // -// multicast.hpp -// ~~~~~~~~~~~~~ +// ip/multicast.hpp +// ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/ip/detail/socket_option.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ip { namespace multicast { diff --git a/ext/asio/asio/ip/resolver_query_base.hpp b/ext/asio/asio/ip/resolver_query_base.hpp index 5a0acea8f3..8963f41dd8 100644 --- a/ext/asio/asio/ip/resolver_query_base.hpp +++ b/ext/asio/asio/ip/resolver_query_base.hpp @@ -1,8 +1,8 @@ // -// resolver_query_base.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// ip/resolver_query_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/resolver_service.hpp b/ext/asio/asio/ip/resolver_service.hpp index 75f6b2c3af..0d866d6610 100644 --- a/ext/asio/asio/ip/resolver_service.hpp +++ b/ext/asio/asio/ip/resolver_service.hpp @@ -1,8 +1,8 @@ // -// resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// ip/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/error.hpp" +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/resolver_service.hpp" #include "asio/io_service.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" -#include "asio/detail/resolver_service.hpp" -#include "asio/detail/service_base.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { @@ -72,13 +72,14 @@ public: explicit resolver_service(asio::io_service& io_service) : asio::detail::service_base< resolver_service<InternetProtocol> >(io_service), - service_impl_(asio::use_service<service_impl_type>(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new resolver implementation. @@ -130,8 +131,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace ip diff --git a/ext/asio/asio/ip/tcp.hpp b/ext/asio/asio/ip/tcp.hpp index a2e9ac9c52..67fb09f122 100644 --- a/ext/asio/asio/ip/tcp.hpp +++ b/ext/asio/asio/ip/tcp.hpp @@ -1,8 +1,8 @@ // -// tcp.hpp -// ~~~~~~~ +// ip/tcp.hpp +// ~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_stream_socket.hpp" +#include "asio/detail/socket_option.hpp" +#include "asio/detail/socket_types.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" -#include "asio/detail/socket_option.hpp" -#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/udp.hpp b/ext/asio/asio/ip/udp.hpp index fb261187a8..ca3ac785f5 100644 --- a/ext/asio/asio/ip/udp.hpp +++ b/ext/asio/asio/ip/udp.hpp @@ -1,8 +1,8 @@ // -// udp.hpp -// ~~~~~~~ +// ip/udp.hpp +// ~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/basic_datagram_socket.hpp" +#include "asio/detail/socket_types.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" -#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ip { diff --git a/ext/asio/asio/ip/unicast.hpp b/ext/asio/asio/ip/unicast.hpp index 46d7239c8e..e3d04e5899 100644 --- a/ext/asio/asio/ip/unicast.hpp +++ b/ext/asio/asio/ip/unicast.hpp @@ -1,8 +1,8 @@ // -// unicast.hpp -// ~~~~~~~~~~~ +// ip/unicast.hpp +// ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/ip/detail/socket_option.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ip { namespace unicast { diff --git a/ext/asio/asio/ip/v6_only.hpp b/ext/asio/asio/ip/v6_only.hpp index 928caff0df..5ac6a37f7f 100644 --- a/ext/asio/asio/ip/v6_only.hpp +++ b/ext/asio/asio/ip/v6_only.hpp @@ -1,8 +1,8 @@ // -// v6_only.hpp -// ~~~~~~~~~~~ +// ip/v6_only.hpp +// ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/socket_option.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ip { diff --git a/ext/asio/asio/is_read_buffered.hpp b/ext/asio/asio/is_read_buffered.hpp index 8d971747a3..e48de55227 100644 --- a/ext/asio/asio/is_read_buffered.hpp +++ b/ext/asio/asio/is_read_buffered.hpp @@ -2,7 +2,7 @@ // is_read_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/buffered_read_stream_fwd.hpp" #include "asio/buffered_stream_fwd.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/is_write_buffered.hpp b/ext/asio/asio/is_write_buffered.hpp index 5d16b1c542..c681a2bb92 100644 --- a/ext/asio/asio/is_write_buffered.hpp +++ b/ext/asio/asio/is_write_buffered.hpp @@ -2,7 +2,7 @@ // is_write_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/buffered_stream_fwd.hpp" #include "asio/buffered_write_stream_fwd.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { diff --git a/ext/asio/asio/local/basic_endpoint.hpp b/ext/asio/asio/local/basic_endpoint.hpp index 81e6a7ed57..d2d0a023e7 100644 --- a/ext/asio/asio/local/basic_endpoint.hpp +++ b/ext/asio/asio/local/basic_endpoint.hpp @@ -1,8 +1,8 @@ // -// basic_endpoint.hpp -// ~~~~~~~~~~~~~~~~~~ +// local/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,30 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/throw_exception.hpp> -#include <cstddef> -#include <cstring> -#include <ostream> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/system_error.hpp" -#include "asio/detail/socket_ops.hpp" -#include "asio/detail/socket_types.hpp" -#include "asio/detail/throw_error.hpp" - -#if !defined(ASIO_DISABLE_LOCAL_SOCKETS) -# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define ASIO_HAS_LOCAL_SOCKETS 1 -# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS) +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include "asio/local/detail/endpoint.hpp" + +#if !defined(BOOST_NO_IOSTREAM) +# include <iosfwd> +#endif // !defined(BOOST_NO_IOSTREAM) + +#include "asio/detail/push_options.hpp" namespace asio { namespace local { @@ -74,34 +62,30 @@ public: /// Default constructor. basic_endpoint() { - init("", 0); } /// Construct an endpoint using the specified path name. basic_endpoint(const char* path) + : impl_(path) { - using namespace std; // For strlen. - init(path, strlen(path)); } /// Construct an endpoint using the specified path name. basic_endpoint(const std::string& path) + : impl_(path) { - init(path.data(), path.length()); } /// Copy constructor. basic_endpoint(const basic_endpoint& other) - : data_(other.data_), - path_length_(other.path_length_) + : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { - data_ = other.data_; - path_length_ = other.path_length_; + impl_ = other.impl_; return *this; } @@ -114,123 +98,96 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &data_.base; + return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { - return &data_.base; + return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { - return path_length_ - + offsetof(asio::detail::sockaddr_un_type, sun_path); + return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { - if (size > sizeof(asio::detail::sockaddr_un_type)) - { - asio::system_error e(asio::error::invalid_argument); - boost::throw_exception(e); - } - else if (size == 0) - { - path_length_ = 0; - } - else - { - path_length_ = size - - offsetof(asio::detail::sockaddr_un_type, sun_path); - - // The path returned by the operating system may be NUL-terminated. - if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) - --path_length_; - } + impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { - return sizeof(asio::detail::sockaddr_un_type); + return impl_.capacity(); } /// Get the path associated with the endpoint. std::string path() const { - return std::string(data_.local.sun_path, path_length_); + return impl_.path(); } /// Set the path associated with the endpoint. void path(const char* p) { - using namespace std; // For strlen. - init(p, strlen(p)); + impl_.path(p); } /// Set the path associated with the endpoint. void path(const std::string& p) { - init(p.data(), p.length()); + impl_.path(p); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { - return e1.path() == e2.path(); + return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { - return e1.path() != e2.path(); + return !(e1.impl_ == e2.impl_); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { - return e1.path() < e2.path(); + return e1.impl_ < e2.impl_; } -private: - // The underlying UNIX socket address. - union data_union + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint<Protocol>& e1, + const basic_endpoint<Protocol>& e2) { - asio::detail::socket_addr_type base; - asio::detail::sockaddr_un_type local; - } data_; + return e2.impl_ < e1.impl_; + } - // The length of the path associated with the endpoint. - std::size_t path_length_; + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint<Protocol>& e1, + const basic_endpoint<Protocol>& e2) + { + return !(e2 < e1); + } - // Initialise with a specified path. - void init(const char* path, std::size_t path_length) + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint<Protocol>& e1, + const basic_endpoint<Protocol>& e2) { - if (path_length > sizeof(data_.local.sun_path) - 1) - { - // The buffer is not large enough to store this address. - asio::error_code ec(asio::error::name_too_long); - asio::detail::throw_error(ec); - } - - using namespace std; // For memcpy. - data_.local = asio::detail::sockaddr_un_type(); - data_.local.sun_family = AF_UNIX; - memcpy(data_.local.sun_path, path, path_length); - path_length_ = path_length; - - // NUL-terminate normal path names. Names that start with a NUL are in the - // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. - if (path_length > 0 && data_.local.sun_path[0] == 0) - data_.local.sun_path[path_length] = 0; + return !(e1 < e2); } + +private: + // The underlying UNIX domain endpoint. + asio::local::detail::endpoint impl_; }; /// Output an endpoint as a string. @@ -257,9 +214,9 @@ std::basic_ostream<Elem, Traits>& operator<<( } // namespace local } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP diff --git a/ext/asio/asio/local/connect_pair.hpp b/ext/asio/asio/local/connect_pair.hpp index da1d4fc5bd..4a582477e3 100644 --- a/ext/asio/asio/local/connect_pair.hpp +++ b/ext/asio/asio/local/connect_pair.hpp @@ -1,8 +1,8 @@ // -// connect_pair.hpp -// ~~~~~~~~~~~~~~~~ +// local/connect_pair.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) #include "asio/basic_socket.hpp" -#include "asio/error.hpp" -#include "asio/local/basic_endpoint.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/local/basic_endpoint.hpp" -#if defined(ASIO_HAS_LOCAL_SOCKETS) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace local { @@ -73,8 +75,9 @@ inline asio::error_code connect_pair( if (socket1.assign(protocol, sv[0], ec)) { asio::error_code temp_ec; - asio::detail::socket_ops::close(sv[0], temp_ec); - asio::detail::socket_ops::close(sv[1], temp_ec); + asio::detail::socket_ops::state_type state[2] = { 0, 0 }; + asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec); + asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec); return ec; } @@ -82,7 +85,8 @@ inline asio::error_code connect_pair( { asio::error_code temp_ec; socket1.close(temp_ec); - asio::detail::socket_ops::close(sv[1], temp_ec); + asio::detail::socket_ops::state_type state = 0; + asio::detail::socket_ops::close(sv[1], state, true, temp_ec); return ec; } @@ -92,9 +96,9 @@ inline asio::error_code connect_pair( } // namespace local } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_LOCAL_CONNECT_PAIR_HPP diff --git a/ext/asio/asio/local/datagram_protocol.hpp b/ext/asio/asio/local/datagram_protocol.hpp index 0340180545..39f47ce7d5 100644 --- a/ext/asio/asio/local/datagram_protocol.hpp +++ b/ext/asio/asio/local/datagram_protocol.hpp @@ -1,8 +1,8 @@ // -// datagram_protocol.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// local/datagram_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) #include "asio/basic_datagram_socket.hpp" -#include "asio/local/basic_endpoint.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/local/basic_endpoint.hpp" -#if defined(ASIO_HAS_LOCAL_SOCKETS) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace local { @@ -70,9 +72,9 @@ public: } // namespace local } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP diff --git a/ext/asio/asio/local/detail/endpoint.hpp b/ext/asio/asio/local/detail/endpoint.hpp new file mode 100644 index 0000000000..05fc992383 --- /dev/null +++ b/ext/asio/asio/local/detail/endpoint.hpp @@ -0,0 +1,133 @@ +// +// local/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_LOCAL_DETAIL_ENDPOINT_HPP +#define ASIO_LOCAL_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_LOCAL_SOCKETS) + +#include <cstddef> +#include <string> +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace local { +namespace detail { + +// Helper class for implementing a UNIX domain endpoint. +class endpoint +{ +public: + // Default constructor. + ASIO_DECL endpoint(); + + // Construct an endpoint using the specified path name. + ASIO_DECL endpoint(const char* path); + + // Construct an endpoint using the specified path name. + ASIO_DECL endpoint(const std::string& path); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_), + path_length_(other.path_length_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + path_length_ = other.path_length_; + return *this; + } + + // Get the underlying endpoint in the native type. + asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return path_length_ + + offsetof(asio::detail::sockaddr_un_type, sun_path); + } + + // Set the underlying size of the endpoint in the native type. + ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(asio::detail::sockaddr_un_type); + } + + // Get the path associated with the endpoint. + ASIO_DECL std::string path() const; + + // Set the path associated with the endpoint. + ASIO_DECL void path(const char* p); + + // Set the path associated with the endpoint. + ASIO_DECL void path(const std::string& p); + + // Compare two endpoints for equality. + ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + +private: + // The underlying UNIX socket address. + union data_union + { + asio::detail::socket_addr_type base; + asio::detail::sockaddr_un_type local; + } data_; + + // The length of the path associated with the endpoint. + std::size_t path_length_; + + // Initialise with a specified path. + ASIO_DECL void init(const char* path, std::size_t path_length); +}; + +} // namespace detail +} // namespace local +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/local/detail/impl/endpoint.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_LOCAL_SOCKETS) + +#endif // ASIO_LOCAL_DETAIL_ENDPOINT_HPP diff --git a/ext/asio/asio/local/detail/impl/endpoint.ipp b/ext/asio/asio/local/detail/impl/endpoint.ipp new file mode 100644 index 0000000000..e1bb53fea9 --- /dev/null +++ b/ext/asio/asio/local/detail/impl/endpoint.ipp @@ -0,0 +1,128 @@ +// +// local/detail/impl/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP +#define ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_LOCAL_SOCKETS) + +#include <cstring> +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/local/detail/endpoint.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace local { +namespace detail { + +endpoint::endpoint() +{ + init("", 0); +} + +endpoint::endpoint(const char* path) +{ + using namespace std; // For strlen. + init(path, strlen(path)); +} + +endpoint::endpoint(const std::string& path) +{ + init(path.data(), path.length()); +} + +void endpoint::resize(std::size_t size) +{ + if (size > sizeof(asio::detail::sockaddr_un_type)) + { + asio::error_code ec(asio::error::invalid_argument); + asio::detail::throw_error(ec); + } + else if (size == 0) + { + path_length_ = 0; + } + else + { + path_length_ = size + - offsetof(asio::detail::sockaddr_un_type, sun_path); + + // The path returned by the operating system may be NUL-terminated. + if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) + --path_length_; + } +} + +std::string endpoint::path() const +{ + return std::string(data_.local.sun_path, path_length_); +} + +void endpoint::path(const char* p) +{ + using namespace std; // For strlen. + init(p, strlen(p)); +} + +void endpoint::path(const std::string& p) +{ + init(p.data(), p.length()); +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.path() == e2.path(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + return e1.path() < e2.path(); +} + +void endpoint::init(const char* path, std::size_t path_length) +{ + if (path_length > sizeof(data_.local.sun_path) - 1) + { + // The buffer is not large enough to store this address. + asio::error_code ec(asio::error::name_too_long); + asio::detail::throw_error(ec); + } + + using namespace std; // For memcpy. + data_.local = asio::detail::sockaddr_un_type(); + data_.local.sun_family = AF_UNIX; + memcpy(data_.local.sun_path, path, path_length); + path_length_ = path_length; + + // NUL-terminate normal path names. Names that start with a NUL are in the + // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. + if (path_length > 0 && data_.local.sun_path[0] == 0) + data_.local.sun_path[path_length] = 0; +} + +} // namespace detail +} // namespace local +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_LOCAL_SOCKETS) + +#endif // ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP diff --git a/ext/asio/asio/local/stream_protocol.hpp b/ext/asio/asio/local/stream_protocol.hpp index 47fe42f132..e65a2f6dfb 100644 --- a/ext/asio/asio/local/stream_protocol.hpp +++ b/ext/asio/asio/local/stream_protocol.hpp @@ -1,8 +1,8 @@ // -// stream_protocol.hpp -// ~~~~~~~~~~~~~~~~~~~ +// local/stream_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_stream_socket.hpp" -#include "asio/local/basic_endpoint.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/local/basic_endpoint.hpp" -#if defined(ASIO_HAS_LOCAL_SOCKETS) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace local { @@ -80,9 +82,9 @@ public: } // namespace local } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP diff --git a/ext/asio/asio/placeholders.hpp b/ext/asio/asio/placeholders.hpp index 70e69fca53..6fda487d7f 100644 --- a/ext/asio/asio/placeholders.hpp +++ b/ext/asio/asio/placeholders.hpp @@ -2,7 +2,7 @@ // placeholders.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <boost/bind/arg.hpp> #include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace placeholders { diff --git a/ext/asio/asio/posix/basic_descriptor.hpp b/ext/asio/asio/posix/basic_descriptor.hpp index 37bcc94dfc..591e65a6d9 100644 --- a/ext/asio/asio/posix/basic_descriptor.hpp +++ b/ext/asio/asio/posix/basic_descriptor.hpp @@ -1,8 +1,8 @@ // -// basic_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// posix/basic_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) #include "asio/basic_io_object.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/posix/descriptor_base.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace posix { @@ -291,4 +292,7 @@ protected: #include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + #endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/ext/asio/asio/posix/basic_stream_descriptor.hpp b/ext/asio/asio/posix/basic_stream_descriptor.hpp index 21e2287dbf..8211c58d06 100644 --- a/ext/asio/asio/posix/basic_stream_descriptor.hpp +++ b/ext/asio/asio/posix/basic_stream_descriptor.hpp @@ -1,8 +1,8 @@ // -// basic_stream_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// posix/basic_stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) +#include <cstddef> +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/posix/basic_descriptor.hpp" #include "asio/posix/stream_descriptor_service.hpp" -#include "asio/detail/throw_error.hpp" -#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace posix { @@ -296,9 +294,9 @@ public: } // namespace posix } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/ext/asio/asio/posix/descriptor_base.hpp b/ext/asio/asio/posix/descriptor_base.hpp index 29e17469df..2222915678 100644 --- a/ext/asio/asio/posix/descriptor_base.hpp +++ b/ext/asio/asio/posix/descriptor_base.hpp @@ -1,8 +1,8 @@ // -// descriptor_base.hpp -// ~~~~~~~~~~~~~~~~~~~ +// posix/descriptor_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) #include "asio/detail/io_control.hpp" #include "asio/detail/socket_option.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace posix { @@ -90,4 +90,7 @@ protected: #include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + #endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP diff --git a/ext/asio/asio/posix/stream_descriptor.hpp b/ext/asio/asio/posix/stream_descriptor.hpp index 72fbbed23c..48c20a3686 100644 --- a/ext/asio/asio/posix/stream_descriptor.hpp +++ b/ext/asio/asio/posix/stream_descriptor.hpp @@ -1,8 +1,8 @@ // -// stream_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// posix/stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/posix/basic_stream_descriptor.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include "asio/posix/basic_stream_descriptor.hpp" + namespace asio { namespace posix { @@ -34,6 +34,4 @@ typedef basic_stream_descriptor<> stream_descriptor; #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP diff --git a/ext/asio/asio/posix/stream_descriptor_service.hpp b/ext/asio/asio/posix/stream_descriptor_service.hpp index 61cee1b54d..4660e79dab 100644 --- a/ext/asio/asio/posix/stream_descriptor_service.hpp +++ b/ext/asio/asio/posix/stream_descriptor_service.hpp @@ -1,8 +1,8 @@ // -// stream_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// posix/stream_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,28 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/error.hpp" -#include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" - -#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) -# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 -# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include <cstddef> +#include "asio/error.hpp" +#include "asio/io_service.hpp" #include "asio/detail/reactive_descriptor_service.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace posix { @@ -179,9 +169,9 @@ private: } // namespace posix } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP diff --git a/ext/asio/asio/raw_socket_service.hpp b/ext/asio/asio/raw_socket_service.hpp index a8973d3445..3d0016d328 100644 --- a/ext/asio/asio/raw_socket_service.hpp +++ b/ext/asio/asio/raw_socket_service.hpp @@ -2,7 +2,7 @@ // raw_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" @@ -32,6 +26,8 @@ # include "asio/detail/reactive_socket_service.hpp" #endif +#include "asio/detail/push_options.hpp" + namespace asio { /// Default service implementation for a raw socket. diff --git a/ext/asio/asio/read.hpp b/ext/asio/asio/read.hpp index 859c05a003..7f04b07dbd 100644 --- a/ext/asio/asio/read.hpp +++ b/ext/asio/asio/read.hpp @@ -2,7 +2,7 @@ // read.hpp // ~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/basic_streambuf.hpp" +#include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /** @@ -536,8 +533,8 @@ void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, } // namespace asio -#include "asio/impl/read.ipp" - #include "asio/detail/pop_options.hpp" +#include "asio/impl/read.hpp" + #endif // ASIO_READ_HPP diff --git a/ext/asio/asio/read_at.hpp b/ext/asio/asio/read_at.hpp index 6bb3fe125a..4be1f96f2b 100644 --- a/ext/asio/asio/read_at.hpp +++ b/ext/asio/asio/read_at.hpp @@ -2,7 +2,7 @@ // read_at.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> #include <boost/cstdint.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/basic_streambuf.hpp" +#include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /** @@ -569,8 +566,8 @@ void async_read_at(AsyncRandomAccessReadDevice& d, } // namespace asio -#include "asio/impl/read_at.ipp" - #include "asio/detail/pop_options.hpp" +#include "asio/impl/read_at.hpp" + #endif // ASIO_READ_AT_HPP diff --git a/ext/asio/asio/read_until.hpp b/ext/asio/asio/read_until.hpp index 5df71ce29c..67fa066de1 100644 --- a/ext/asio/asio/read_until.hpp +++ b/ext/asio/asio/read_until.hpp @@ -2,7 +2,7 @@ // read_until.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,27 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/push_options.hpp" #include <cstddef> -#include <boost/regex.hpp> #include <boost/type_traits/is_function.hpp> #include <boost/type_traits/remove_pointer.hpp> #include <boost/utility/enable_if.hpp> #include <boost/detail/workaround.hpp> #include <string> -#include "asio/detail/pop_options.hpp" - #include "asio/basic_streambuf.hpp" +#include "asio/detail/regex_fwd.hpp" #include "asio/error.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail @@ -914,10 +909,10 @@ void async_read_until(AsyncReadStream& s, } // namespace asio -#include "asio/impl/read_until.ipp" +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/read_until.hpp" #endif // !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_READ_UNTIL_HPP diff --git a/ext/asio/asio/serial_port.hpp b/ext/asio/asio/serial_port.hpp index a55a03aa07..4cc6fd443b 100644 --- a/ext/asio/asio/serial_port.hpp +++ b/ext/asio/asio/serial_port.hpp @@ -2,7 +2,7 @@ // serial_port.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,13 +16,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/basic_serial_port.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include "asio/basic_serial_port.hpp" + namespace asio { /// Typedef for the typical usage of a serial port. @@ -33,6 +33,4 @@ typedef basic_serial_port<> serial_port; #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_SERIAL_PORT_HPP diff --git a/ext/asio/asio/serial_port_base.hpp b/ext/asio/asio/serial_port_base.hpp index 28e51a08a0..9c7a773954 100644 --- a/ext/asio/asio/serial_port_base.hpp +++ b/ext/asio/asio/serial_port_base.hpp @@ -2,7 +2,7 @@ // serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,32 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <stdexcept> -#include <boost/config.hpp> -#include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" - -#if !defined(ASIO_DISABLE_SERIAL_PORT) -# if defined(ASIO_HAS_IOCP) \ - || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define ASIO_HAS_SERIAL_PORT 1 -# endif // defined(ASIO_HAS_IOCP) -#endif // !defined(ASIO_DISABLE_STREAM_HANDLE) +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# include "asio/detail/push_options.hpp" # include <termios.h> -# include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include "asio/error_code.hpp" +#include <boost/detail/workaround.hpp> #include "asio/detail/socket_types.hpp" +#include "asio/error_code.hpp" #if defined(GENERATING_DOCUMENTATION) # define ASIO_OPTION_STORAGE implementation_defined @@ -51,6 +37,8 @@ # define ASIO_OPTION_STORAGE termios #endif +#include "asio/detail/push_options.hpp" + namespace asio { /// The serial_port_base class is used as a base for the basic_serial_port class @@ -67,9 +55,11 @@ public: public: explicit baud_rate(unsigned int rate = 0); unsigned int value() const; - asio::error_code store(ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; - asio::error_code load(const ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: unsigned int value_; @@ -83,11 +73,13 @@ public: { public: enum type { none, software, hardware }; - explicit flow_control(type t = none); + ASIO_DECL explicit flow_control(type t = none); type value() const; - asio::error_code store(ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; - asio::error_code load(const ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: type value_; @@ -101,11 +93,13 @@ public: { public: enum type { none, odd, even }; - explicit parity(type t = none); + ASIO_DECL explicit parity(type t = none); type value() const; - asio::error_code store(ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; - asio::error_code load(const ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: type value_; @@ -119,11 +113,13 @@ public: { public: enum type { one, onepointfive, two }; - explicit stop_bits(type t = one); + ASIO_DECL explicit stop_bits(type t = one); type value() const; - asio::error_code store(ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; - asio::error_code load(const ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: type value_; @@ -136,11 +132,13 @@ public: class character_size { public: - explicit character_size(unsigned int t = 8); + ASIO_DECL explicit character_size(unsigned int t = 8); unsigned int value() const; - asio::error_code store(ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; - asio::error_code load(const ASIO_OPTION_STORAGE& storage, + ASIO_DECL asio::error_code load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: unsigned int value_; @@ -161,13 +159,16 @@ private: } // namespace asio -#include "asio/impl/serial_port_base.ipp" +#include "asio/detail/pop_options.hpp" #undef ASIO_OPTION_STORAGE +#include "asio/impl/serial_port_base.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/serial_port_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_SERIAL_PORT_BASE_HPP diff --git a/ext/asio/asio/serial_port_service.hpp b/ext/asio/asio/serial_port_service.hpp index 5847c293f5..37142d5b56 100644 --- a/ext/asio/asio/serial_port_service.hpp +++ b/ext/asio/asio/serial_port_service.hpp @@ -2,7 +2,7 @@ // serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,23 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/push_options.hpp" #include <cstddef> -#include <boost/config.hpp> #include <string> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/reactive_serial_port_service.hpp" +#include "asio/detail/win_iocp_serial_port_service.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/serial_port_base.hpp" -#include "asio/detail/service_base.hpp" -#include "asio/detail/reactive_serial_port_service.hpp" -#include "asio/detail/win_iocp_serial_port_service.hpp" -#if defined(ASIO_HAS_SERIAL_PORT) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { @@ -199,9 +196,9 @@ private: } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_SERIAL_PORT_SERVICE_HPP diff --git a/ext/asio/asio/socket_acceptor_service.hpp b/ext/asio/asio/socket_acceptor_service.hpp index b2e2c6d2ec..a1e4874ebf 100644 --- a/ext/asio/asio/socket_acceptor_service.hpp +++ b/ext/asio/asio/socket_acceptor_service.hpp @@ -2,7 +2,7 @@ // socket_acceptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/basic_socket.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" @@ -28,6 +26,8 @@ # include "asio/detail/reactive_socket_service.hpp" #endif +#include "asio/detail/push_options.hpp" + namespace asio { /// Default service implementation for a socket acceptor. diff --git a/ext/asio/asio/socket_base.hpp b/ext/asio/asio/socket_base.hpp index d82cd22e8e..56585e18f4 100644 --- a/ext/asio/asio/socket_base.hpp +++ b/ext/asio/asio/socket_base.hpp @@ -2,7 +2,7 @@ // socket_base.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/io_control.hpp" #include "asio/detail/socket_option.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /// The socket_base class is used as a base for the basic_stream_socket and diff --git a/ext/asio/asio/ssl.hpp b/ext/asio/asio/ssl.hpp index a9fff5e6ed..48aff5a9b9 100644 --- a/ext/asio/asio/ssl.hpp +++ b/ext/asio/asio/ssl.hpp @@ -2,7 +2,7 @@ // ssl.hpp // ~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/ext/asio/asio/ssl/basic_context.hpp b/ext/asio/asio/ssl/basic_context.hpp index ea3893ed5a..20ed57dc2e 100755 --- a/ext/asio/asio/ssl/basic_context.hpp +++ b/ext/asio/asio/ssl/basic_context.hpp @@ -1,9 +1,9 @@ // -// basic_context.hpp -// ~~~~~~~~~~~~~~~~~ +// ssl/basic_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,17 +16,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <string> #include <boost/noncopyable.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ssl/context_base.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ssl { diff --git a/ext/asio/asio/ssl/context.hpp b/ext/asio/asio/ssl/context.hpp index d53882afa9..7aedc4dbd8 100644 --- a/ext/asio/asio/ssl/context.hpp +++ b/ext/asio/asio/ssl/context.hpp @@ -1,9 +1,9 @@ // -// context.hpp -// ~~~~~~~~~~~ +// ssl/context.hpp +// ~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,8 +16,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/context_service.hpp" @@ -30,6 +29,4 @@ typedef basic_context<context_service> context; } // namespace ssl } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // ASIO_SSL_CONTEXT_HPP diff --git a/ext/asio/asio/ssl/context_base.hpp b/ext/asio/asio/ssl/context_base.hpp index a0700ca27a..7636bedebb 100755 --- a/ext/asio/asio/ssl/context_base.hpp +++ b/ext/asio/asio/ssl/context_base.hpp @@ -1,8 +1,8 @@ // -// context_base.hpp -// ~~~~~~~~~~~~~~~~ +// ssl/context_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/ssl/detail/openssl_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ssl { diff --git a/ext/asio/asio/ssl/context_service.hpp b/ext/asio/asio/ssl/context_service.hpp index e9cfef7ef2..766bbdee24 100755 --- a/ext/asio/asio/ssl/context_service.hpp +++ b/ext/asio/asio/ssl/context_service.hpp @@ -1,9 +1,9 @@ // -// context_service.hpp -// ~~~~~~~~~~~~~~~~~~~ +// ssl/context_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,19 +16,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <string> #include <boost/noncopyable.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/detail/openssl_context_service.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ssl { diff --git a/ext/asio/asio/ssl/detail/openssl_context_service.hpp b/ext/asio/asio/ssl/detail/openssl_context_service.hpp index a3d4fdb54c..7019542ee2 100755 --- a/ext/asio/asio/ssl/detail/openssl_context_service.hpp +++ b/ext/asio/asio/ssl/detail/openssl_context_service.hpp @@ -1,9 +1,9 @@ // -// openssl_context_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_context_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,21 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstring> #include <string> #include <boost/function.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/detail/openssl_init.hpp" #include "asio/ssl/detail/openssl_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ssl { namespace detail { diff --git a/ext/asio/asio/ssl/detail/openssl_init.hpp b/ext/asio/asio/ssl/detail/openssl_init.hpp index 9ecbb78ffd..dcda50f32c 100755 --- a/ext/asio/asio/ssl/detail/openssl_init.hpp +++ b/ext/asio/asio/ssl/detail/openssl_init.hpp @@ -1,9 +1,9 @@ // -// openssl_init.hpp -// ~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,20 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstring> #include <vector> #include <boost/assert.hpp> -#include <boost/config.hpp> #include <boost/shared_ptr.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/detail/mutex.hpp" #include "asio/detail/tss_ptr.hpp" #include "asio/ssl/detail/openssl_types.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace ssl { namespace detail { diff --git a/ext/asio/asio/ssl/detail/openssl_operation.hpp b/ext/asio/asio/ssl/detail/openssl_operation.hpp index 8d237e3616..c5119a5915 100755 --- a/ext/asio/asio/ssl/detail/openssl_operation.hpp +++ b/ext/asio/asio/ssl/detail/openssl_operation.hpp @@ -1,6 +1,6 @@ // -// openssl_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // @@ -15,19 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <boost/function.hpp> #include <boost/assert.hpp> #include <boost/bind.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/buffer.hpp" -#include "asio/placeholders.hpp" -#include "asio/write.hpp" #include "asio/detail/socket_ops.hpp" +#include "asio/placeholders.hpp" #include "asio/ssl/detail/openssl_types.hpp" +#include "asio/strand.hpp" +#include "asio/system_error.hpp" +#include "asio/write.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ssl { @@ -160,7 +160,7 @@ public: if (error_code == SSL_ERROR_SSL) return handler_(asio::error_code( - error_code, asio::error::get_ssl_category()), rc); + sys_error_code, asio::error::get_ssl_category()), rc); bool is_read_needed = (error_code == SSL_ERROR_WANT_READ); bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE || @@ -195,7 +195,7 @@ public: else { return handler_(asio::error_code( - error_code, asio::error::get_ssl_category()), rc); + sys_error_code, asio::error::get_ssl_category()), rc); } } diff --git a/ext/asio/asio/ssl/detail/openssl_stream_service.hpp b/ext/asio/asio/ssl/detail/openssl_stream_service.hpp index d7bb457a9e..aef9e7e955 100644 --- a/ext/asio/asio/ssl/detail/openssl_stream_service.hpp +++ b/ext/asio/asio/ssl/detail/openssl_stream_service.hpp @@ -1,9 +1,9 @@ // -// stream_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// ssl/detail/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,9 +16,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> #include <climits> #include <memory> @@ -26,17 +24,17 @@ #include <boost/noncopyable.hpp> #include <boost/function.hpp> #include <boost/bind.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/strand.hpp" -#include "asio/detail/buffer_sequence_adapter.hpp" -#include "asio/detail/service_base.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/detail/openssl_operation.hpp" #include "asio/ssl/detail/openssl_types.hpp" +#include "asio/strand.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ssl { @@ -92,7 +90,7 @@ private: : base_handler<Stream>(io_service) , handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &io_handler<Stream, Handler>::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } @@ -116,7 +114,7 @@ private: : base_handler<Stream>(io_service) , handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &handshake_handler<Stream, Handler>::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } @@ -141,7 +139,7 @@ private: : base_handler<Stream>(io_service), handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &shutdown_handler<Stream, Handler>::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } diff --git a/ext/asio/asio/ssl/detail/openssl_types.hpp b/ext/asio/asio/ssl/detail/openssl_types.hpp index c697d7400c..fbe1b74370 100755 --- a/ext/asio/asio/ssl/detail/openssl_types.hpp +++ b/ext/asio/asio/ssl/detail/openssl_types.hpp @@ -1,8 +1,8 @@ // -// openssl_types.hpp -// ~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/socket_types.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <openssl/conf.h> #include <openssl/ssl.h> #include <openssl/engine.h> #include <openssl/err.h> -#include "asio/detail/pop_options.hpp" - -#include "asio/detail/pop_options.hpp" +#include "asio/detail/socket_types.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP diff --git a/ext/asio/asio/ssl/stream.hpp b/ext/asio/asio/ssl/stream.hpp index e800e626ab..e16cd9a35e 100644 --- a/ext/asio/asio/ssl/stream.hpp +++ b/ext/asio/asio/ssl/stream.hpp @@ -1,9 +1,9 @@ // -// stream.hpp -// ~~~~~~~~~~ +// ssl/stream.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,20 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> #include <boost/noncopyable.hpp> #include <boost/type_traits/remove_reference.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/stream_service.hpp" -#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ssl { diff --git a/ext/asio/asio/ssl/stream_base.hpp b/ext/asio/asio/ssl/stream_base.hpp index d62d386ae5..e1cc0d72c5 100755 --- a/ext/asio/asio/ssl/stream_base.hpp +++ b/ext/asio/asio/ssl/stream_base.hpp @@ -1,8 +1,8 @@ // -// stream_base.hpp -// ~~~~~~~~~~~~~~~ +// ssl/stream_base.hpp +// ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" +#include <boost/detail/workaround.hpp> #include "asio/detail/push_options.hpp" -#include <boost/detail/workaround.hpp> -#include "asio/detail/pop_options.hpp" namespace asio { namespace ssl { diff --git a/ext/asio/asio/ssl/stream_service.hpp b/ext/asio/asio/ssl/stream_service.hpp index 1f1e6ad96d..d99548e333 100644 --- a/ext/asio/asio/ssl/stream_service.hpp +++ b/ext/asio/asio/ssl/stream_service.hpp @@ -1,9 +1,9 @@ // -// stream_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// ssl/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,19 +16,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> #include <boost/noncopyable.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #include "asio/ssl/basic_context.hpp" -#include "asio/ssl/stream_base.hpp" #include "asio/ssl/detail/openssl_stream_service.hpp" +#include "asio/ssl/stream_base.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace ssl { diff --git a/ext/asio/asio/strand.hpp b/ext/asio/asio/strand.hpp index 6b321513dd..5a526f24a3 100644 --- a/ext/asio/asio/strand.hpp +++ b/ext/asio/asio/strand.hpp @@ -2,7 +2,7 @@ // strand.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/io_service.hpp" +#include "asio/detail/config.hpp" #include "asio/detail/strand_service.hpp" #include "asio/detail/wrapped_handler.hpp" +#include "asio/io_service.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { diff --git a/ext/asio/asio/stream_socket_service.hpp b/ext/asio/asio/stream_socket_service.hpp index 1c4935c123..553719ecec 100644 --- a/ext/asio/asio/stream_socket_service.hpp +++ b/ext/asio/asio/stream_socket_service.hpp @@ -2,7 +2,7 @@ // stream_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" @@ -32,6 +26,8 @@ # include "asio/detail/reactive_socket_service.hpp" #endif +#include "asio/detail/push_options.hpp" + namespace asio { /// Default service implementation for a stream socket. diff --git a/ext/asio/asio/streambuf.hpp b/ext/asio/asio/streambuf.hpp index 665155be84..553da3e56b 100644 --- a/ext/asio/asio/streambuf.hpp +++ b/ext/asio/asio/streambuf.hpp @@ -2,7 +2,7 @@ // streambuf.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,12 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/basic_streambuf.hpp" +#include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) +#include "asio/basic_streambuf.hpp" + namespace asio { /// Typedef for the typical usage of basic_streambuf. @@ -30,6 +30,4 @@ typedef basic_streambuf<> streambuf; #endif // !defined(BOOST_NO_IOSTREAM) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_STREAMBUF_HPP diff --git a/ext/asio/asio/system_error.hpp b/ext/asio/asio/system_error.hpp index e704b3fb90..60580a11aa 100644 --- a/ext/asio/asio/system_error.hpp +++ b/ext/asio/asio/system_error.hpp @@ -2,7 +2,7 @@ // system_error.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,18 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> +#include "asio/detail/config.hpp" #include <boost/scoped_ptr.hpp> #include <cerrno> #include <exception> #include <string> -#include "asio/detail/pop_options.hpp" - #include "asio/error_code.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /// The system_error class is used to represent system conditions that diff --git a/ext/asio/asio/thread.hpp b/ext/asio/asio/thread.hpp index 9e578bc598..070483ef55 100644 --- a/ext/asio/asio/thread.hpp +++ b/ext/asio/asio/thread.hpp @@ -2,7 +2,7 @@ // thread.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - +#include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/thread.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /// A simple abstraction for starting threads. diff --git a/ext/asio/asio/time_traits.hpp b/ext/asio/asio/time_traits.hpp index 0371373689..3b2899b166 100644 --- a/ext/asio/asio/time_traits.hpp +++ b/ext/asio/asio/time_traits.hpp @@ -2,7 +2,7 @@ // time_traits.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,14 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - #include "asio/detail/socket_types.hpp" // Must come before posix_time. #include "asio/detail/push_options.hpp" #include <boost/date_time/posix_time/posix_time_types.hpp> #include "asio/detail/pop_options.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /// Time traits suitable for use with the deadline timer. diff --git a/ext/asio/asio/version.hpp b/ext/asio/asio/version.hpp index 198f5086fa..0402d0eb38 100644 --- a/ext/asio/asio/version.hpp +++ b/ext/asio/asio/version.hpp @@ -2,7 +2,7 @@ // version.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,6 +18,6 @@ // ASIO_VERSION % 100 is the sub-minor version // ASIO_VERSION / 100 % 1000 is the minor version // ASIO_VERSION / 100000 is the major version -#define ASIO_VERSION 100405 // 1.4.5 +#define ASIO_VERSION 100408 // 1.4.8 #endif // ASIO_VERSION_HPP diff --git a/ext/asio/asio/windows/basic_handle.hpp b/ext/asio/asio/windows/basic_handle.hpp index 8c2ee60ebb..f87b3db8e2 100644 --- a/ext/asio/asio/windows/basic_handle.hpp +++ b/ext/asio/asio/windows/basic_handle.hpp @@ -1,8 +1,8 @@ // -// basic_handle.hpp -// ~~~~~~~~~~~~~~~~ +// windows/basic_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,15 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) #include "asio/basic_io_object.hpp" -#include "asio/error.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" namespace asio { namespace windows { @@ -222,4 +224,8 @@ protected: #include "asio/detail/pop_options.hpp" +#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + #endif // ASIO_WINDOWS_BASIC_HANDLE_HPP diff --git a/ext/asio/asio/windows/basic_random_access_handle.hpp b/ext/asio/asio/windows/basic_random_access_handle.hpp index 2e6b994e0b..056b175794 100644 --- a/ext/asio/asio/windows/basic_random_access_handle.hpp +++ b/ext/asio/asio/windows/basic_random_access_handle.hpp @@ -1,8 +1,8 @@ // -// basic_random_access_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/basic_random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) +#include <cstddef> +#include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/windows/basic_handle.hpp" #include "asio/windows/random_access_handle_service.hpp" -#include "asio/detail/throw_error.hpp" -#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace windows { @@ -312,9 +310,9 @@ public: } // namespace windows } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP diff --git a/ext/asio/asio/windows/basic_stream_handle.hpp b/ext/asio/asio/windows/basic_stream_handle.hpp index 48e7153da6..28149f4cca 100644 --- a/ext/asio/asio/windows/basic_stream_handle.hpp +++ b/ext/asio/asio/windows/basic_stream_handle.hpp @@ -1,8 +1,8 @@ // -// basic_stream_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// windows/basic_stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) +#include <cstddef> #include "asio/error.hpp" #include "asio/windows/basic_handle.hpp" #include "asio/windows/stream_handle_service.hpp" #include "asio/detail/throw_error.hpp" -#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace windows { @@ -294,9 +292,9 @@ public: } // namespace windows } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP diff --git a/ext/asio/asio/windows/overlapped_ptr.hpp b/ext/asio/asio/windows/overlapped_ptr.hpp index 087170b5a0..8f4d628e0c 100644 --- a/ext/asio/asio/windows/overlapped_ptr.hpp +++ b/ext/asio/asio/windows/overlapped_ptr.hpp @@ -1,8 +1,8 @@ // -// overlapped_ptr.hpp -// ~~~~~~~~~~~~~~~~~~ +// windows/overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,20 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ + || defined(GENERATING_DOCUMENTATION) -#include "asio/io_service.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/win_iocp_overlapped_ptr.hpp" +#include "asio/io_service.hpp" -#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) -# if defined(ASIO_HAS_IOCP) -# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 -# endif // defined(ASIO_HAS_IOCP) -#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) - -#if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace windows { @@ -110,9 +106,9 @@ private: } // namespace windows } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_OVERLAPPED_PTR_HPP diff --git a/ext/asio/asio/windows/random_access_handle.hpp b/ext/asio/asio/windows/random_access_handle.hpp index 6e5dd7b6fc..727b084cab 100644 --- a/ext/asio/asio/windows/random_access_handle.hpp +++ b/ext/asio/asio/windows/random_access_handle.hpp @@ -1,8 +1,8 @@ // -// random_access_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/windows/basic_random_access_handle.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include "asio/windows/basic_random_access_handle.hpp" + namespace asio { namespace windows { @@ -34,6 +34,4 @@ typedef basic_random_access_handle<> random_access_handle; #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP diff --git a/ext/asio/asio/windows/random_access_handle_service.hpp b/ext/asio/asio/windows/random_access_handle_service.hpp index 2e579f82e6..b2c05efc31 100644 --- a/ext/asio/asio/windows/random_access_handle_service.hpp +++ b/ext/asio/asio/windows/random_access_handle_service.hpp @@ -1,8 +1,8 @@ // -// random_access_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/random_access_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,27 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/push_options.hpp" #include <cstddef> #include <boost/config.hpp> #include <boost/cstdint.hpp> -#include "asio/detail/pop_options.hpp" - +#include "asio/detail/win_iocp_handle_service.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" -#include "asio/detail/win_iocp_handle_service.hpp" -#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) -# if defined(ASIO_HAS_IOCP) -# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 -# endif // defined(ASIO_HAS_IOCP) -#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) - -#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace windows { @@ -172,9 +164,9 @@ private: } // namespace windows } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP diff --git a/ext/asio/asio/windows/stream_handle.hpp b/ext/asio/asio/windows/stream_handle.hpp index d55dc3174a..802d157614 100644 --- a/ext/asio/asio/windows/stream_handle.hpp +++ b/ext/asio/asio/windows/stream_handle.hpp @@ -1,8 +1,8 @@ // -// stream_handle.hpp -// ~~~~~~~~~~~~~~~~~~ +// windows/stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/windows/basic_stream_handle.hpp" +#include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include "asio/windows/basic_stream_handle.hpp" + namespace asio { namespace windows { @@ -34,6 +34,4 @@ typedef basic_stream_handle<> stream_handle; #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_STREAM_HANDLE_HPP diff --git a/ext/asio/asio/windows/stream_handle_service.hpp b/ext/asio/asio/windows/stream_handle_service.hpp index 75eff60a6e..816cfe556b 100644 --- a/ext/asio/asio/windows/stream_handle_service.hpp +++ b/ext/asio/asio/windows/stream_handle_service.hpp @@ -1,8 +1,8 @@ // -// stream_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/stream_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,26 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" -#include "asio/detail/push_options.hpp" -#include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" +#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) +#include <cstddef> +#include "asio/detail/win_iocp_handle_service.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/detail/service_base.hpp" -#include "asio/detail/win_iocp_handle_service.hpp" -#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) -# if defined(ASIO_HAS_IOCP) -# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1 -# endif // defined(ASIO_HAS_IOCP) -#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) - -#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) +#include "asio/detail/push_options.hpp" namespace asio { namespace windows { @@ -170,9 +161,9 @@ private: } // namespace windows } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include "asio/detail/pop_options.hpp" - #endif // ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP diff --git a/ext/asio/asio/write.hpp b/ext/asio/asio/write.hpp index 2b188cde4c..bd90ecb069 100644 --- a/ext/asio/asio/write.hpp +++ b/ext/asio/asio/write.hpp @@ -2,7 +2,7 @@ // write.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/basic_streambuf.hpp" +#include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /** @@ -533,8 +530,8 @@ void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, } // namespace asio -#include "asio/impl/write.ipp" - #include "asio/detail/pop_options.hpp" +#include "asio/impl/write.hpp" + #endif // ASIO_WRITE_HPP diff --git a/ext/asio/asio/write_at.hpp b/ext/asio/asio/write_at.hpp index 5690bcfda1..37d0cbb2ea 100644 --- a/ext/asio/asio/write_at.hpp +++ b/ext/asio/asio/write_at.hpp @@ -2,7 +2,7 @@ // write_at.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/push_options.hpp" - -#include "asio/detail/push_options.hpp" +#include "asio/detail/config.hpp" #include <cstddef> -#include <boost/config.hpp> #include <boost/cstdint.hpp> -#include "asio/detail/pop_options.hpp" - -#include "asio/basic_streambuf.hpp" +#include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { /** @@ -556,8 +553,8 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, } // namespace asio -#include "asio/impl/write_at.ipp" - #include "asio/detail/pop_options.hpp" +#include "asio/impl/write_at.hpp" + #endif // ASIO_WRITE_AT_HPP |