Make it possible to build curl for Windows CE using the CeGCC toolchain.
With both CMake and autotools, including tests and examples, also in CI.
The build configuration is the default one with Schannel enabled. No
3rd-party dependencies have been tested.
Also revive old code to make Schannel build with Windows CE, including
certificate verification.
Builds have been throughougly tested. But, I've made no functional tests
for this PR. Some parts (esp. file operations, like truncate and seek)
are stubbed out and likely broken as a result. Test servers build, but
they do not work on Windows CE. This patch substitutes `fstat()` calls
with `stat()`, which operate on filenames, not file handles. This may or
may not work and/or may not be secure.
About CeGCC: I used the latest available macOS binary build v0.59.1
r1397 from 2009, in native `mingw32ce` build mode. CeGCC is in effect
MinGW + GCC 4.4.0 + old/classic-mingw Windows headers. It targets
Windows CE v3.0 according to its `_WIN32_WCE` value. It means this PR
restores portions of old/classic-mingw support. It makes the Windows CE
codepath compatible with GCC 4.4.0. It also adds workaround for CMake,
which cannot identify and configure this toolchain out of the box.
Notes:
- CMake doesn't recognize CeGCC/mingw32ce, necessitating tricks as seen
with Amiga and MS-DOS.
- CMake doesn't set `MINGW` for mingw32ce. Set it and `MINGW32CE`
manually as a helper variable, in addition to `WINCE` which CMake sets
based on `CMAKE_SYSTEM_NAME`.
- CMake fails to create an implib for `libcurl.dll`, due to not
recognizing the platform as a Windowsy one. This patch adds the
necessary workaround to make it work.
- headers shipping with CeGCC miss some things curl needs for Schannel
support. Fixed by restoring and renovating code previously deleted
old-mingw code.
- it's sometime non-trivial to figure out if a fallout is WinCE,
mingw32ce, old-mingw, or GCC version-specific.
- WinCE is always Unicode. With exceptions: no `wmain`,
`GetProcAddress()`.
- `_fileno()` is said to convert from `FILE *` to `void *` which is
a Win32 file `HANDLE`. (This patch doesn't use this, but with further
effort it probably could be.)
https://stackoverflow.com/questions/3989545/how-do-i-get-the-file-handle-from-the-fopen-file-structure
- WinCE has no signals, current directory, stdio/CRT file handles, no
`_get_osfhandle()`, no `errno`, no `errno.h`. Some of this stuff is
standard C89, yet missing from this platform. Microsoft expects
Windows CE apps to use Win32 file API and `FILE *` exclusively.
- revived CeGCC here (not tested for this PR):
https://building.enlyze.com/posts/a-new-windows-ce-x86-compiler-in-2024/
On `UNDER_CE` vs. `_WIN32_WCE`: (This patch settled on `UNDER_CE`)
- A custom VS2008 WinCE toolchain does not set any of these.
The compiler binaries don't contain these strings, and has no compiler
option for targeting WinCE, hinting that a vanilla toolchain isn't
setting any of them either.
- `UNDER_CE` is automatically defined by the CeGCC compiler.
https://cegcc.sourceforge.net/docs/details.html
- `UNDER_CE` is similar to `_WIN32`, except it's not set automatically
by all compilers. It's not supposed to have any value, like a version.
(Though e.g. OpenSSL sets it to a version)
- `_WIN32_WCE` is the CE counterpart of the non-CE `_WIN32_WINNT` macro.
That does return the targeted Windows CE version.
- `_WIN32_WCE` is not defined by compilers, and relies on a header
setting it to a default, or the build to set it to the desired target
version. This is also how `_WIN32_WINNT` works.
- `_WIN32_WCE` default is set by `windef.h` in CeGCC.
- `_WIN32_WCE` isn't set to a default by MSVC Windows CE headers (the
ones I checked at least).
- CMake sets `_WIN32_WCE=<ver>`, `UNDER_CE`, `WINCE` for MSVC WinCE.
- `_WIN32_WCE` seems more popular in other projects, including CeGCC
itself. `zlib` is a notable exception amongst curl dependencies,
which uses `UNDER_CE`.
- Since `_WIN32_WCE` needs "certain" headers to have it defined, it's
undefined depending on headers included beforehand.
- `curl/curl.h` re-uses `_WIN32_WCE`'s as a self-guard, relying on
its not-(necessarily)-defined-by-default property:
25b445e479/include/curl/curl.h (L77)
Toolchain downloads:
- Windows:
https://downloads.sourceforge.net/cegcc/cegcc/0.59.1/cegcc_mingw32ce_cygwin1.7_r1399.tar.bz2
- macOS Intel:
https://downloads.sourceforge.net/cegcc/cegcc/0.59.1/cegcc_mingw32ce_snowleopard_r1397.tar.bz2
Closes #15975
411 lines
11 KiB
C
411 lines
11 KiB
C
#ifndef HEADER_CURL_SETUP_ONCE_H
|
|
#define HEADER_CURL_SETUP_ONCE_H
|
|
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
* SPDX-License-Identifier: curl
|
|
*
|
|
***************************************************************************/
|
|
|
|
/*
|
|
* Inclusion of common header files.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
#ifndef UNDER_CE
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_IO_H
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T)
|
|
#include <stdbool.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef USE_WOLFSSL
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
#ifdef USE_SCHANNEL
|
|
/* Must set this before <schannel.h> is included directly or indirectly by
|
|
another Windows header. */
|
|
# define SCHANNEL_USE_BLACKLISTS 1
|
|
#endif
|
|
|
|
#ifdef __hpux
|
|
# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
|
|
# ifdef _APP32_64BIT_OFF_T
|
|
# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
|
|
# undef _APP32_64BIT_OFF_T
|
|
# else
|
|
# undef OLD_APP32_64BIT_OFF_T
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
#include <sys/socket.h>
|
|
#endif
|
|
|
|
#include "functypes.h"
|
|
|
|
#ifdef __hpux
|
|
# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
|
|
# ifdef OLD_APP32_64BIT_OFF_T
|
|
# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
|
|
# undef OLD_APP32_64BIT_OFF_T
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
/*
|
|
* Definition of timeval struct for platforms that do not have it.
|
|
*/
|
|
|
|
#ifndef HAVE_STRUCT_TIMEVAL
|
|
struct timeval {
|
|
long tv_sec;
|
|
long tv_usec;
|
|
};
|
|
#endif
|
|
|
|
|
|
/*
|
|
* If we have the MSG_NOSIGNAL define, make sure we use
|
|
* it as the fourth argument of function send()
|
|
*/
|
|
|
|
#ifdef HAVE_MSG_NOSIGNAL
|
|
#define SEND_4TH_ARG MSG_NOSIGNAL
|
|
#else
|
|
#define SEND_4TH_ARG 0
|
|
#endif
|
|
|
|
|
|
#if defined(__minix)
|
|
/* Minix does not support recv on TCP sockets */
|
|
#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
|
|
(RECV_TYPE_ARG2)(y), \
|
|
(RECV_TYPE_ARG3)(z))
|
|
|
|
#elif defined(HAVE_RECV)
|
|
/*
|
|
* The definitions for the return type and arguments types
|
|
* of functions recv() and send() belong and come from the
|
|
* configuration file. Do not define them in any other place.
|
|
*
|
|
* HAVE_RECV is defined if you have a function named recv()
|
|
* which is used to read incoming data from sockets. If your
|
|
* function has another name then do not define HAVE_RECV.
|
|
*
|
|
* If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
|
|
* RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
|
|
* be defined.
|
|
*
|
|
* HAVE_SEND is defined if you have a function named send()
|
|
* which is used to write outgoing data on a connected socket.
|
|
* If yours has another name then do not define HAVE_SEND.
|
|
*
|
|
* If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
|
|
* SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
|
|
* SEND_TYPE_RETV must also be defined.
|
|
*/
|
|
|
|
#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
|
|
(RECV_TYPE_ARG2)(y), \
|
|
(RECV_TYPE_ARG3)(z), \
|
|
(RECV_TYPE_ARG4)(0))
|
|
#else /* HAVE_RECV */
|
|
#ifndef sread
|
|
#error "Missing definition of macro sread!"
|
|
#endif
|
|
#endif /* HAVE_RECV */
|
|
|
|
|
|
#if defined(__minix)
|
|
/* Minix does not support send on TCP sockets */
|
|
#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
|
|
(SEND_TYPE_ARG2)(y), \
|
|
(SEND_TYPE_ARG3)(z))
|
|
|
|
#elif defined(HAVE_SEND)
|
|
#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
|
|
(SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \
|
|
(SEND_TYPE_ARG3)(z), \
|
|
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
|
|
#else /* HAVE_SEND */
|
|
#ifndef swrite
|
|
#error "Missing definition of macro swrite!"
|
|
#endif
|
|
#endif /* HAVE_SEND */
|
|
|
|
|
|
/*
|
|
* Function-like macro definition used to close a socket.
|
|
*/
|
|
|
|
#if defined(HAVE_CLOSESOCKET)
|
|
# define sclose(x) closesocket((x))
|
|
#elif defined(HAVE_CLOSESOCKET_CAMEL)
|
|
# define sclose(x) CloseSocket((x))
|
|
#elif defined(MSDOS) /* Watt-32 */
|
|
# define sclose(x) close_s((x))
|
|
#elif defined(USE_LWIPSOCK)
|
|
# define sclose(x) lwip_close((x))
|
|
#else
|
|
# define sclose(x) close((x))
|
|
#endif
|
|
|
|
/*
|
|
* Stack-independent version of fcntl() on sockets:
|
|
*/
|
|
#if defined(USE_LWIPSOCK)
|
|
# define sfcntl lwip_fcntl
|
|
#else
|
|
# define sfcntl fcntl
|
|
#endif
|
|
|
|
/*
|
|
* 'bool' stuff compatible with HP-UX headers.
|
|
*/
|
|
|
|
#if defined(__hpux) && !defined(HAVE_BOOL_T)
|
|
typedef int bool;
|
|
# define false 0
|
|
# define true 1
|
|
# define HAVE_BOOL_T
|
|
#endif
|
|
|
|
|
|
/*
|
|
* 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
|
|
* On non-C99 platforms there is no bool, so define an enum for that.
|
|
* On C99 platforms 'false' and 'true' also exist. Enum uses a
|
|
* global namespace though, so use bool_false and bool_true.
|
|
*/
|
|
|
|
#ifndef HAVE_BOOL_T
|
|
typedef enum {
|
|
bool_false = 0,
|
|
bool_true = 1
|
|
} bool;
|
|
|
|
/*
|
|
* Use a define to let 'true' and 'false' use those enums. There
|
|
* are currently no use of true and false in libcurl proper, but
|
|
* there are some in the examples. This will cater for any later
|
|
* code happening to use true and false.
|
|
*/
|
|
# define false bool_false
|
|
# define true bool_true
|
|
# define HAVE_BOOL_T
|
|
#endif
|
|
|
|
/* the type we use for storing a single boolean bit */
|
|
#ifdef _MSC_VER
|
|
typedef bool bit;
|
|
#define BIT(x) bool x
|
|
#else
|
|
typedef unsigned int bit;
|
|
#define BIT(x) bit x:1
|
|
#endif
|
|
|
|
/*
|
|
* Redefine TRUE and FALSE too, to catch current use. With this
|
|
* change, 'bool found = 1' will give a warning on MIPSPro, but
|
|
* 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro,
|
|
* AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too.
|
|
*/
|
|
|
|
#ifndef TRUE
|
|
#define TRUE true
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE false
|
|
#endif
|
|
|
|
#include "curl_ctype.h"
|
|
|
|
|
|
/*
|
|
* Macro used to include code only in debug builds.
|
|
*/
|
|
|
|
#ifdef DEBUGBUILD
|
|
#define DEBUGF(x) x
|
|
#else
|
|
#define DEBUGF(x) do { } while(0)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Macro used to include assertion code only in debug builds.
|
|
*/
|
|
|
|
#undef DEBUGASSERT
|
|
#if defined(DEBUGBUILD)
|
|
#define DEBUGASSERT(x) assert(x)
|
|
#else
|
|
#define DEBUGASSERT(x) do { } while(0)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno
|
|
* (or equivalent) on this platform to hide platform details to code using it.
|
|
*/
|
|
|
|
#ifdef USE_WINSOCK
|
|
#define SOCKERRNO ((int)WSAGetLastError())
|
|
#define SET_SOCKERRNO(x) (WSASetLastError((int)(x)))
|
|
#else
|
|
#define SOCKERRNO (errno)
|
|
#define SET_SOCKERRNO(x) (errno = (x))
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Portable error number symbolic names defined to Winsock error codes.
|
|
*/
|
|
|
|
#ifdef USE_WINSOCK
|
|
#undef EBADF /* override definition in errno.h */
|
|
#define EBADF WSAEBADF
|
|
#undef EINTR /* override definition in errno.h */
|
|
#define EINTR WSAEINTR
|
|
#undef EINVAL /* override definition in errno.h */
|
|
#define EINVAL WSAEINVAL
|
|
#undef EWOULDBLOCK /* override definition in errno.h */
|
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
|
#undef EINPROGRESS /* override definition in errno.h */
|
|
#define EINPROGRESS WSAEINPROGRESS
|
|
#undef EALREADY /* override definition in errno.h */
|
|
#define EALREADY WSAEALREADY
|
|
#undef ENOTSOCK /* override definition in errno.h */
|
|
#define ENOTSOCK WSAENOTSOCK
|
|
#undef EDESTADDRREQ /* override definition in errno.h */
|
|
#define EDESTADDRREQ WSAEDESTADDRREQ
|
|
#undef EMSGSIZE /* override definition in errno.h */
|
|
#define EMSGSIZE WSAEMSGSIZE
|
|
#undef EPROTOTYPE /* override definition in errno.h */
|
|
#define EPROTOTYPE WSAEPROTOTYPE
|
|
#undef ENOPROTOOPT /* override definition in errno.h */
|
|
#define ENOPROTOOPT WSAENOPROTOOPT
|
|
#undef EPROTONOSUPPORT /* override definition in errno.h */
|
|
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
|
|
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
|
|
#undef EOPNOTSUPP /* override definition in errno.h */
|
|
#define EOPNOTSUPP WSAEOPNOTSUPP
|
|
#define EPFNOSUPPORT WSAEPFNOSUPPORT
|
|
#undef EAFNOSUPPORT /* override definition in errno.h */
|
|
#define EAFNOSUPPORT WSAEAFNOSUPPORT
|
|
#undef EADDRINUSE /* override definition in errno.h */
|
|
#define EADDRINUSE WSAEADDRINUSE
|
|
#undef EADDRNOTAVAIL /* override definition in errno.h */
|
|
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
|
#undef ENETDOWN /* override definition in errno.h */
|
|
#define ENETDOWN WSAENETDOWN
|
|
#undef ENETUNREACH /* override definition in errno.h */
|
|
#define ENETUNREACH WSAENETUNREACH
|
|
#undef ENETRESET /* override definition in errno.h */
|
|
#define ENETRESET WSAENETRESET
|
|
#undef ECONNABORTED /* override definition in errno.h */
|
|
#define ECONNABORTED WSAECONNABORTED
|
|
#undef ECONNRESET /* override definition in errno.h */
|
|
#define ECONNRESET WSAECONNRESET
|
|
#undef ENOBUFS /* override definition in errno.h */
|
|
#define ENOBUFS WSAENOBUFS
|
|
#undef EISCONN /* override definition in errno.h */
|
|
#define EISCONN WSAEISCONN
|
|
#undef ENOTCONN /* override definition in errno.h */
|
|
#define ENOTCONN WSAENOTCONN
|
|
#define ESHUTDOWN WSAESHUTDOWN
|
|
#define ETOOMANYREFS WSAETOOMANYREFS
|
|
#undef ETIMEDOUT /* override definition in errno.h */
|
|
#define ETIMEDOUT WSAETIMEDOUT
|
|
#undef ECONNREFUSED /* override definition in errno.h */
|
|
#define ECONNREFUSED WSAECONNREFUSED
|
|
#undef ELOOP /* override definition in errno.h */
|
|
#define ELOOP WSAELOOP
|
|
#ifndef ENAMETOOLONG /* possible previous definition in errno.h */
|
|
#define ENAMETOOLONG WSAENAMETOOLONG
|
|
#endif
|
|
#define EHOSTDOWN WSAEHOSTDOWN
|
|
#undef EHOSTUNREACH /* override definition in errno.h */
|
|
#define EHOSTUNREACH WSAEHOSTUNREACH
|
|
#ifndef ENOTEMPTY /* possible previous definition in errno.h */
|
|
#define ENOTEMPTY WSAENOTEMPTY
|
|
#endif
|
|
#define EPROCLIM WSAEPROCLIM
|
|
#define EUSERS WSAEUSERS
|
|
#define EDQUOT WSAEDQUOT
|
|
#define ESTALE WSAESTALE
|
|
#define EREMOTE WSAEREMOTE
|
|
#endif
|
|
|
|
/*
|
|
* Macro argv_item_t hides platform details to code using it.
|
|
*/
|
|
|
|
#ifdef __VMS
|
|
#define argv_item_t __char_ptr32
|
|
#elif defined(_UNICODE) && !defined(UNDER_CE)
|
|
#define argv_item_t wchar_t *
|
|
#else
|
|
#define argv_item_t char *
|
|
#endif
|
|
|
|
|
|
/*
|
|
* We use this ZERO_NULL to avoid picky compiler warnings,
|
|
* when assigning a NULL pointer to a function pointer var.
|
|
*/
|
|
|
|
#define ZERO_NULL 0
|
|
|
|
|
|
#endif /* HEADER_CURL_SETUP_ONCE_H */
|