From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/Makefile.in | 2 +- dlls/ws2_32/protocol.c | 240 +++++++++++++++++++++++++++++++++-- dlls/ws2_32/tests/protocol.c | 4 +- dlls/ws2_32/ws2_32_private.h | 2 + 4 files changed, 235 insertions(+), 13 deletions(-)
diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in index e80def64881..10faa56759c 100644 --- a/dlls/ws2_32/Makefile.in +++ b/dlls/ws2_32/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -D_WS2_32_ MODULE = ws2_32.dll UNIXLIB = ws2_32.so IMPORTLIB = ws2_32 -DELAYIMPORTS = dnsapi advapi32 iphlpapi user32 +DELAYIMPORTS = dnsapi advapi32 iphlpapi user32 bluetoothapis UNIX_LIBS = $(PTHREAD_LIBS)
SOURCES = \ diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 2699593a2f3..27a20f98eee 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -24,6 +24,8 @@
#include "ws2_32_private.h"
+#include <wine/exception.h> + WINE_DEFAULT_DEBUG_CHANNEL(winsock); WINE_DECLARE_DEBUG_CHANNEL(winediag);
@@ -2073,35 +2075,253 @@ int WINAPI WSAGetServiceClassNameByClassIdW( GUID *class, WCHAR *service, DWORD return -1; }
+/* NS_BTH support */ +struct ws_bth_query_device +{ + BTH_DEVICE_INFO_LIST *list; + SIZE_T idx; +}; + +struct ws_bth_query_ctx +{ + DWORD flags; + union { + struct ws_bth_query_device device; + } data; +}; + +#define WS_LOOKUP_SERVICE_HANDLE_MAGIC 0x721e6cd9 + +union ws_lookup_service_data +{ + struct ws_bth_query_ctx bth; +}; + +struct ws_lookup_service_ctx +{ + DWORD magic; + DWORD namespace; + union ws_lookup_service_data data; +}; + +static DWORD bth_for_all_radios( void (*callback)( HANDLE radio, void *data ), void *data ) +{ + BLUETOOTH_FIND_RADIO_PARAMS params = {0}; + HBLUETOOTH_RADIO_FIND find; + HANDLE radio; + DWORD ret; + + params.dwSize = sizeof( params ); + find = BluetoothFindFirstRadio( ¶ms, &radio ); + if (!find) + return GetLastError(); + do { + callback( radio, data ); + CloseHandle( radio ); + } while (BluetoothFindNextRadio( find, &radio )); + ret = GetLastError(); + BluetoothFindRadioClose( find ); + return ret == ERROR_NO_MORE_ITEMS ? 0 : ret; +} + +static ULONG bth_device_info_list_size( ULONG num_devices ) +{ + BTH_DEVICE_INFO_LIST *list; + return sizeof( *list ) + (num_devices - 1) * sizeof( list->deviceList[0] ); +} + +static void bth_radio_append_device_list( HANDLE radio, void *data ) +{ + ULONG num_devices = 1; + BTH_DEVICE_INFO_LIST *final_list = *(BTH_DEVICE_INFO_LIST **)data, *list, **ret = data; + + for (;;) + { + DWORD size, bytes; + + size = bth_device_info_list_size( num_devices ); + list = calloc( 1, size ); + if (!list) + return; + if (!DeviceIoControl( radio, IOCTL_BTH_GET_DEVICE_INFO, NULL, 0, list, size, &bytes, NULL ) + && GetLastError() != ERROR_INVALID_USER_BUFFER) + { + free( list ); + ERR( "Failed to get device list for radio %p: %lu\n", radio, GetLastError() ); + return; + } + if (!list->numOfDevices) + { + free( list ); + return; + } + if (num_devices == list->numOfDevices) + break; + + /* The buffer was not properly sized, try again. */ + num_devices = list->numOfDevices; + free( list ); + } + if (!final_list && !(final_list = calloc( 1, sizeof( *final_list )))) + { + free( list ); + return; + } + else if (final_list) + { + void *ptr; + + ptr = realloc( final_list, bth_device_info_list_size( (final_list)->numOfDevices + list->numOfDevices ) ); + if (!ptr) + { + free( list ); + return; + } + final_list = ptr; + } + + memcpy( &final_list->deviceList[(final_list)->numOfDevices], list->deviceList, + sizeof( list->deviceList[0] ) * list->numOfDevices ); + final_list->numOfDevices += list->numOfDevices; + *ret = final_list; + free( list ); +} + +static INT bth_lookup_devices( const BLOB *blob, DWORD flags, struct ws_bth_query_device *query ) +{ + DWORD err; + + TRACE( "(%p, %#lx, %p)\n", blob, flags, query ); + + if (flags & LUP_FLUSHCACHE) + FIXME( "Device inquiry is not supported\n" ); + + query->idx = 0; + query->list = NULL; + err = bth_for_all_radios( bth_radio_append_device_list, &query->list ); + if (err) + { + if (query->list) + free( query->list ); + WSASetLastError( err == ERROR_NO_MORE_ITEMS ? WSASERVICE_NOT_FOUND : err ); + return -1; + } + WSASetLastError( query->list ? ERROR_SUCCESS : WSASERVICE_NOT_FOUND ); + return query->list ? 0 : -1; +} + +static INT ws_bth_lookup_service_begin( WSAQUERYSETA *search, DWORD flags, struct ws_bth_query_ctx *handle ) +{ + TRACE( "(%p, %#lx, %p)\n", search, flags, handle ); + + assert( search->dwNameSpace == NS_BTH ); + handle->flags = flags; + + if (flags & LUP_CONTAINERS) + return bth_lookup_devices( search->lpBlob, flags, &handle->data.device ); + + FIXME( "Service inquiry is not supported\n" ); + WSASetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; +} + +static void ws_bth_lookup_service_end( struct ws_bth_query_ctx *handle );
/*********************************************************************** * WSALookupServiceBeginA (ws2_32.@) */ -int WINAPI WSALookupServiceBeginA( WSAQUERYSETA *query, DWORD flags, HANDLE *lookup ) +int WINAPI WSALookupServiceBeginA( WSAQUERYSETA *query, DWORD flags, HANDLE *lookup_handle ) { - FIXME( "(%p %#lx %p) Stub!\n", query, flags, lookup ); - SetLastError( WSA_NOT_ENOUGH_MEMORY ); - return -1; -} + struct ws_lookup_service_ctx *lookup = NULL; + union ws_lookup_service_data lookup_data = {0}; + + TRACE( "(%p %#lx %p)\n", query, flags, lookup_handle ); + + if (!query || query->dwSize != sizeof( *query ) || !lookup_handle) + { + WSASetLastError( WSAEFAULT ); + return -1; + } + switch (query->dwNameSpace) + { + case NS_BTH: + if (ws_bth_lookup_service_begin( query, flags, &lookup_data.bth )) + return -1; + break; + default: + FIXME( "Unsupported dwNameSpace: %lu\n", query->dwNameSpace ); + SetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; + } + if (!(lookup = calloc( 1, sizeof( *lookup ) ))) + { + ws_bth_lookup_service_end( &lookup_data.bth ); + WSASetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; + }
+ lookup->magic = WS_LOOKUP_SERVICE_HANDLE_MAGIC; + lookup->namespace = query->dwNameSpace; + lookup->data = lookup_data; + *lookup_handle = lookup; + + return 0; +}
/*********************************************************************** * WSALookupServiceBeginW (ws2_32.@) */ int WINAPI WSALookupServiceBeginW( WSAQUERYSETW *query, DWORD flags, HANDLE *lookup ) { - FIXME( "(%p %#lx %p) Stub!\n", query, flags, lookup ); - SetLastError( WSA_NOT_ENOUGH_MEMORY ); - return -1; + WSAQUERYSETA queryA = {0}; + + TRACE( "(%p %#lx %p)\n", query, flags, lookup ); + + if (!query || query->dwSize != sizeof( *query ) || !lookup) + { + WSASetLastError( WSAEFAULT ); + return -1; + } + + /* These are the only fields that we use right now. */ + queryA.dwSize = sizeof( queryA ); + queryA.dwNameSpace = query->dwNameSpace; + queryA.lpBlob = query->lpBlob; + return WSALookupServiceBeginA( &queryA, flags, lookup ); }
+static void ws_bth_lookup_service_end( struct ws_bth_query_ctx *handle ) +{ + if (handle->flags & LUP_CONTAINERS) + free( handle->data.device.list ); +}
/*********************************************************************** * WSALookupServiceEnd (ws2_32.@) */ -int WINAPI WSALookupServiceEnd( HANDLE lookup ) +int WINAPI WSALookupServiceEnd( HANDLE lookup_handle ) { - FIXME("(%p) Stub!\n", lookup ); + struct ws_lookup_service_ctx *lookup = lookup_handle; + + TRACE( "(%p)\n", lookup_handle ); + + if (!lookup_handle || lookup->magic != WS_LOOKUP_SERVICE_HANDLE_MAGIC) + { + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; + } + + switch (lookup->namespace) + { + case NS_BTH: + ws_bth_lookup_service_end( &lookup->data.bth ); + break; + default: + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; + } + + free( lookup_handle ); return 0; }
diff --git a/dlls/ws2_32/tests/protocol.c b/dlls/ws2_32/tests/protocol.c index 7bea851eadb..fa26d70176c 100644 --- a/dlls/ws2_32/tests/protocol.c +++ b/dlls/ws2_32/tests/protocol.c @@ -687,8 +687,8 @@ static void test_WSALookupService_devices( void ) SetLastError( 0xdeadbeef ); ret = WSALookupServiceBeginA( &queryA, init_flags, &lookup_handle ); err = WSAGetLastError(); - todo_wine ok( !ret || err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); - todo_wine ok( lookup_handle || err == WSASERVICE_NOT_FOUND, "Expected lookup_handle to be non-NULL\n" ); + ok( !ret || err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); + ok( lookup_handle || err == WSASERVICE_NOT_FOUND, "Expected lookup_handle to be non-NULL\n" ); if (!lookup_handle) { skip( "WSALookupServiceBeginA failed\n" ); diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 9a4d0794151..179a8f02f40 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -38,6 +38,8 @@ #include "mswsock.h" #include "bthsdpdef.h" #include "bluetoothapis.h" +#include "bthdef.h" +#include "bthioctl.h" #include "ws2bth.h" #include "ws2tcpip.h" #include "ws2spi.h"