[asio] patches for Windows CE

Here is a set of patches which provides Windows CE support for the Boost.Asio library. Please let me know if anything doesn't make sense or seems out of place. boost/asio/detail/win_thread.hpp: WinCE does not define the process.h header. It also does not supply the _beginthreadex function in its CRT, but this can be simulated with Win32 CreateThread. boost/asio/detail/win_tss_ptr.hpp: WinCE does not supply the TLS_OUT_OF_INDEXES constant. The patch defines this to the appropriate value. boost/asio/detail/socket_ops.hpp: - WinCE does not include the errno variable. - WinCE seems to have the annoying behavior that GetLastError() will report an error code even if the API call was successful. As a result, in the error_wrapper() helper function, it is necessary to check for a non-zero return value (indicating an unsuccessful call) before recording an error code from GetLastError(). - WinCE does not include the ANSI versions of WSAStringToAddress and WSAAddressToString (only the wide-char versions) - WinCE does supply getaddrinfo, freeaddrinfo, and getnameinfo functions. boost/asio/detail/socket_types.hpp: WinCE needs to link to WS2.LIB instead of WS2_32.LIB or MSWSOCK.LIB. boost/asio/detail/win_iocp_io_service_fwd.hpp: WinCE does not support I/O completion ports. boost/asio/ip/detail/socket_option.hpp: For whatever reason, on WinCE the IPPROTO_IP/IP_MULTICAST_TTL option seems to specify a 4-byte int instead of a 1-byte int. boost/asio/socket_base.hpp: boost/asio/ip/unicast.hpp: boost/asio/ip/multicast.hpp: libs/asio/test/socket_base.cpp: libs/asio/test/ip/unicast.cpp: libs/asio/test/ip/multicast.cpp: WinCE does not support the SOL_SOCKET/SO_DEBUG, SOL_SOCKET/SO_DONTROUTE, IPPROTO_IP/IP_TTL, or IPPROTO_IP/IP_MULTICAST_LOOP options. The patches therefore do not define the socket_base::debug, socket_base::do_not_route, unicast::hops or multicast::enable_loopback types for WinCE. It was not clear whether this was the preferred method for handling unsupported options or whether the option types should still be defined and the related tests adjusted to show the options are expected to fail on WinCE. In addition, WinCE does not seem to support changing the receive buffer size with the SO_RCVBUF option, although you can get the receive buffer size with this option. The socket_base::receive_buffer_size tests were adjusted to reflect this behavior. Again, let me know if there are questions or comments. Thanks, -Dave Index: win_thread.hpp =================================================================== --- win_thread.hpp (revision 40703) +++ win_thread.hpp (working copy) @@ -31,13 +31,58 @@ #include <boost/asio/detail/push_options.hpp> #include <boost/throw_exception.hpp> #include <memory> + +#ifndef BOOST_NO_THREADEX #include <process.h> +#endif + #include <boost/asio/detail/pop_options.hpp> namespace boost { namespace asio { namespace detail { +#if defined(BOOST_NO_THREADEX) +// Windows CE doesn't define _beginthreadex + +struct ThreadProxyData +{ + typedef unsigned (__stdcall* func)(void*); + func start_address_; + void* arglist_; + ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {} +}; + +DWORD WINAPI ThreadProxy(LPVOID args) +{ + ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args); + DWORD ret=data->start_address_(data->arglist_); + delete data; + return ret; +} + +inline unsigned start_thread(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), +void* arglist, unsigned initflag,unsigned* thrdaddr) +{ + DWORD threadID; + HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy, + new ThreadProxyData(start_address,arglist),initflag,&threadID); + if (hthread!=0) + *thrdaddr=threadID; + return reinterpret_cast<unsigned>(hthread); +} +#else + +inline unsigned start_thread(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), +void* arglist, unsigned initflag,unsigned* thrdaddr) +{ + return _beginthreadex(security, stack_size, start_address, arglist, initflag, thrdaddr); +} + + +#endif + + unsigned int __stdcall win_thread_function(void* arg); class win_thread @@ -50,7 +95,7 @@ { std::auto_ptr<func_base> arg(new func<Function>(f)); unsigned int thread_id = 0; - thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0, + thread_ = reinterpret_cast<HANDLE>(start_thread(0, 0, win_thread_function, arg.get(), 0, &thread_id)); if (!thread_) { Index: win_tss_ptr.hpp =================================================================== --- win_tss_ptr.hpp (revision 40703) +++ win_tss_ptr.hpp (working copy) @@ -32,6 +32,11 @@ #include <boost/throw_exception.hpp> #include <boost/asio/detail/pop_options.hpp> +#if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES) +#define TLS_OUT_OF_INDEXES 0xFFFFFFFF +#endif + + namespace boost { namespace asio { namespace detail { Index: socket_ops.hpp =================================================================== --- socket_ops.hpp (revision 40703) +++ socket_ops.hpp (working copy) @@ -49,7 +49,9 @@ inline void clear_error(boost::system::error_code& ec) { +#if !defined(UNDER_CE) errno = 0; +#endif #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) WSASetLastError(0); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -60,7 +62,13 @@ inline ReturnType error_wrapper(ReturnType return_value, boost::system::error_code& ec) { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#if defined(UNDER_CE) + if (return_value) + { + ec = boost::system::error_code(WSAGetLastError(), + boost::asio::error::system_category); + } +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) ec = boost::system::error_code(WSAGetLastError(), boost::asio::error::system_category); #else @@ -291,7 +299,8 @@ 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, addrlen, 0, 0), ec); + send_buf_count, &bytes_transferred, flags, addr, + static_cast<int>(addrlen), 0, 0), ec); if (result != 0) return -1; return bytes_transferred; @@ -635,10 +644,20 @@ } DWORD string_length = static_cast<DWORD>(length); + +#if !defined(BOOST_NO_ANSI_APIS) int result = error_wrapper(::WSAAddressToStringA( reinterpret_cast<sockaddr*>(&address), address_length, 0, dest, &string_length), ec); +#else + LPWSTR string_buffer = (LPWSTR)_alloca( length * 2 ); + int result = error_wrapper(::WSAAddressToStringW( + reinterpret_cast<sockaddr*>(&address), + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, NULL, NULL); +#endif + // Windows may set error code on success. if (result != socket_error_retval) clear_error(ec); @@ -681,10 +700,21 @@ sockaddr_storage_type address; int address_length = sizeof(sockaddr_storage_type); + +#if !defined(BOOST_NO_ANSI_APIS) int result = error_wrapper(::WSAStringToAddressA( const_cast<char*>(src), af, 0, reinterpret_cast<sockaddr*>(&address), &address_length), ec); +#else + 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, + reinterpret_cast<sockaddr*>(&address), + &address_length), ec); +#endif if (af == AF_INET) { @@ -1616,7 +1646,7 @@ { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# 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); @@ -1647,7 +1677,7 @@ inline void freeaddrinfo(addrinfo_type* ai) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. ::freeaddrinfo(ai); # else @@ -1675,7 +1705,7 @@ char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# 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, addrlen, host, static_cast<DWORD>(hostlen), Index: socket_types.hpp =================================================================== --- socket_types.hpp (revision 40703) +++ socket_types.hpp (working copy) @@ -80,7 +80,9 @@ # undef BOOST_ASIO_WSPIAPI_H_DEFINED # endif // defined(BOOST_ASIO_WSPIAPI_H_DEFINED) # if !defined(BOOST_ASIO_NO_DEFAULT_LINKED_LIBS) -# if defined(_MSC_VER) || defined(__BORLANDC__) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) # pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "mswsock.lib") # endif // defined(_MSC_VER) || defined(__BORLANDC__) Index: win_iocp_io_service_fwd.hpp =================================================================== --- win_iocp_io_service_fwd.hpp (revision 40703) +++ win_iocp_io_service_fwd.hpp (working copy) @@ -26,7 +26,7 @@ // This service is only supported on Win32 (NT4 and later). #if !defined(BOOST_ASIO_DISABLE_IOCP) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) && !defined(UNDER_CE) // Define this to indicate that IOCP is supported on the target platform. #define BOOST_ASIO_HAS_IOCP 1 Index: socket_option.hpp =================================================================== --- socket_option.hpp (revision 40703) +++ socket_option.hpp (working copy) @@ -354,7 +354,11 @@ } private: +#if defined(UNDER_CE) + unsigned long ipv4_value_; +#else unsigned char ipv4_value_; +#endif int ipv6_value_; }; Index: multicast.cpp =================================================================== --- multicast.cpp (revision 40703) +++ multicast.cpp (working copy) @@ -77,6 +77,8 @@ hops1 = 1; static_cast<int>(hops1.value()); +#if !defined(UNDER_CE) + // enable_loopback class. ip::multicast::enable_loopback enable_loopback1(true); @@ -87,6 +89,9 @@ static_cast<bool>(enable_loopback1); static_cast<bool>(!enable_loopback1); static_cast<bool>(enable_loopback1.value()); + +#endif // !defined(UNDER_CE) + } catch (std::exception&) { @@ -241,6 +246,8 @@ BOOST_CHECK(hops4.value() == 0); } +#if !defined(UNDER_CE) + // enable_loopback class. if (have_v4) @@ -304,6 +311,8 @@ BOOST_CHECK(!static_cast<bool>(enable_loopback4)); BOOST_CHECK(!enable_loopback4); } + +#endif // !defined(UNDER_CE) } } // namespace ip_multicast_runtime Index: multicast.hpp =================================================================== --- multicast.hpp (revision 40703) +++ multicast.hpp (working copy) @@ -167,7 +167,7 @@ */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined enable_loopback; -#else +#elif !defined(UNDER_CE) typedef boost::asio::ip::detail::socket_option::multicast_enable_loopback< IPPROTO_IP, IP_MULTICAST_LOOP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP> enable_loopback; Index: unicast.hpp =================================================================== --- unicast.hpp (revision 40703) +++ unicast.hpp (working copy) @@ -57,7 +57,7 @@ */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined hops; -#else +#elif !defined(UNDER_CE) typedef boost::asio::ip::detail::socket_option::unicast_hops< IPPROTO_IP, IP_TTL, IPPROTO_IPV6, IPV6_UNICAST_HOPS> hops; #endif Index: unicast.cpp =================================================================== --- unicast.cpp (revision 40703) +++ unicast.cpp (working copy) @@ -38,6 +38,8 @@ io_service ios; ip::udp::socket sock(ios); +#if !defined(UNDER_CE) + // hops class. ip::unicast::hops hops1(1024); @@ -46,6 +48,8 @@ sock.get_option(hops2); hops1 = 1; static_cast<int>(hops1.value()); + +#endif // !defined(UNDER_CE) } catch (std::exception&) { @@ -85,6 +89,9 @@ BOOST_CHECK(have_v4 || have_v6); + +#if !defined(UNDER_CE) + // hops class. if (have_v4) @@ -132,6 +139,9 @@ BOOST_CHECK(!ec); BOOST_CHECK(hops4.value() == 255); } + +#endif // !defined(UNDER_CE) + } } // namespace ip_unicast_runtime Index: socket_base.cpp =================================================================== --- socket_base.cpp (revision 40703) +++ socket_base.cpp (working copy) @@ -62,6 +62,8 @@ static_cast<bool>(!broadcast1); static_cast<bool>(broadcast1.value()); +#if !defined(UNDER_CE) + // debug class. socket_base::debug debug1(true); @@ -84,6 +86,8 @@ static_cast<bool>(!do_not_route1); static_cast<bool>(do_not_route1.value()); +#endif // !defined(UNDER_CE) + // keep_alive class. socket_base::keep_alive keep_alive1(true); @@ -233,6 +237,8 @@ BOOST_CHECK(!static_cast<bool>(broadcast4)); BOOST_CHECK(!broadcast4); +#if !defined(UNDER_CE) + // debug class. socket_base::debug debug1(true); @@ -316,6 +322,8 @@ BOOST_CHECK(!static_cast<bool>(do_not_route4)); BOOST_CHECK(!do_not_route4); +#endif // !defined(UNDER_CE) + // keep_alive class. socket_base::keep_alive keep_alive1(true); @@ -415,22 +423,38 @@ socket_base::receive_buffer_size receive_buffer_size1(4096); BOOST_CHECK(receive_buffer_size1.value() == 4096); tcp_sock.set_option(receive_buffer_size1, ec); +#if defined(UNDER_CE) + BOOST_CHECK(!!ec); // Can only get value on Windows CE +#else BOOST_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif socket_base::receive_buffer_size receive_buffer_size2; tcp_sock.get_option(receive_buffer_size2, ec); +#if defined(UNDER_CE) + BOOST_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); // Can only get value on Windows CE +#else BOOST_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); - BOOST_CHECK(receive_buffer_size2.value() == 4096); + BOOST_CHECK_EQUAL(receive_buffer_size2.value(), 4096); +#endif socket_base::receive_buffer_size receive_buffer_size3(16384); BOOST_CHECK(receive_buffer_size3.value() == 16384); tcp_sock.set_option(receive_buffer_size3, ec); +#if defined(UNDER_CE) + BOOST_CHECK(!!ec); // Can only get value on Windows CE +#else BOOST_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif socket_base::receive_buffer_size receive_buffer_size4; tcp_sock.get_option(receive_buffer_size4, ec); +#if defined(UNDER_CE) + BOOST_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); // Can only get value on Windows CE +#else BOOST_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); - BOOST_CHECK(receive_buffer_size4.value() == 16384); + BOOST_CHECK_EQUAL(receive_buffer_size4.value(), 16384); +#endif // receive_low_watermark class. Index: socket_base.hpp =================================================================== --- socket_base.hpp (revision 40703) +++ socket_base.hpp (working copy) @@ -136,7 +136,7 @@ */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined debug; -#else +#elif !defined(UNDER_CE) typedef boost::asio::detail::socket_option::boolean< SOL_SOCKET, SO_DEBUG> debug; #endif @@ -169,7 +169,7 @@ */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined do_not_route; -#else +#elif !defined(UNDER_CE) typedef boost::asio::detail::socket_option::boolean< SOL_SOCKET, SO_DONTROUTE> do_not_route; #endif

On Sat, 03 Nov 2007 13:12:50 -0600, "David Deakins" <ddeakins@veeco.com> said:
Here is a set of patches which provides Windows CE support for the Boost.Asio library. Please let me know if anything doesn't make sense or seems out of place.
Thanks for the patches. I've made some changes based on them, although in some cases I've taken a different approach. Please let me know if there are problems with what I have done.
boost/asio/socket_base.hpp: boost/asio/ip/unicast.hpp: boost/asio/ip/multicast.hpp: libs/asio/test/socket_base.cpp: libs/asio/test/ip/unicast.cpp: libs/asio/test/ip/multicast.cpp: WinCE does not support the SOL_SOCKET/SO_DEBUG, SOL_SOCKET/SO_DONTROUTE, IPPROTO_IP/IP_TTL, or IPPROTO_IP/IP_MULTICAST_LOOP options. The patches therefore do not define the socket_base::debug, socket_base::do_not_route, unicast::hops or multicast::enable_loopback types for WinCE. It was not clear whether this was the preferred method for handling unsupported options or whether the option types should still be defined and the related tests adjusted to show the options are expected to fail on WinCE. In addition, WinCE does not seem to support changing the receive buffer size with the SO_RCVBUF option, although you can get the receive buffer size with this option. The socket_base::receive_buffer_size tests were adjusted to reflect this behavior.
Does WinCE not have the #defines for these options? Or is it a runtime failure? (And if so, what error gets reported?) Cheers, Chris

Christopher Kohlhoff wrote:
On Sat, 03 Nov 2007 13:12:50 -0600, "David Deakins" <ddeakins@veeco.com> said:
Here is a set of patches which provides Windows CE support for the Boost.Asio library. Please let me know if anything doesn't make sense or seems out of place.
Thanks for the patches. I've made some changes based on them, although in some cases I've taken a different approach. Please let me know if there are problems with what I have done.
Your implementations look fine except that in boost/asio/detail/socket_ops.hpp, in function clear_error (), the 'errno = 0;' line should have an #ifndef UNDER_CE/#endif around it.
boost/asio/socket_base.hpp: boost/asio/ip/unicast.hpp: boost/asio/ip/multicast.hpp: libs/asio/test/socket_base.cpp: libs/asio/test/ip/unicast.cpp: libs/asio/test/ip/multicast.cpp: WinCE does not support the SOL_SOCKET/SO_DEBUG, SOL_SOCKET/SO_DONTROUTE, IPPROTO_IP/IP_TTL, or IPPROTO_IP/IP_MULTICAST_LOOP options.
Does WinCE not have the #defines for these options? Or is it a runtime failure? (And if so, what error gets reported?)
It does have the defines for these options; the failure is a run-time error. GetLastError() returns 10042/WSAENOPROTOOPT. Thanks, -Dave
participants (3)
-
Christopher Kohlhoff
-
David Deakins
-
Michael Marcin