Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/hnetcfg/apps.c | 21 ++++++++++----------- dlls/hnetcfg/manager.c | 4 ++-- dlls/hnetcfg/policy.c | 14 +++++++------- dlls/hnetcfg/port.c | 13 ++++++------- dlls/hnetcfg/profile.c | 4 ++-- dlls/hnetcfg/service.c | 8 ++++---- 6 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c index b6447cf4d63..16379e3457b 100644 --- a/dlls/hnetcfg/apps.c +++ b/dlls/hnetcfg/apps.c @@ -29,7 +29,6 @@ #include "natupnp.h"
#include "wine/debug.h" -#include "wine/heap.h" #include "hnetcfg_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg); @@ -62,7 +61,7 @@ static ULONG WINAPI fw_app_Release( { TRACE("destroying %p\n", fw_app); SysFreeString( fw_app->filename ); - HeapFree( GetProcessHeap(), 0, fw_app ); + free( fw_app ); } return refs; } @@ -281,7 +280,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( res = WNetGetUniversalNameW(image, UNIVERSAL_NAME_INFO_LEVEL, NULL, &sz); if (res == WN_MORE_DATA) { - if (!(path = heap_alloc(sz))) + if (!(path = malloc(sz))) return E_OUTOFMEMORY;
info = (UNIVERSAL_NAME_INFOW *)&path; @@ -291,21 +290,21 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( SysFreeString(This->filename); This->filename = SysAllocString(info->lpUniversalName); } - heap_free(path); + free(path); return HRESULT_FROM_WIN32(res); }
sz = GetFullPathNameW(image, 0, NULL, NULL); - if (!(path = heap_alloc(++sz * sizeof(WCHAR)))) + if (!(path = malloc(++sz * sizeof(WCHAR)))) return E_OUTOFMEMORY; GetFullPathNameW(image, sz, path, NULL);
longsz = GetLongPathNameW(path, path, sz); if (longsz > sz) { - if (!(path = heap_realloc(path, longsz * sizeof(WCHAR)))) + if (!(path = realloc(path, longsz * sizeof(WCHAR)))) { - heap_free(path); + free(path); return E_OUTOFMEMORY; } GetLongPathNameW(path, path, longsz); @@ -313,7 +312,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName(
SysFreeString( This->filename ); This->filename = SysAllocString(path); - heap_free(path); + free(path); return This->filename ? S_OK : E_OUTOFMEMORY; }
@@ -432,7 +431,7 @@ HRESULT NetFwAuthorizedApplication_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fa = HeapAlloc( GetProcessHeap(), 0, sizeof(*fa) ); + fa = malloc( sizeof(*fa) ); if (!fa) return E_OUTOFMEMORY;
fa->INetFwAuthorizedApplication_iface.lpVtbl = &fw_app_vtbl; @@ -470,7 +469,7 @@ static ULONG WINAPI fw_apps_Release( if (!refs) { TRACE("destroying %p\n", fw_apps); - HeapFree( GetProcessHeap(), 0, fw_apps ); + free( fw_apps ); } return refs; } @@ -645,7 +644,7 @@ HRESULT NetFwAuthorizedApplications_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fa = HeapAlloc( GetProcessHeap(), 0, sizeof(*fa) ); + fa = malloc( sizeof(*fa) ); if (!fa) return E_OUTOFMEMORY;
fa->INetFwAuthorizedApplications_iface.lpVtbl = &fw_apps_vtbl; diff --git a/dlls/hnetcfg/manager.c b/dlls/hnetcfg/manager.c index 2c0790a73b5..fda69729901 100644 --- a/dlls/hnetcfg/manager.c +++ b/dlls/hnetcfg/manager.c @@ -58,7 +58,7 @@ static ULONG WINAPI fw_manager_Release( if (!refs) { TRACE("destroying %p\n", fw_manager); - HeapFree( GetProcessHeap(), 0, fw_manager ); + free( fw_manager ); } return refs; } @@ -244,7 +244,7 @@ HRESULT NetFwMgr_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fm = HeapAlloc( GetProcessHeap(), 0, sizeof(*fm) ); + fm = malloc( sizeof(*fm) ); if (!fm) return E_OUTOFMEMORY;
fm->INetFwMgr_iface.lpVtbl = &fw_manager_vtbl; diff --git a/dlls/hnetcfg/policy.c b/dlls/hnetcfg/policy.c index 1f5b0daa568..7bdc1563d90 100644 --- a/dlls/hnetcfg/policy.c +++ b/dlls/hnetcfg/policy.c @@ -105,7 +105,7 @@ static ULONG WINAPI netfw_rules_Release( if (!refs) { TRACE("destroying %p\n", This); - HeapFree( GetProcessHeap(), 0, This ); + free( This ); } return refs; } @@ -265,7 +265,7 @@ static HRESULT create_INetFwRules(INetFwRules **object)
TRACE("(%p)\n", object);
- rules = HeapAlloc( GetProcessHeap(), 0, sizeof(*rules) ); + rules = malloc( sizeof(*rules) ); if (!rules) return E_OUTOFMEMORY;
rules->INetFwRules_iface.lpVtbl = &fw_rules_vtbl; @@ -292,7 +292,7 @@ static ULONG WINAPI fw_policy_Release( if (!refs) { TRACE("destroying %p\n", fw_policy); - HeapFree( GetProcessHeap(), 0, fw_policy ); + free( fw_policy ); } return refs; } @@ -435,7 +435,7 @@ HRESULT NetFwPolicy_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwPolicy_iface.lpVtbl = &fw_policy_vtbl; @@ -487,7 +487,7 @@ static ULONG WINAPI fwpolicy2_Release(INetFwPolicy2 *iface) { INetFwRules_Release(fw_policy->fw_policy2_rules); TRACE("destroying %p\n", fw_policy); - HeapFree( GetProcessHeap(), 0, fw_policy ); + free( fw_policy ); } return refs; } @@ -768,7 +768,7 @@ HRESULT NetFwPolicy2_create( IUnknown *outer, void **obj )
TRACE("(%p,%p)\n", outer, obj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwPolicy2_iface.lpVtbl = &fw_policy2_vtbl; @@ -778,7 +778,7 @@ HRESULT NetFwPolicy2_create( IUnknown *outer, void **obj )
if (FAILED(create_INetFwRules(&fp->fw_policy2_rules))) { - HeapFree( GetProcessHeap(), 0, fp ); + free( fp ); return E_OUTOFMEMORY; }
diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index fd4ac4977d3..9e9264df1dc 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -28,7 +28,6 @@ #include "netfw.h" #include "natupnp.h"
-#include "wine/heap.h" #include "wine/debug.h" #include "hnetcfg_private.h"
@@ -64,7 +63,7 @@ static ULONG WINAPI fw_port_Release( { TRACE("destroying %p\n", fw_port); SysFreeString( fw_port->name ); - HeapFree( GetProcessHeap(), 0, fw_port ); + free( fw_port ); } return refs; } @@ -363,7 +362,7 @@ HRESULT NetFwOpenPort_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwOpenPort_iface.lpVtbl = &fw_port_vtbl; @@ -404,7 +403,7 @@ static ULONG WINAPI fw_ports_Release( if (!refs) { TRACE("destroying %p\n", fw_ports); - HeapFree( GetProcessHeap(), 0, fw_ports ); + free( fw_ports ); } return refs; } @@ -592,7 +591,7 @@ HRESULT NetFwOpenPorts_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwOpenPorts_iface.lpVtbl = &fw_ports_vtbl; @@ -653,7 +652,7 @@ static ULONG WINAPI upnpnat_Release(IUPnPNAT *iface) LONG refs = InterlockedDecrement( &This->ref ); if (!refs) { - heap_free( This ); + free( This ); } return refs; } @@ -762,7 +761,7 @@ HRESULT IUPnPNAT_create(IUnknown *outer, void **object)
TRACE("(%p,%p)\n", outer, object);
- nat = heap_alloc( sizeof(*nat) ); + nat = malloc( sizeof(*nat) ); if (!nat) return E_OUTOFMEMORY;
nat->IUPnPNAT_iface.lpVtbl = &upnpnat_vtbl; diff --git a/dlls/hnetcfg/profile.c b/dlls/hnetcfg/profile.c index d0e9f48dab4..63f6d0cc7ed 100644 --- a/dlls/hnetcfg/profile.c +++ b/dlls/hnetcfg/profile.c @@ -58,7 +58,7 @@ static ULONG WINAPI fw_profile_Release( if (!refs) { TRACE("destroying %p\n", fw_profile); - HeapFree( GetProcessHeap(), 0, fw_profile ); + free( fw_profile ); } return refs; } @@ -334,7 +334,7 @@ HRESULT NetFwProfile_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwProfile_iface.lpVtbl = &fw_profile_vtbl; diff --git a/dlls/hnetcfg/service.c b/dlls/hnetcfg/service.c index 5bfeedaaedf..122d9797bab 100644 --- a/dlls/hnetcfg/service.c +++ b/dlls/hnetcfg/service.c @@ -58,7 +58,7 @@ static ULONG WINAPI fw_service_Release( if (!refs) { TRACE("destroying %p\n", fw_service); - HeapFree( GetProcessHeap(), 0, fw_service ); + free( fw_service ); } return refs; } @@ -290,7 +290,7 @@ static HRESULT NetFwService_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwService_iface.lpVtbl = &fw_service_vtbl; @@ -328,7 +328,7 @@ static ULONG WINAPI fw_services_Release( if (!refs) { TRACE("destroying %p\n", fw_services); - HeapFree( GetProcessHeap(), 0, fw_services ); + free( fw_services ); } return refs; } @@ -464,7 +464,7 @@ HRESULT NetFwServices_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY;
fp->INetFwServices_iface.lpVtbl = &fw_services_vtbl;
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- The patchset aims to fully implement IStaticPortMappingCollection. I placed the full patchset here: https://github.com/gofman/wine/tree/portmapping
dlls/hnetcfg/tests/policy.c | 132 +++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-)
diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index e2606933079..6abdcd7fb4e 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -29,6 +29,12 @@ #include "netfw.h" #include "natupnp.h"
+static ULONG get_refcount(IUnknown *unk) +{ + IUnknown_AddRef(unk); + return IUnknown_Release(unk); +} + static void test_policy2_rules(INetFwPolicy2 *policy2) { HRESULT hr; @@ -164,6 +170,119 @@ static void test_NetFwAuthorizedApplication(void) INetFwAuthorizedApplication_Release(app); }
+static void test_static_port_mapping_collection( IStaticPortMappingCollection *ports ) +{ + LONG i, count, count2, expected_count, external_port; + IStaticPortMapping *pm, *pm2; + ULONG refcount, refcount2; + IEnumVARIANT *enum_ports; + IUnknown *unk; + ULONG fetched; + BSTR protocol; + VARIANT var; + HRESULT hr; + + refcount = get_refcount((IUnknown *)ports); + hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + refcount2 = get_refcount((IUnknown *)ports); + ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2); + + hr = IEnumVARIANT_Reset(enum_ports); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + count = 0xdeadbeef; + hr = IStaticPortMappingCollection_get_Count(ports, &count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"UDP", &pm); + if (SUCCEEDED(hr)) + { + expected_count = count; + IStaticPortMapping_Release(pm); + } + else + { + expected_count = count + 1; + } + + hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"udp", 12345, (BSTR)L"1.2.3.4", + VARIANT_TRUE, (BSTR)L"wine_test", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"UDP", 12345, (BSTR)L"1.2.3.4", + VARIANT_TRUE, (BSTR)L"wine_test", &pm); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Count(ports, &count2); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, NULL, &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"UDP", NULL); + ok(hr == E_POINTER, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"udp", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, -1, (BSTR)L"UDP", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 65536, (BSTR)L"UDP", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12346, (BSTR)L"UDP", &pm); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Got unexpected hr %#x.\n", hr); + + hr = IEnumVARIANT_Reset(enum_ports); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + for (i = 0; i < count2; ++i) + { + VariantInit(&var); + + fetched = 0xdeadbeef; + hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(fetched == 1, "Got unexpected fetched %u.\n", fetched); + ok(V_VT(&var) == VT_DISPATCH, "Got unexpected variant type %u.\n", V_VT(&var)); + + hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IStaticPortMapping, (void **)&pm); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMapping_get_Protocol(pm, &protocol); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + external_port = 0xdeadbeef; + hr = IStaticPortMapping_get_ExternalPort(pm, &external_port); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + ok(!wcscmp(protocol, L"UDP") || !wcscmp(protocol, L"TCP"), "Got unexpected protocol %s.\n", + debugstr_w(protocol)); + hr = IStaticPortMappingCollection_get_Item(ports, external_port, protocol, &pm2); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(pm2 != pm, "Got same interface.\n"); + + IStaticPortMapping_Release(pm); + IStaticPortMapping_Release(pm2); + + SysFreeString(protocol); + + VariantClear(&var); + } + hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched); + ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + IEnumVARIANT_Release(enum_ports); +} + static void test_IUPnPNAT(void) { IUPnPNAT *nat; @@ -171,6 +290,7 @@ static void test_IUPnPNAT(void) IDynamicPortMappingCollection *dync_ports; INATEventManager *manager; IProvideClassInfo *provider; + ULONG refcount, refcount2; HRESULT hr;
hr = CoCreateInstance(&CLSID_UPnPNAT, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IUPnPNAT, (void**)&nat); @@ -179,11 +299,21 @@ static void test_IUPnPNAT(void) hr = IUPnPNAT_QueryInterface(nat, &IID_IProvideClassInfo, (void**)&provider); ok(hr == E_NOINTERFACE, "got: %08x\n", hr);
+ refcount = get_refcount((IUnknown *)nat); hr = IUPnPNAT_get_StaticPortMappingCollection(nat, &static_ports); + ok(hr == S_OK, "got: %08x\n", hr); if(hr == S_OK && static_ports) + { + refcount2 = get_refcount((IUnknown *)nat); + ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2); + test_static_port_mapping_collection( static_ports ); IStaticPortMappingCollection_Release(static_ports); - + } + else if (hr == S_OK) + { + skip( "UPNP gateway not found.\n" ); + } hr = IUPnPNAT_get_DynamicPortMappingCollection(nat, &dync_ports); ok(hr == S_OK || hr == E_NOTIMPL /* Windows 8.1 */, "got: %08x\n", hr); if(hr == S_OK && dync_ports)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/hnetcfg/Makefile.in | 2 +- dlls/hnetcfg/apps.c | 3 +- dlls/hnetcfg/hnetcfg_private.h | 1 + dlls/hnetcfg/port.c | 348 ++++++++++++++++++++++++++++++++- dlls/hnetcfg/tests/policy.c | 3 +- 5 files changed, 350 insertions(+), 7 deletions(-)
diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in index 3bc329cd7f1..8d1f1b27ffe 100644 --- a/dlls/hnetcfg/Makefile.in +++ b/dlls/hnetcfg/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = hnetcfg.dll IMPORTS = oleaut32 ole32 advapi32 mpr uuid - +DELAYIMPORTS = ws2_32 EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \ diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c index 16379e3457b..c5fe5e41f5e 100644 --- a/dlls/hnetcfg/apps.c +++ b/dlls/hnetcfg/apps.c @@ -114,7 +114,8 @@ static REFIID tid_id[] = &IID_INetFwPolicy, &IID_INetFwPolicy2, &IID_INetFwProfile, - &IID_IUPnPNAT + &IID_IUPnPNAT, + &IID_IStaticPortMappingCollection, };
HRESULT get_typeinfo( enum type_id tid, ITypeInfo **ret ) diff --git a/dlls/hnetcfg/hnetcfg_private.h b/dlls/hnetcfg/hnetcfg_private.h index be2d0f3c7c6..91fef756464 100644 --- a/dlls/hnetcfg/hnetcfg_private.h +++ b/dlls/hnetcfg/hnetcfg_private.h @@ -28,6 +28,7 @@ enum type_id INetFwProfile_tid, INetFwRules_tid, IUPnPNAT_tid, + IStaticPortMappingCollection_tid, last_tid };
diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 9e9264df1dc..89a3f571d45 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -24,6 +24,9 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "string.h" +#include "assert.h" +#include "winsock2.h" #include "ole2.h" #include "netfw.h" #include "natupnp.h" @@ -33,6 +36,343 @@
WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg);
+static struct +{ + LONG refs; + BOOL winsock_initialized; +} +upnp_gateway_connection; + +static SRWLOCK upnp_gateway_connection_lock = SRWLOCK_INIT; + +static void gateway_connection_cleanup(void) +{ + TRACE( ".\n" ); + if (upnp_gateway_connection.winsock_initialized) WSACleanup(); + memset( &upnp_gateway_connection, 0, sizeof(upnp_gateway_connection) ); +} + +static BOOL init_gateway_connection(void) +{ + static const char upnp_search_request[] = + "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "ST:upnp:rootdevice\r\n" + "MX:2\r\n" + "MAN:"ssdp:discover"\r\n" + "\r\n"; + + const DWORD timeout = 1000; + int len, address_len; + char buffer[2048]; + SOCKADDR_IN addr; + WSADATA wsa_data; + unsigned int i; + SOCKET s; + + upnp_gateway_connection.winsock_initialized = WSAStartup( MAKEWORD( 2, 2 ), &wsa_data ); + if ((s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP )) == -1) + { + ERR( "Failed to create socket, error %u.\n", WSAGetLastError() ); + return FALSE; + } + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) == SOCKET_ERROR) + { + ERR( "setsockopt(SO_RCVTIME0) failed, error %u.\n", WSAGetLastError() ); + closesocket( s ); + return FALSE; + } + addr.sin_family = AF_INET; + addr.sin_port = htons( 1900 ); + addr.sin_addr.S_un.S_addr = inet_addr( "239.255.255.250" ); + if (sendto( s, upnp_search_request, strlen( upnp_search_request ), 0, (SOCKADDR *)&addr, sizeof(addr) ) + == SOCKET_ERROR) + { + ERR( "sendto failed, error %u\n", WSAGetLastError() ); + closesocket( s ); + return FALSE; + } + /* Windows has a dedicated SSDP discovery service which maintains gateway device info and does + * not usually delay in get_StaticPortMappingCollection(). Although it may still delay depending + * on network connection state and always delays in IUPnPNAT_get_NATEventManager(). */ + FIXME( "Waiting for reply from router.\n" ); + for (i = 0; i < 2; ++i) + { + address_len = sizeof(addr); + len = recvfrom( s, buffer, sizeof(buffer) - 1, 0, (SOCKADDR *)&addr, &address_len ); + if (len == -1) + { + if (WSAGetLastError() != WSAETIMEDOUT) + { + WARN( "recvfrom error %u.\n", WSAGetLastError() ); + closesocket( s ); + return FALSE; + } + } + else break; + } + closesocket( s ); + if (i == 2) + { + TRACE( "No reply from router.\n" ); + return FALSE; + } + TRACE( "Received reply from gateway, len %d.\n", len ); + return TRUE; +} + +static BOOL grab_gateway_connection(void) +{ + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + if (!upnp_gateway_connection.refs && !init_gateway_connection()) + { + gateway_connection_cleanup(); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + return FALSE; + } + ++upnp_gateway_connection.refs; + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + return TRUE; +} + +static void release_gateway_connection(void) +{ + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + assert( upnp_gateway_connection.refs ); + if (!--upnp_gateway_connection.refs) + gateway_connection_cleanup(); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); +} + +struct static_port_mapping_collection +{ + IStaticPortMappingCollection IStaticPortMappingCollection_iface; + LONG refs; +}; + +static inline struct static_port_mapping_collection *impl_from_IStaticPortMappingCollection + ( IStaticPortMappingCollection *iface ) +{ + return CONTAINING_RECORD(iface, struct static_port_mapping_collection, IStaticPortMappingCollection_iface); +} + +static ULONG WINAPI static_ports_AddRef( + IStaticPortMappingCollection *iface ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + return InterlockedIncrement( &ports->refs ); +} + +static ULONG WINAPI static_ports_Release( + IStaticPortMappingCollection *iface ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + LONG refs = InterlockedDecrement( &ports->refs ); + if (!refs) + { + TRACE("destroying %p\n", ports); + release_gateway_connection(); + free( ports ); + } + return refs; +} + +static HRESULT WINAPI static_ports_QueryInterface( + IStaticPortMappingCollection *iface, + REFIID riid, + void **ppvObject ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + + TRACE("%p %s %p\n", ports, debugstr_guid( riid ), ppvObject ); + + if ( IsEqualGUID( riid, &IID_IStaticPortMappingCollection ) || + IsEqualGUID( riid, &IID_IDispatch ) || + IsEqualGUID( riid, &IID_IUnknown ) ) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + IStaticPortMappingCollection_AddRef( iface ); + return S_OK; +} + +static HRESULT WINAPI static_ports_GetTypeInfoCount( + IStaticPortMappingCollection *iface, + UINT *pctinfo ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + + TRACE("%p %p\n", ports, pctinfo); + *pctinfo = 1; + return S_OK; +} + +static HRESULT WINAPI static_ports_GetTypeInfo( + IStaticPortMappingCollection *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + + TRACE("%p %u %u %p\n", ports, iTInfo, lcid, ppTInfo); + return get_typeinfo( IStaticPortMappingCollection_tid, ppTInfo ); +} + +static HRESULT WINAPI static_ports_GetIDsOfNames( + IStaticPortMappingCollection *iface, + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p %s %p %u %u %p\n", ports, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); + + hr = get_typeinfo( IStaticPortMappingCollection_tid, &typeinfo ); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_GetIDsOfNames( typeinfo, rgszNames, cNames, rgDispId ); + ITypeInfo_Release( typeinfo ); + } + return hr; +} + +static HRESULT WINAPI static_ports_Invoke( + IStaticPortMappingCollection *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p %d %s %d %d %p %p %p %p\n", ports, dispIdMember, debugstr_guid(riid), + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + hr = get_typeinfo( IStaticPortMappingCollection_tid, &typeinfo ); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_Invoke( typeinfo, &ports->IStaticPortMappingCollection_iface, dispIdMember, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); + ITypeInfo_Release( typeinfo ); + } + return hr; +} + +static HRESULT WINAPI static_ports__NewEnum( + IStaticPortMappingCollection *iface, + IUnknown **ret ) +{ + FIXME( "iface %p, ret %p stub.\n", iface, ret ); + + if (ret) *ret = NULL; + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_get_Item( + IStaticPortMappingCollection *iface, + LONG port, + BSTR protocol, + IStaticPortMapping **mapping ) +{ + FIXME( "iface %p, port %d, protocol %s stub.\n", iface, port, debugstr_w(protocol) ); + + if (mapping) *mapping = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_get_Count( + IStaticPortMappingCollection *iface, + LONG *count ) +{ + FIXME( "iface %p, count %p stub.\n", iface, count ); + + if (count) *count = 0; + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_Remove( + IStaticPortMappingCollection *iface, + LONG port, + BSTR protocol ) +{ + FIXME( "iface %p, port %d, protocol %s stub.\n", iface, port, debugstr_w(protocol) ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_Add( + IStaticPortMappingCollection *iface, + LONG external, + BSTR protocol, + LONG internal, + BSTR client, + VARIANT_BOOL enabled, + BSTR description, + IStaticPortMapping **mapping ) +{ + FIXME( "iface %p, external %d, protocol %s, internal %d, client %s, enabled %d, descritption %s, mapping %p stub.\n", + iface, external, debugstr_w(protocol), internal, debugstr_w(client), enabled, debugstr_w(description), + mapping ); + + if (mapping) *mapping = NULL; + return E_NOTIMPL; +} + +static const IStaticPortMappingCollectionVtbl static_ports_vtbl = +{ + static_ports_QueryInterface, + static_ports_AddRef, + static_ports_Release, + static_ports_GetTypeInfoCount, + static_ports_GetTypeInfo, + static_ports_GetIDsOfNames, + static_ports_Invoke, + static_ports__NewEnum, + static_ports_get_Item, + static_ports_get_Count, + static_ports_Remove, + static_ports_Add, +}; + +static HRESULT static_port_mapping_collection_create(IStaticPortMappingCollection **object) +{ + struct static_port_mapping_collection *ports; + + if (!object) return E_POINTER; + if (!grab_gateway_connection()) + { + *object = NULL; + return S_OK; + } + if (!(ports = calloc( 1, sizeof(*ports) ))) + { + release_gateway_connection(); + return E_OUTOFMEMORY; + } + ports->refs = 1; + ports->IStaticPortMappingCollection_iface.lpVtbl = &static_ports_vtbl; + *object = &ports->IStaticPortMappingCollection_iface; + return S_OK; +} + typedef struct fw_port { INetFwOpenPort INetFwOpenPort_iface; @@ -716,10 +1056,10 @@ static HRESULT WINAPI upnpnat_Invoke(IUPnPNAT *iface, DISPID dispIdMember, REFII static HRESULT WINAPI upnpnat_get_StaticPortMappingCollection(IUPnPNAT *iface, IStaticPortMappingCollection **collection) { upnpnat *This = impl_from_IUPnPNAT( iface ); - FIXME("%p, %p\n", This, collection); - if(collection) - *collection = NULL; - return S_OK; + + TRACE("%p, %p\n", This, collection); + + return static_port_mapping_collection_create( collection ); }
static HRESULT WINAPI upnpnat_get_DynamicPortMappingCollection(IUPnPNAT *iface, IDynamicPortMappingCollection **collection) diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index 6abdcd7fb4e..19b6e3f6f2e 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -184,7 +184,8 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p
refcount = get_refcount((IUnknown *)ports); hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + if (FAILED(hr)) return;
hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/hnetcfg/port.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 89a3f571d45..fa866d874c9 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -27,6 +27,7 @@ #include "string.h" #include "assert.h" #include "winsock2.h" +#include "winhttp.h" #include "ole2.h" #include "netfw.h" #include "natupnp.h" @@ -40,11 +41,49 @@ static struct { LONG refs; BOOL winsock_initialized; + WCHAR locationW[256]; } upnp_gateway_connection;
static SRWLOCK upnp_gateway_connection_lock = SRWLOCK_INIT;
+static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned int location_size ) +{ + char *saveptr = NULL, *tok, *tok2; + unsigned int status; + + tok = strtok_s( response, "\n", &saveptr ); + if (!tok) return FALSE; + + /* HTTP/1.1 200 OK */ + tok2 = strtok( tok, " " ); + if (!tok2) return FALSE; + tok2 = strtok( NULL, " " ); + if (!tok2) return FALSE; + status = atoi( tok2 ); + if (status != HTTP_STATUS_OK) + { + WARN( "status %u.\n", status ); + return FALSE; + } + while ((tok = strtok_s( NULL, "\n", &saveptr ))) + { + tok2 = strtok( tok, " " ); + if (!tok2) continue; + if (!stricmp( tok2, "LOCATION:" )) + { + tok2 = strtok( NULL, " \r" ); + if (!tok2) + { + WARN( "Error parsing location.\n" ); + return FALSE; + } + return !!MultiByteToWideChar( CP_UTF8, 0, tok2, -1, locationW, location_size / 2 ); + } + } + return FALSE; +} + static void gateway_connection_cleanup(void) { TRACE( ".\n" ); @@ -118,6 +157,13 @@ static BOOL init_gateway_connection(void) return FALSE; } TRACE( "Received reply from gateway, len %d.\n", len ); + buffer[len] = 0; + if (!parse_search_response( buffer, upnp_gateway_connection.locationW, sizeof(upnp_gateway_connection.locationW) )) + { + WARN( "Error parsing response.\n" ); + return FALSE; + } + TRACE( "Gateway description location %s.\n", debugstr_w(upnp_gateway_connection.locationW) ); return TRUE; }
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/hnetcfg/Makefile.in | 2 +- dlls/hnetcfg/port.c | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in index 8d1f1b27ffe..8435de81f94 100644 --- a/dlls/hnetcfg/Makefile.in +++ b/dlls/hnetcfg/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = hnetcfg.dll IMPORTS = oleaut32 ole32 advapi32 mpr uuid -DELAYIMPORTS = ws2_32 +DELAYIMPORTS = ws2_32 winhttp EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \ diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index fa866d874c9..b1d5398a01a 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -42,6 +42,7 @@ static struct LONG refs; BOOL winsock_initialized; WCHAR locationW[256]; + HINTERNET session, connection; } upnp_gateway_connection;
@@ -84,9 +85,43 @@ static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned in return FALSE; }
+static BOOL open_gateway_connection(void) +{ + static const int timeout = 3000; + + WCHAR hostname[64], urlpath[128]; + URL_COMPONENTS url; + + memset( &url, 0, sizeof(url) ); + url.dwStructSize = sizeof(url); + url.lpszHostName = hostname; + url.dwHostNameLength = ARRAY_SIZE(hostname); + url.lpszUrlPath = urlpath; + url.dwUrlPathLength = ARRAY_SIZE(urlpath); + + if (!WinHttpCrackUrl( upnp_gateway_connection.locationW, 0, 0, &url )) return FALSE; + + upnp_gateway_connection.session = WinHttpOpen( L"hnetcfg", WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 ); + if (!upnp_gateway_connection.session) return FALSE; + if (!WinHttpSetTimeouts( upnp_gateway_connection.session, timeout, timeout, timeout, timeout )) + return FALSE; + + TRACE( "hostname %s, urlpath %s, port %u.\n", debugstr_w(hostname), debugstr_w(urlpath), url.nPort ); + upnp_gateway_connection.connection = WinHttpConnect ( upnp_gateway_connection.session, hostname, url.nPort, 0 ); + if (!upnp_gateway_connection.connection) + { + WARN( "WinHttpConnect error %u.\n", GetLastError() ); + return FALSE; + } + return TRUE; +} + static void gateway_connection_cleanup(void) { TRACE( ".\n" ); + WinHttpCloseHandle( upnp_gateway_connection.connection ); + WinHttpCloseHandle( upnp_gateway_connection.session ); if (upnp_gateway_connection.winsock_initialized) WSACleanup(); memset( &upnp_gateway_connection, 0, sizeof(upnp_gateway_connection) ); } @@ -164,6 +199,12 @@ static BOOL init_gateway_connection(void) return FALSE; } TRACE( "Gateway description location %s.\n", debugstr_w(upnp_gateway_connection.locationW) ); + if (!open_gateway_connection()) + { + WARN( "Error opening gateway connection.\n" ); + return FALSE; + } + TRACE( "Opened gateway connection.\n" ); return TRUE; }
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/hnetcfg/Makefile.in | 2 +- dlls/hnetcfg/port.c | 166 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 5 deletions(-)
diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in index 8435de81f94..926eec4e476 100644 --- a/dlls/hnetcfg/Makefile.in +++ b/dlls/hnetcfg/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = hnetcfg.dll IMPORTS = oleaut32 ole32 advapi32 mpr uuid -DELAYIMPORTS = ws2_32 winhttp +DELAYIMPORTS = ws2_32 winhttp shcore xmllite EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \ diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index b1d5398a01a..389e36f4d50 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -25,9 +25,12 @@ #include "winbase.h" #include "winuser.h" #include "string.h" +#include "initguid.h" #include "assert.h" #include "winsock2.h" #include "winhttp.h" +#include "shlwapi.h" +#include "xmllite.h" #include "ole2.h" #include "netfw.h" #include "natupnp.h" @@ -43,6 +46,9 @@ static struct BOOL winsock_initialized; WCHAR locationW[256]; HINTERNET session, connection; + WCHAR desc_urlpath[128]; + WCHAR control_url[256]; + unsigned int version; } upnp_gateway_connection;
@@ -85,19 +91,99 @@ static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned in return FALSE; }
+static BOOL parse_desc_xml( const char *desc_xml ) +{ + static const WCHAR urn_wanipconnection[] = L"urn:schemas-upnp-org:service:WANIPConnection:"; + WCHAR control_url[ARRAY_SIZE(upnp_gateway_connection.control_url)]; + BOOL service_type_matches, control_url_found, found = FALSE; + unsigned int version = 0; + XmlNodeType node_type; + IXmlReader *reader; + const WCHAR *value; + BOOL ret = FALSE; + IStream *stream; + HRESULT hr; + + if (!(stream = SHCreateMemStream( (BYTE *)desc_xml, strlen( desc_xml ) + 1 ))) return FALSE; + if (FAILED(hr = CreateXmlReader( &IID_IXmlReader, (void **)&reader, NULL ))) + { + IStream_Release( stream ); + return FALSE; + } + if (FAILED(hr = IXmlReader_SetInput( reader, (IUnknown*)stream ))) goto done; + + while (SUCCEEDED(IXmlReader_Read( reader, &node_type )) && node_type != XmlNodeType_None) + { + if (node_type != XmlNodeType_Element) continue; + + if (FAILED(IXmlReader_GetLocalName( reader, &value, NULL ))) goto done; + if (wcsicmp( value, L"service" )) continue; + control_url_found = service_type_matches = FALSE; + while (SUCCEEDED(IXmlReader_Read( reader, &node_type ))) + { + if (node_type != XmlNodeType_Element && node_type != XmlNodeType_EndElement) continue; + if (FAILED(IXmlReader_GetLocalName( reader, &value, NULL ))) + { + WARN( "IXmlReader_GetLocalName failed.\n" ); + goto done; + } + if (node_type == XmlNodeType_EndElement) + { + if (!wcsicmp( value, L"service" )) break; + continue; + } + if (!wcsicmp( value, L"serviceType" )) + { + if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done; + if (node_type != XmlNodeType_Text) goto done; + if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + if (wcsnicmp( value, urn_wanipconnection, ARRAY_SIZE(urn_wanipconnection) - 1 )) break; + version = _wtoi( value + ARRAY_SIZE(urn_wanipconnection) - 1 ); + service_type_matches = version >= 1; + } + else if (!wcsicmp( value, L"controlURL" )) + { + if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done; + if (node_type != XmlNodeType_Text) goto done; + if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + if (wcslen( value ) + 1 > ARRAY_SIZE(control_url)) goto done; + wcscpy( control_url, value ); + control_url_found = TRUE; + } + } + if (service_type_matches && control_url_found) + { + if (found) + { + FIXME( "Found another WANIPConnection service, ignoring.\n" ); + continue; + } + found = TRUE; + wcscpy( upnp_gateway_connection.control_url, control_url ); + upnp_gateway_connection.version = version; + } + } + + ret = found; +done: + IXmlReader_Release( reader ); + IStream_Release( stream ); + return ret; +} + static BOOL open_gateway_connection(void) { static const int timeout = 3000;
- WCHAR hostname[64], urlpath[128]; + WCHAR hostname[64]; URL_COMPONENTS url;
memset( &url, 0, sizeof(url) ); url.dwStructSize = sizeof(url); url.lpszHostName = hostname; url.dwHostNameLength = ARRAY_SIZE(hostname); - url.lpszUrlPath = urlpath; - url.dwUrlPathLength = ARRAY_SIZE(urlpath); + url.lpszUrlPath = upnp_gateway_connection.desc_urlpath; + url.dwUrlPathLength = ARRAY_SIZE(upnp_gateway_connection.desc_urlpath);
if (!WinHttpCrackUrl( upnp_gateway_connection.locationW, 0, 0, &url )) return FALSE;
@@ -107,7 +193,8 @@ static BOOL open_gateway_connection(void) if (!WinHttpSetTimeouts( upnp_gateway_connection.session, timeout, timeout, timeout, timeout )) return FALSE;
- TRACE( "hostname %s, urlpath %s, port %u.\n", debugstr_w(hostname), debugstr_w(urlpath), url.nPort ); + TRACE( "hostname %s, urlpath %s, port %u.\n", + debugstr_w(hostname), debugstr_w(upnp_gateway_connection.desc_urlpath), url.nPort ); upnp_gateway_connection.connection = WinHttpConnect ( upnp_gateway_connection.session, hostname, url.nPort, 0 ); if (!upnp_gateway_connection.connection) { @@ -117,6 +204,69 @@ static BOOL open_gateway_connection(void) return TRUE; }
+static BOOL get_control_url(void) +{ + static const WCHAR *accept_types[] = + { + L"text/xml", + NULL + }; + unsigned int desc_xml_size, offset; + DWORD size, status = 0; + HINTERNET request; + char *desc_xml; + BOOL ret; + + request = WinHttpOpenRequest( upnp_gateway_connection.connection, NULL, upnp_gateway_connection.desc_urlpath, NULL, + WINHTTP_NO_REFERER, accept_types, 0 ); + if (!request) return FALSE; + + if (!WinHttpSendRequest( request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0 )) + { + WARN( "Error sending request %u.\n", GetLastError() ); + WinHttpCloseHandle( request ); + return FALSE; + } + if (!WinHttpReceiveResponse(request, NULL)) + { + WARN( "Error receiving response %u.\n", GetLastError() ); + WinHttpCloseHandle( request ); + return FALSE; + } + size = sizeof(status); + if (!WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, &status, &size, NULL) || status != HTTP_STATUS_OK ) + { + WARN( "Error response from server, error %u, http status %u.\n", GetLastError(), status ); + WinHttpCloseHandle( request ); + return FALSE; + } + desc_xml_size = 1024; + desc_xml = malloc( desc_xml_size ); + offset = 0; + while (WinHttpReadData( request, desc_xml + offset, desc_xml_size - offset - 1, &size ) && size) + { + offset += size; + if (offset + 1 == desc_xml_size) + { + char *new; + + desc_xml_size *= 2; + if (!(new = realloc( desc_xml, desc_xml_size ))) + { + ERR( "No memory.\n" ); + break; + } + desc_xml = new; + } + } + desc_xml[offset] = 0; + WinHttpCloseHandle( request ); + ret = parse_desc_xml( desc_xml ); + free( desc_xml ); + return ret; +} + static void gateway_connection_cleanup(void) { TRACE( ".\n" ); @@ -205,6 +355,14 @@ static BOOL init_gateway_connection(void) return FALSE; } TRACE( "Opened gateway connection.\n" ); + if (!get_control_url()) + { + WARN( "Could not get_control URL.\n" ); + gateway_connection_cleanup(); + return FALSE; + } + TRACE( "control_url %s, version %u.\n", debugstr_w(upnp_gateway_connection.control_url), + upnp_gateway_connection.version ); return TRUE; }