Boost logo

Boost :

From: David Deakins (ddeakins_at_[hidden])
Date: 2007-11-03 15:12:50


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk