diff --git a/example/local/Jamfile b/example/local/Jamfile index 0d1d6fa6..a278b75b 100644 --- a/example/local/Jamfile +++ b/example/local/Jamfile @@ -33,6 +33,18 @@ exe connect_pair $(SOCKET_LIBS) ; +exe iostream_client + : @boost/libs/system/build/boost_system + iostream_client.cpp + : $(BOOST_ROOT) + ../../../.. + BOOST_ALL_NO_LIB=1 + multi + <*>ws2_32 + <*>mswsock + $(SOCKET_LIBS) + ; + exe stream_client : @boost/libs/system/build/boost_system stream_client.cpp diff --git a/example/local/Jamfile.v2 b/example/local/Jamfile.v2 index 170977cb..0258e73c 100644 --- a/example/local/Jamfile.v2 +++ b/example/local/Jamfile.v2 @@ -38,6 +38,21 @@ exe connect_pair HPUX:ipv6 ; +exe iostream_client + : iostream_client.cpp + /boost/system//boost_system + : BOOST_ALL_NO_LIB=1 + multi + SOLARIS:socket + SOLARIS:nsl + NT:_WIN32_WINNT=0x0501 + NT,gcc:ws2_32 + NT,gcc:mswsock + NT,gcc-cygwin:__USE_W32_SOCKETS + HPUX,gcc:_XOPEN_SOURCE_EXTENDED + HPUX:ipv6 + ; + exe stream_client : stream_client.cpp /boost/system//boost_system diff --git a/example/local/iostream_client.cpp b/example/local/iostream_client.cpp new file mode 100644 index 00000000..a2fdd5af --- /dev/null +++ b/example/local/iostream_client.cpp @@ -0,0 +1,59 @@ +// +// stream_client.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: iostream_client \n"; + return 1; + } + + boost::asio::io_service io_service; + + stream_protocol::endpoint ep(argv[1]); + stream_protocol::iostream s(ep); + + using namespace std; // For strlen. + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t length = strlen(request); + s << request; + + char reply[max_length]; + s.read(reply, length); + std::cout << "Reply is: "; + std::cout.write(reply, length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/include/boost/asio/basic_socket_streambuf.hpp b/include/boost/asio/basic_socket_streambuf.hpp index da7337c3..9977be68 100644 --- a/include/boost/asio/basic_socket_streambuf.hpp +++ b/include/boost/asio/basic_socket_streambuf.hpp @@ -248,7 +248,8 @@ private: setp(put_buffer_.begin(), put_buffer_.end()); } - void resolve_and_connect(const typename Protocol::resolver_query& query, + template + void resolve_and_connect(const ResolverQuery& query, boost::system::error_code& ec) { typedef typename Protocol::resolver resolver_type; diff --git a/include/boost/asio/basic_streambuf.hpp b/include/boost/asio/basic_streambuf.hpp index e9eafa81..a151f805 100644 --- a/include/boost/asio/basic_streambuf.hpp +++ b/include/boost/asio/basic_streambuf.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -96,6 +97,7 @@ public: if (pptr() + n > epptr()) n = epptr() - pptr(); pbump(static_cast(n)); + setg(eback(), gptr(), pptr()); } /// Move the start of the get area by the specified number of characters. @@ -151,7 +153,6 @@ protected: { // Get current stream positions as offsets. std::size_t gnext = gptr() - &buffer_[0]; - std::size_t gend = egptr() - &buffer_[0]; std::size_t pnext = pptr() - &buffer_[0]; std::size_t pend = epptr() - &buffer_[0]; @@ -164,9 +165,8 @@ protected: // Shift existing contents of get area to start of buffer. if (gnext > 0) { - std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend); - gend -= gnext; pnext -= gnext; + std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext); } // Ensure buffer is large enough to hold at least the specified size. @@ -174,7 +174,8 @@ protected: { if (n <= max_size_ && pnext <= max_size_ - n) { - buffer_.resize((std::max)(pnext + n, 1)); + pend = pnext + n; + buffer_.resize((std::max)(pend, 1)); } else { @@ -183,8 +184,8 @@ protected: } // Update stream positions. - setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend); - setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n); + setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext); + setp(&buffer_[0] + pnext, &buffer_[0] + pend); } private: diff --git a/include/boost/asio/detail/deadline_timer_service.hpp b/include/boost/asio/detail/deadline_timer_service.hpp index 76fd2d0f..16206a74 100644 --- a/include/boost/asio/detail/deadline_timer_service.hpp +++ b/include/boost/asio/detail/deadline_timer_service.hpp @@ -64,6 +64,7 @@ public: deadline_timer_service >(io_service), scheduler_(boost::asio::use_service(io_service)) { + scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); } diff --git a/include/boost/asio/detail/dev_poll_reactor.hpp b/include/boost/asio/detail/dev_poll_reactor.hpp index 2d233194..87390858 100644 --- a/include/boost/asio/detail/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/dev_poll_reactor.hpp @@ -123,6 +123,17 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > + task_io_service_type; + use_service(this->get_io_service()).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&) diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index c54423bb..2770c6a5 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -124,6 +124,16 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + // Register a socket with the reactor. Returns 0 on success, system error // code on failure. int register_descriptor(socket_type descriptor, diff --git a/include/boost/asio/detail/kqueue_reactor.hpp b/include/boost/asio/detail/kqueue_reactor.hpp index a6a671a3..179b7d49 100644 --- a/include/boost/asio/detail/kqueue_reactor.hpp +++ b/include/boost/asio/detail/kqueue_reactor.hpp @@ -132,6 +132,16 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).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& descriptor_data) diff --git a/include/boost/asio/detail/null_thread.hpp b/include/boost/asio/detail/null_thread.hpp index 507904ba..5aed2112 100644 --- a/include/boost/asio/detail/null_thread.hpp +++ b/include/boost/asio/detail/null_thread.hpp @@ -39,12 +39,9 @@ class null_thread : private noncopyable { public: - // The purpose of the thread. - enum purpose { internal, external }; - // Constructor. template - null_thread(Function f, purpose = internal) + null_thread(Function f) { boost::system::system_error e( boost::asio::error::operation_not_supported, "thread"); diff --git a/include/boost/asio/detail/posix_thread.hpp b/include/boost/asio/detail/posix_thread.hpp index 6dbc3b8f..1e386184 100644 --- a/include/boost/asio/detail/posix_thread.hpp +++ b/include/boost/asio/detail/posix_thread.hpp @@ -43,12 +43,9 @@ class posix_thread : private noncopyable { public: - // The purpose of the thread. - enum purpose { internal, external }; - // Constructor. template - posix_thread(Function f, purpose = internal) + posix_thread(Function f) : joined_(false) { std::auto_ptr arg(new func(f)); diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index 5334f21b..ad828aa2 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -82,6 +82,7 @@ public: reactive_descriptor_service >(io_service), reactor_(boost::asio::use_service(io_service)) { + reactor_.init_task(); } // Destroy all user-defined handler objects owned by the service. diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 16727460..982cc645 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -110,6 +110,7 @@ public: reactive_socket_service >(io_service), reactor_(boost::asio::use_service(io_service)) { + reactor_.init_task(); } // Destroy all user-defined handler objects owned by the service. diff --git a/include/boost/asio/detail/select_reactor.hpp b/include/boost/asio/detail/select_reactor.hpp index 83787535..77caf546 100644 --- a/include/boost/asio/detail/select_reactor.hpp +++ b/include/boost/asio/detail/select_reactor.hpp @@ -111,6 +111,16 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).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&) diff --git a/include/boost/asio/detail/service_registry.hpp b/include/boost/asio/detail/service_registry.hpp index d1b1c04e..6b25663f 100644 --- a/include/boost/asio/detail/service_registry.hpp +++ b/include/boost/asio/detail/service_registry.hpp @@ -37,6 +37,21 @@ namespace boost { namespace asio { namespace detail { +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +#endif // defined(__GNUC__) + +template +class typeid_wrapper {}; + +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +#endif // defined(__GNUC__) + class service_registry : private noncopyable { @@ -169,7 +184,7 @@ private: void init_service_id(boost::asio::io_service::service& service, const boost::asio::detail::service_id& /*id*/) { - service.type_info_ = &typeid(Service); + service.type_info_ = &typeid(typeid_wrapper); service.id_ = 0; } #endif // !defined(BOOST_ASIO_NO_TYPEID) @@ -189,7 +204,8 @@ private: const boost::asio::io_service::service& service, const boost::asio::detail::service_id& /*id*/) { - return service.type_info_ != 0 && *service.type_info_ == typeid(Service); + return service.type_info_ != 0 + && *service.type_info_ == typeid(typeid_wrapper); } #endif // !defined(BOOST_ASIO_NO_TYPEID) diff --git a/include/boost/asio/detail/task_io_service.hpp b/include/boost/asio/detail/task_io_service.hpp index 546a6b21..eeae6b0b 100644 --- a/include/boost/asio/detail/task_io_service.hpp +++ b/include/boost/asio/detail/task_io_service.hpp @@ -44,14 +44,13 @@ public: task_io_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base >(io_service), mutex_(), - task_(use_service(io_service)), + task_(0), task_interrupted_(true), outstanding_work_(0), stopped_(false), shutdown_(false), first_idle_thread_(0) { - handler_queue_.push(&task_handler_); } void init(size_t /*concurrency_hint*/) @@ -74,8 +73,20 @@ public: h->destroy(); } - // Reset handler queue to initial state. - handler_queue_.push(&task_handler_); + // Reset to initial state. + task_ = 0; + } + + // Initialise the task, if required. + void init_task() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + handler_queue_.push(&task_handler_); + interrupt_one_idle_thread(lock); + } } // Run the event loop until interrupted or no more work. @@ -194,10 +205,10 @@ public: // Wake up a thread to execute the handler. if (!interrupt_one_idle_thread(lock)) { - if (!task_interrupted_) + if (!task_interrupted_ && task_) { task_interrupted_ = true; - task_.interrupt(); + task_->interrupt(); } } } @@ -246,7 +257,7 @@ private: // Run the task. May throw an exception. Only block if the handler // queue is empty and we have an idle_thread_info object, otherwise // we want to return as soon as possible. - task_.run(!more_handlers && !polling); + task_->run(!more_handlers && !polling); } else { @@ -285,10 +296,10 @@ private: { stopped_ = true; interrupt_all_idle_threads(lock); - if (!task_interrupted_) + if (!task_interrupted_ && task_) { task_interrupted_ = true; - task_.interrupt(); + task_->interrupt(); } } @@ -376,7 +387,7 @@ private: boost::asio::detail::mutex mutex_; // The task to be run by this service. - Task& task_; + Task* task_; // Handler object to represent the position of the task in the queue. class task_handler diff --git a/include/boost/asio/detail/task_io_service_2lock.hpp b/include/boost/asio/detail/task_io_service_2lock.hpp index 6082b4f4..bd406cbe 100644 --- a/include/boost/asio/detail/task_io_service_2lock.hpp +++ b/include/boost/asio/detail/task_io_service_2lock.hpp @@ -50,7 +50,7 @@ public: : boost::asio::detail::service_base >(io_service), front_mutex_(), back_mutex_(), - task_(use_service(io_service)), + task_(&use_service(io_service)), outstanding_work_(0), front_stopped_(false), back_stopped_(false), @@ -58,7 +58,6 @@ public: back_first_idle_thread_(0), back_task_thread_(0) { - handler_queue_.push(&task_handler_); } void init(size_t /*concurrency_hint*/) @@ -77,8 +76,20 @@ public: if (h != &task_handler_) h->destroy(); - // Reset handler queue to initial state. - handler_queue_.push(&task_handler_); + // Reset to initial state. + task_ = 0; + } + + // Initialise the task, if required. + void init_task() + { + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + if (!back_shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + handler_queue_.push(&task_handler_); + interrupt_one_idle_thread(back_lock); + } } // Run the event loop until interrupted or no more work. @@ -287,7 +298,7 @@ private: // queue is empty and we're not polling, otherwise we want to return // as soon as possible. task_has_run = true; - task_.run(!more_handlers && !polling); + task_->run(!more_handlers && !polling); } else { @@ -342,10 +353,10 @@ private: idle_thread->next = 0; idle_thread->wakeup_event.signal(back_lock); } - else if (back_task_thread_) + else if (back_task_thread_ && task_) { back_task_thread_ = 0; - task_.interrupt(); + task_->interrupt(); } } @@ -361,10 +372,10 @@ private: idle_thread->wakeup_event.signal(back_lock); } - if (back_task_thread_) + if (back_task_thread_ && task_) { back_task_thread_ = 0; - task_.interrupt(); + task_->interrupt(); } } @@ -415,7 +426,7 @@ private: boost::asio::detail::mutex back_mutex_; // The task to be run by this service. - Task& task_; + Task* task_; // Handler object to represent the position of the task in the queue. class task_handler diff --git a/include/boost/asio/detail/win_iocp_io_service.hpp b/include/boost/asio/detail/win_iocp_io_service.hpp index d992cd0e..c36dd52e 100644 --- a/include/boost/asio/detail/win_iocp_io_service.hpp +++ b/include/boost/asio/detail/win_iocp_io_service.hpp @@ -149,6 +149,11 @@ public: timer_queues_.clear(); } + // Initialise the task. Nothing to do here. + void init_task() + { + } + // Register a handle with the IO completion port. boost::system::error_code register_handle( HANDLE handle, boost::system::error_code& ec) diff --git a/include/boost/asio/detail/win_thread.hpp b/include/boost/asio/detail/win_thread.hpp index fe95b3fb..c8058d80 100644 --- a/include/boost/asio/detail/win_thread.hpp +++ b/include/boost/asio/detail/win_thread.hpp @@ -40,50 +40,67 @@ namespace detail { unsigned int __stdcall win_thread_function(void* arg); -class win_thread - : private noncopyable +#if (WINVER < 0x0500) +void __stdcall apc_function(ULONG data); +#else +void __stdcall apc_function(ULONG_PTR data); +#endif + +template +class win_thread_base { public: - // The purpose of the thread. - enum purpose { internal, external }; + static bool terminate_threads() + { + return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0; + } + static void set_terminate_threads(bool b) + { + ::InterlockedExchange(&terminate_threads_, b ? 1 : 0); + } + +private: + static long terminate_threads_; +}; + +template +long win_thread_base::terminate_threads_ = 0; + +class win_thread + : private noncopyable, + public win_thread_base +{ +public: // Constructor. template - win_thread(Function f, purpose p = internal) + win_thread(Function f) : exit_event_(0) { std::auto_ptr arg(new func(f)); ::HANDLE entry_event = 0; - if (p == internal) + arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); + if (!entry_event) { - arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); - if (!entry_event) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::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); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread.exit_event"); - boost::throw_exception(e); - } + DWORD last_error = ::GetLastError(); + boost::system::system_error e( + boost::system::error_code(last_error, + boost::asio::error::get_system_category()), + "thread.entry_event"); + boost::throw_exception(e); } - else + + arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); + if (!exit_event_) { - arg->entry_event_ = 0; - arg->exit_event_ = 0; + DWORD last_error = ::GetLastError(); + ::CloseHandle(entry_event); + boost::system::system_error e( + boost::system::error_code(last_error, + boost::asio::error::get_system_category()), + "thread.exit_event"); + boost::throw_exception(e); } unsigned int thread_id = 0; @@ -123,14 +140,15 @@ public: // Wait for the thread to exit. void join() { - if (exit_event_) + ::WaitForSingleObject(exit_event_, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) { - ::WaitForSingleObject(exit_event_, INFINITE); - ::CloseHandle(exit_event_); ::TerminateThread(thread_, 0); } else { + ::QueueUserAPC(apc_function, thread_, 0); ::WaitForSingleObject(thread_, INFINITE); } } @@ -138,6 +156,12 @@ public: private: friend unsigned int __stdcall win_thread_function(void* arg); +#if (WINVER < 0x0500) + friend void __stdcall apc_function(ULONG); +#else + friend void __stdcall apc_function(ULONG_PTR); +#endif + class func_base { public: @@ -175,21 +199,30 @@ inline unsigned int __stdcall win_thread_function(void* arg) std::auto_ptr func( static_cast(arg)); - if (func->entry_event_) - ::SetEvent(func->entry_event_); + ::SetEvent(func->entry_event_); func->run(); - if (HANDLE exit_event = func->exit_event_) - { - func.reset(); - ::SetEvent(exit_event); - ::Sleep(INFINITE); - } + // 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 (WINVER < 0x0500) +inline void __stdcall apc_function(ULONG) {} +#else +inline void __stdcall apc_function(ULONG_PTR) {} +#endif + } // namespace detail } // namespace asio } // namespace boost diff --git a/include/boost/asio/detail/wince_thread.hpp b/include/boost/asio/detail/wince_thread.hpp index 6b624872..7b24ec25 100644 --- a/include/boost/asio/detail/wince_thread.hpp +++ b/include/boost/asio/detail/wince_thread.hpp @@ -43,12 +43,9 @@ class wince_thread : private noncopyable { public: - // The purpose of the thread. - enum purpose { internal, external }; - // Constructor. template - wince_thread(Function f, purpose = internal) + wince_thread(Function f) { std::auto_ptr arg(new func(f)); DWORD thread_id = 0; diff --git a/include/boost/asio/ip/address_v4.hpp b/include/boost/asio/ip/address_v4.hpp index 9bea8cbc..357edfae 100644 --- a/include/boost/asio/ip/address_v4.hpp +++ b/include/boost/asio/ip/address_v4.hpp @@ -18,7 +18,9 @@ #include #include +#include #include +#include #include #include #include @@ -56,6 +58,15 @@ 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); } @@ -63,6 +74,14 @@ public: /// 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 = boost::asio::detail::socket_ops::host_to_network_long(addr); } diff --git a/include/boost/asio/ip/address_v6.hpp b/include/boost/asio/ip/address_v6.hpp index 89f2ee3f..5f5f0927 100644 --- a/include/boost/asio/ip/address_v6.hpp +++ b/include/boost/asio/ip/address_v6.hpp @@ -63,6 +63,17 @@ public: 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); } @@ -166,7 +177,11 @@ public: address_v4 to_v4() const { if (!is_v4_mapped() && !is_v4_compatible()) - throw std::bad_cast(); + { + 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); diff --git a/include/boost/asio/read_until.hpp b/include/boost/asio/read_until.hpp index 7695cd09..6144e60c 100644 --- a/include/boost/asio/read_until.hpp +++ b/include/boost/asio/read_until.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,20 @@ namespace asio { namespace detail { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) + template + struct has_result_type + { + template struct inner + { + struct big { char a[100]; }; + static big helper(U, ...); + static char helper(U, typename U::result_type* = 0); + }; + static const T& ref(); + enum { value = (sizeof((inner::helper)((ref)())) == 1) }; + }; +#else // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) template struct has_result_type { @@ -44,6 +59,7 @@ namespace detail static const T& ref(); enum { value = (sizeof((helper)((ref)())) == 1) }; }; +#endif // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) } // namespace detail /// Type trait used to determine whether a type can be used as a match condition