[PATCH 3/6] hnetcfg: Return stub interface from upnpnat_get_StaticPortMappingCollection() if UPNP IGD is found.
Paul Gofman
pgofman at codeweavers.com
Tue Feb 1 04:49:21 CST 2022
Signed-off-by: Paul Gofman <pgofman at 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);
--
2.34.1
More information about the wine-devel
mailing list