MinGW is missing support for winhttp.dll which will be used for automatic proxy server detection in Windows. Until it becomes available the workaround performed is to provide wrapper functions and dynamically map the missing library into the address space, get the function pointer for the actual API and call it with the arguments provided.
To keep things managable and short in the source code two preprocessor macros are defined that do most of the work. Signed-off-by: Heiko Hund <heiko.h...@sophos.com> --- configure.ac | 30 ++++++++++++++++ win32.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ win32.h | 61 ++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index a3789d9..42d46cb 100644 --- a/configure.ac +++ b/configure.ac @@ -665,6 +665,36 @@ if test "${WIN32}" = "yes"; then fi dnl +dnl Check if MinGW knows about WinHTTP API +dnl +if test "${WIN32}" = "yes"; then + AC_MSG_CHECKING([if MinGW knows about WinHTTP]) + AC_TRY_LINK([ + #include <windows.h> + #include <winhttp.h> + ], [ + LPWSTR *url; + HINTERNET session; + WINHTTP_PROXY_INFO proxy_info; + WINHTTP_AUTOPROXY_OPTIONS proxy_options; + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_info; + + WinHttpGetDefaultProxyConfiguration (&proxy_info); + WinHttpGetIEProxyConfigForCurrentUser (&ie_proxy_info); + WinHttpDetectAutoProxyConfigUrl (WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A, url); + session = WinHttpOpen (NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + WinHttpGetProxyForUrl (session, L"http://openvpn.net", &proxy_options, &proxy_info); + WinHttpCloseHandle (session); + ], [ + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no.]) + AC_MSG_NOTICE([Enabling WinHTTP compatibility layer.]) + AC_DEFINE(USE_WINHTTP_COMPAT, 1, [Use the WinHTTP compatibility layer]) + ]) +fi + +dnl dnl check for LZO library dnl diff --git a/win32.c b/win32.c index cf6cc2d..15743a8 100644 --- a/win32.c +++ b/win32.c @@ -1128,4 +1128,112 @@ win_get_tempdir() } return tmpdir; } + + +#ifdef USE_WINHTTP_COMPAT + +/* + * MinGW is missing support for winhttp.dll which is used for automatic + * proxy server detection. Until it becomes available the workaround is + * to dynamically map the library into the address space and get the + * function pointers for the APIs that are used. The two macros below + * do just that. + * + * PROVIDE_WIN32_LIBRARY provides means to access API functions. + * Arguments: LIB - name of the DLL to load + * + * DEFINE_WIN32_WRAPPER defines a wrapper function around the + * original API provoded by the library. The original API can + * be accessed within the wrapper as <LIB>_<FUNC> (see Arguments). + * Arguments: LIB name of the DLL the function is exported in + * ERR value to return in case something goes wrong + * RET API function's return value type + * FUNC exported name of the API function + * ARGS declaration of the API function arguments + * BODY the wrapper function's body + */ + +#define PROVIDE_WIN32_LIBRARY(LIB) \ + static HMODULE get_ ## LIB ## _library () \ + { \ + static HMODULE lib = NULL; \ + \ + if (lib == NULL) \ + { \ + char name[MAX_PATH]; \ + UINT len = GetSystemDirectory (name, sizeof (name)); \ + if (len == 0) \ + return NULL; \ + \ + strncpy (name + len, "\\" #LIB ".dll", sizeof (name) - len); \ + name[sizeof (name) - 1] = '\0'; \ + \ + lib = LoadLibrary (name); \ + } \ + \ + return lib; \ + } + +#define DEFINE_WIN32_WRAPPER(LIB, ERR, RET, FUNC, ARGS, BODY) \ + RET FUNC ARGS \ + { \ + typedef RET (WINAPI *(FUNC ## _fn)) ARGS; \ + static FUNC ## _fn LIB ## _ ## FUNC = NULL; \ + \ + if ((LIB ## _ ## FUNC) == NULL) \ + { \ + union { \ + FUNC ## _fn *type; \ + FARPROC *ptr; \ + } u = { .type = &(LIB ## _ ## FUNC) }; \ + \ + HMODULE lib = get_ ## LIB ## _library (); \ + if (lib == NULL) \ + return (ERR); \ + \ + *(u.ptr) = GetProcAddress (lib, (#FUNC)); \ + if ((LIB ## _ ## FUNC) == NULL) \ + return (ERR); \ + } \ + \ + BODY \ + } + + +PROVIDE_WIN32_LIBRARY (winhttp) + +DEFINE_WIN32_WRAPPER (winhttp, NULL, HINTERNET, +WinHttpOpen, (LPCWSTR user_agent, DWORD access_type, LPCWSTR proxy, LPCWSTR bypass, DWORD flags), + return winhttp_WinHttpOpen (user_agent, access_type, proxy, bypass, flags); +) + +DEFINE_WIN32_WRAPPER (winhttp, FALSE, BOOL, +WinHttpCloseHandle, (HINTERNET session), + return winhttp_WinHttpCloseHandle (session); +) + +DEFINE_WIN32_WRAPPER (winhttp, FALSE, BOOL, +WinHttpGetDefaultProxyConfiguration, (WINHTTP_PROXY_INFO *proxy_info), + return winhttp_WinHttpGetDefaultProxyConfiguration (proxy_info); +) + +DEFINE_WIN32_WRAPPER (winhttp, FALSE, BOOL, +WinHttpGetIEProxyConfigForCurrentUser, (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *proxy_config), + return winhttp_WinHttpGetIEProxyConfigForCurrentUser(proxy_config); +) + +DEFINE_WIN32_WRAPPER (winhttp, FALSE, BOOL, +WinHttpDetectAutoProxyConfigUrl, (DWORD flags, LPWSTR *url), + return winhttp_WinHttpDetectAutoProxyConfigUrl (flags, url); +) + +DEFINE_WIN32_WRAPPER (winhttp, FALSE, BOOL, +WinHttpGetProxyForUrl, (HINTERNET session, LPCWSTR url, + WINHTTP_AUTOPROXY_OPTIONS *options, + WINHTTP_PROXY_INFO *proxy_info), + return winhttp_WinHttpGetProxyForUrl (session, url, options, proxy_info); +) + +#endif /* USE_WINHTTP_COMPAT */ + #endif diff --git a/win32.h b/win32.h index 87d8ecc..2ff4b8c 100644 --- a/win32.h +++ b/win32.h @@ -288,5 +288,66 @@ int inet_pton(int af, const char *src, void *st); /* Find temporary directory */ const char *win_get_tempdir(); +/* + * If MinGW does not know about the WinHTTP C API functions and + * constants that are used for automatic proxy server detection + * they are declared here. For detailed information see: + * http://msdn.microsoft.com/en-us/library/aa384252%28v=VS.85%29.aspx + */ +#ifdef USE_WINHTTP_COMPAT + +#include <windows.h> +#include <wininet.h> + +/* WINHTTP_PROXY_INFO dwAccessType constants */ +/* and WinHttpOpen() access_type */ +#define WINHTTP_ACCESS_TYPE_NO_PROXY 1 +#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 + +/* WinHttpDetectAutoProxyConfigUrl() flags */ +#define WINHTTP_AUTO_DETECT_TYPE_DHCP 1 +#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 2 + +/* WINHTTP_AUTOPROXY_OPTIONS dwFlags */ +#define WINHTTP_AUTOPROXY_CONFIG_URL 2 + +/* WinHttpOpen() proxy and bypass values */ +#define WINHTTP_NO_PROXY_NAME 0 +#define WINHTTP_NO_PROXY_BYPASS 0 + +typedef struct { + DWORD dwAccessType; + LPWSTR lpszProxy; + LPWSTR lpszProxyBypass; +} WINHTTP_PROXY_INFO; + +typedef struct { + BOOL fAutoDetect; + LPWSTR lpszAutoConfigUrl; + LPWSTR lpszProxy; + LPWSTR lpszProxyBypass; +} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG; + +typedef struct { + DWORD dwFlags; + DWORD dwAutoDetectFlags; + LPCWSTR lpszAutoConfigUrl; + LPVOID lpvReserved; + DWORD dwReserved; + BOOL fAutoLogonIfChallenged; +} WINHTTP_AUTOPROXY_OPTIONS; + +HINTERNET WinHttpOpen (LPCWSTR user_agent, DWORD access_type, + LPCWSTR proxy, LPCWSTR bypass, DWORD flags); +BOOL WinHttpCloseHandle (HINTERNET session); +BOOL WinHttpGetDefaultProxyConfiguration (WINHTTP_PROXY_INFO *proxy_info); +BOOL WinHttpGetIEProxyConfigForCurrentUser (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *proxy_config); +BOOL WinHttpDetectAutoProxyConfigUrl (DWORD flags, LPWSTR *url); +BOOL WinHttpGetProxyForUrl (HINTERNET session, LPCWSTR url, + WINHTTP_AUTOPROXY_OPTIONS *options, + WINHTTP_PROXY_INFO *proxy_info); + +#endif /* USE_WINHTTP_COMPAT */ + #endif #endif -- 1.7.5.4