[Wine-patches] [eter-2.1 8/9] winhttp: Implement WINHTTP_OPTION_CONNECTION_INFO. (eterbug #10937).

Dmitry Timoshkov dmitry на baikal.ru
Пн Дек 14 10:33:49 MSK 2015


From: Hans Leidekker <hans на codeweavers.com>
---
 dlls/winhttp/session.c       | 94 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/winhttp/tests/winhttp.c | 62 +++++++++++++++++++++++++++++
 include/winhttp.h            | 16 ++++++++
 3 files changed, 172 insertions(+)

diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index d43b225..394fddd 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -25,6 +25,11 @@
 
 #include "windef.h"
 #include "winbase.h"
+#ifndef __MINGW32__
+#define USE_WS_PREFIX
+#endif
+#include "winsock2.h"
+#include "ws2ipdef.h"
 #include "winhttp.h"
 #include "wincrypt.h"
 #include "winreg.h"
@@ -587,6 +592,71 @@ static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
     return ret;
 }
 
+static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
+{
+#ifndef __MINGW32__
+    switch (addr->sa_family)
+    {
+    case AF_INET:
+    {
+        const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
+        struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
+        char *p;
+
+        addr_win->sin_family = WS_AF_INET;
+        addr_win->sin_port   = addr_unix->sin_port;
+        memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
+        p = (char *)&addr_win->sin_addr + 4;
+        memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
+        return TRUE;
+    }
+    case AF_INET6:
+    {
+        const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
+        struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
+
+        addr_win->sin6_family   = WS_AF_INET6;
+        addr_win->sin6_port     = addr_unix->sin6_port;
+        addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
+        memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+        addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
+#else
+        addr_win->sin6_scope_id = 0;
+#endif
+        memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
+        return TRUE;
+    }
+    default:
+        ERR("unhandled family %u\n", addr->sa_family);
+        return FALSE;
+    }
+#else
+    switch (addr->sa_family)
+    {
+    case AF_INET:
+    {
+        struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
+
+        memcpy( addr_in, addr, sizeof(*addr_in) );
+        memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
+        return TRUE;
+    }
+    case AF_INET6:
+    {
+        struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
+
+        memcpy( addr_in6, addr, sizeof(*addr_in6) );
+        memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
+        return TRUE;
+    }
+    default:
+        ERR("unhandled family %u\n", addr->sa_family);
+        return FALSE;
+    }
+#endif
+}
+
 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
 {
     request_t *request = (request_t *)hdr;
@@ -683,6 +753,30 @@ static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buf
         *buflen = sizeof(DWORD);
         return TRUE;
     }
+    case WINHTTP_OPTION_CONNECTION_INFO:
+    {
+        WINHTTP_CONNECTION_INFO *info = buffer;
+        struct sockaddr local;
+        socklen_t len = sizeof(local);
+        const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
+
+        if (!buffer || *buflen < sizeof(*info))
+        {
+            *buflen = sizeof(*info);
+            set_last_error( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
+        if (!netconn_connected( &request->netconn ))
+        {
+            set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
+            return FALSE;
+        }
+        if (getsockname( request->netconn.socket, &local, &len )) return FALSE;
+        if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
+        if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
+        info->cbSize = sizeof(*info);
+        return TRUE;
+    }
     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
         *(DWORD *)buffer = request->resolve_timeout;
         *buflen = sizeof(DWORD);
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index fd0db18..b03e108 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -23,6 +23,8 @@
 #include <stdlib.h>
 #include <windef.h>
 #include <winbase.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
 #include <winhttp.h>
 #include <wincrypt.h>
 #include <winreg.h>
@@ -2019,6 +2021,65 @@ static void test_bad_header( int port )
     WinHttpCloseHandle( ses );
 }
 
+static void test_connection_info( int port )
+{
+    static const WCHAR basicW[] = {'/','b','a','s','i','c',0};
+    HINTERNET ses, con, req;
+    WINHTTP_CONNECTION_INFO info;
+    DWORD size, error;
+    BOOL ret;
+
+    ses = WinHttpOpen( test_useragent, 0, NULL, NULL, 0 );
+    ok( ses != NULL, "failed to open session %u\n", GetLastError() );
+
+    con = WinHttpConnect( ses, localhostW, port, 0 );
+    ok( con != NULL, "failed to open a connection %u\n", GetLastError() );
+
+    req = WinHttpOpenRequest( con, NULL, basicW, NULL, NULL, NULL, 0 );
+    ok( req != NULL, "failed to open a request %u\n", GetLastError() );
+
+    size = sizeof(info);
+    SetLastError( 0xdeadbeef );
+    ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size );
+    error = GetLastError();
+    if (!ret && error == ERROR_INVALID_PARAMETER)
+    {
+        win_skip( "WINHTTP_OPTION_CONNECTION_INFO not supported\n" );
+        return;
+    }
+    ok( !ret, "unexpected success\n" );
+    ok( error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %u\n", error );
+
+    ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
+    ok( ret, "failed to send request %u\n", GetLastError() );
+
+    size = 0;
+    SetLastError( 0xdeadbeef );
+    ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size );
+    error = GetLastError();
+    ok( !ret, "unexpected success\n" );
+    ok( error == ERROR_INSUFFICIENT_BUFFER, "got %u\n", error );
+
+    size = sizeof(info);
+    memset( &info, 0, sizeof(info) );
+    ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size );
+    ok( ret, "failed to retrieve connection info %u\n", GetLastError() );
+    ok( info.cbSize == sizeof(info), "wrong size %u\n", info.cbSize );
+
+    ret = WinHttpReceiveResponse( req, NULL );
+    ok( ret, "failed to receive response %u\n", GetLastError() );
+
+    size = sizeof(info);
+    memset( &info, 0, sizeof(info) );
+    ret = WinHttpQueryOption( req, WINHTTP_OPTION_CONNECTION_INFO, &info, &size );
+    ok( ret, "failed to retrieve connection info %u\n", GetLastError() );
+    ok( info.cbSize == sizeof(info), "wrong size %u\n", info.cbSize );
+
+    WinHttpCloseHandle( req );
+    WinHttpCloseHandle( con );
+    WinHttpCloseHandle( ses );
+}
+
 static void test_credentials(void)
 {
     static WCHAR userW[] = {'u','s','e','r',0};
@@ -2768,6 +2829,7 @@ START_TEST (winhttp)
     if (ret != WAIT_OBJECT_0)
         return;
 
+    test_connection_info(si.port);
     test_basic_request(si.port, NULL, basicW);
     test_no_headers(si.port);
     test_basic_authentication(si.port);
diff --git a/include/winhttp.h b/include/winhttp.h
index cf0da83..9247abf 100644
--- a/include/winhttp.h
+++ b/include/winhttp.h
@@ -19,6 +19,12 @@
 #ifndef __WINE_WINHTTP_H
 #define __WINE_WINHTTP_H
 
+#ifdef _WIN64
+#include <pshpack8.h>
+#else
+#include <pshpack4.h>
+#endif
+
 #define WINHTTPAPI
 #define BOOLAPI WINHTTPAPI BOOL WINAPI
 
@@ -527,6 +533,14 @@ typedef struct
     DWORD dwMinorVersion;
 } HTTP_VERSION_INFO, *LPHTTP_VERSION_INFO;
 
+#ifdef _WS2DEF_
+typedef struct
+{
+    DWORD cbSize;
+    SOCKADDR_STORAGE LocalAddress;
+    SOCKADDR_STORAGE RemoteAddress;
+} WINHTTP_CONNECTION_INFO;
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -565,4 +579,6 @@ BOOL        WINAPI WinHttpWriteData(HINTERNET,LPCVOID,DWORD,LPDWORD);
 }
 #endif
 
+#include <poppack.h>
+
 #endif  /* __WINE_WINHTTP_H */
-- 
2.6.4



Подробная информация о списке рассылки Wine-patches