This MR adds an initial implementation of the winsock `WSALookupsService*` methods for performing Bluetooth device discovery (`LUP_CONTAINERS`).
Pending !7472, the code will also eventually support performing device inquiry scans.
-- v14: ws2_32: Implement WSALookupServiceNext for Bluetooth device discovery. ws2_32: Implement WSALookupServiceBegin for Bluetooth device discovery. ws2_32/tests: Add tests for Bluetooth device discovery in WSALookupServiceBegin/Next.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/tests/Makefile.in | 2 +- dlls/ws2_32/tests/protocol.c | 347 ++++++++++++++++++++++++++++++++++ include/winsock2.h | 5 + include/ws2bth.h | 6 + 4 files changed, 359 insertions(+), 1 deletion(-)
diff --git a/dlls/ws2_32/tests/Makefile.in b/dlls/ws2_32/tests/Makefile.in index 3ca9be37a78..f371e680183 100644 --- a/dlls/ws2_32/tests/Makefile.in +++ b/dlls/ws2_32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = ws2_32.dll -IMPORTS = iphlpapi ws2_32 user32 +IMPORTS = iphlpapi ws2_32 user32 bluetoothapis
SOURCES = \ afd.c \ diff --git a/dlls/ws2_32/tests/protocol.c b/dlls/ws2_32/tests/protocol.c index 09c56439ada..0542aad9ca8 100644 --- a/dlls/ws2_32/tests/protocol.c +++ b/dlls/ws2_32/tests/protocol.c @@ -536,6 +536,351 @@ static void test_WSALookupService(void) ok(!ret, "WSALookupServiceEnd failed unexpectedly\n"); }
+static DWORD get_nth_lookup_flags( SIZE_T n, const DWORD *flags, SIZE_T len ) +{ + SIZE_T i; + DWORD result = 0; + + if (!n) + return 0; + + for (i = 0; i < len; i++) + if (n & (1 << i)) + result |= flags[i]; + + return result; +} + +static void test_WSALookupServiceNext_bth_devices( HANDLE lookup_handle, DWORD flags, BOOL verbose ) +{ + WSAQUERYSETA *results; + DWORD buf_len, i = 0; + + buf_len = sizeof( *results ); + for (;;) + { + INT ret, err; + const BTH_DEVICE_INFO *info = NULL; + + results = calloc( 1, buf_len ); + results->dwSize = sizeof( *results ); + + SetLastError( 0xdeadbeef ); + ret = WSALookupServiceNextA( lookup_handle, flags, &buf_len, results ); + err = WSAGetLastError(); + + winetest_push_context( "device %lu", i); + if (ret) + { + ok( ret == -1, "%d != -1\n", ret ); + todo_wine ok( err == WSA_E_NO_MORE || err == WSAEFAULT, "WSALookupServiceNextA failed: %d\n", err ); + if (err != WSAEFAULT) + { + free( results ); + winetest_pop_context(); + return; + } + ok( buf_len >= sizeof( *results ), "Expected %lu to be greater than %lu\n", buf_len, (DWORD)sizeof( *results ) ); + free( results ); + winetest_pop_context(); + continue; + } + i++; + + if (flags & LUP_RETURN_NAME) + { + todo_wine ok( !!results->lpszServiceInstanceName, "Expected lpszServiceInstanceName to not be NULL\n" ); + if (verbose) + trace( "Name: %s\n", debugstr_a( results->lpszServiceInstanceName ) ); + } + + if (flags & LUP_RETURN_TYPE) + { + todo_wine ok( !!results->lpServiceClassId, "Expected lpServiceClassId to not be NULL\n" ); + if (results->lpServiceClassId && verbose) + trace( "CoD: %#lx\n", results->lpServiceClassId->Data1 ); + } + + if (flags & LUP_RETURN_BLOB) + { + todo_wine ok( !!results->lpBlob, "Expected lpBlob to not be NULL\n" ); + if (results->lpBlob) + { + info = (BTH_DEVICE_INFO *)results->lpBlob->pBlobData; + ok( results->lpBlob->cbSize >= sizeof( *info ), "%lu should be at least %lu\n", + results->lpBlob->cbSize, (DWORD)sizeof( *info ) ); + ok( !!info, "Expected pBlobData to not be NULL\n" ); + if (info) + { + if (results->lpszServiceInstanceName) + ok( !strcmp( info->name, results->lpszServiceInstanceName ), "%s != %s", debugstr_a( info->name ), + debugstr_a( results->lpszServiceInstanceName )); + if (verbose) + trace( "Device Flags: %#lx\n", info->flags ); + if (results->lpServiceClassId) + ok( info->classOfDevice == results->lpServiceClassId->Data1, "%lu != %lu\n", info->classOfDevice, + results->lpServiceClassId->Data1 ); + } + } + } + + if (flags & LUP_RETURN_ADDR) + { + todo_wine ok( !!results->lpcsaBuffer, "Expected lpcsaBuffer to not be NULL\n" ); + if (results->lpcsaBuffer) + { + const SOCKET_ADDRESS *remote_sock_addr = &results->lpcsaBuffer->RemoteAddr; + const SOCKADDR_BTH *remote_bth_addr = (SOCKADDR_BTH *)remote_sock_addr->lpSockaddr; + const SOCKET_ADDRESS *local_sock_addr = &results->lpcsaBuffer->LocalAddr; + const SOCKADDR_BTH *local_bth_addr = (SOCKADDR_BTH *)local_sock_addr->lpSockaddr; + + ok( remote_sock_addr->iSockaddrLength == sizeof( *remote_bth_addr ), "%d != %lu\n", + remote_sock_addr->iSockaddrLength, (DWORD)sizeof( *remote_bth_addr ) ); + ok( !!remote_bth_addr, "Expected RemoteAddr to not be NULL\n" ); + if (remote_bth_addr && remote_sock_addr->iSockaddrLength == sizeof( *remote_bth_addr )) + { + ok( remote_bth_addr->addressFamily == AF_BTH, "%d != %d\n", remote_bth_addr->addressFamily, AF_BTH ); + if (info && info->flags & BDIF_ADDRESS) + ok( remote_bth_addr->btAddr == info->address, "%I64x != %I64x\n", remote_bth_addr->btAddr, info->address ); + } + + if (flags & LUP_RES_SERVICE) + { + ok( local_sock_addr->iSockaddrLength == sizeof( *local_bth_addr ), "%d != %lu\n", + local_sock_addr->iSockaddrLength, (DWORD)sizeof( *local_bth_addr )); + ok( !!local_bth_addr, "Expected LocalAddr to not be NULL\n" ); + if (local_bth_addr && local_sock_addr->iSockaddrLength == sizeof( *local_bth_addr )) + { + ok( local_bth_addr->addressFamily == AF_BTH, "%d != %d\n", local_bth_addr->addressFamily, AF_BTH ); + todo_wine ok( local_bth_addr->btAddr, "Expected btAddr to not be zero\n" ); + } + } + } + } + + winetest_pop_context(); + free( results ); + } +} + +static const DWORD device_lookup_flags[] = {LUP_RETURN_TYPE, LUP_RETURN_NAME, LUP_RETURN_BLOB, LUP_RETURN_ADDR, + LUP_RES_SERVICE}; + +static void test_WSALookupService_bth_devices( void ) +{ + DWORD all_flags = LUP_RETURN_TYPE | LUP_RETURN_NAME | LUP_RETURN_BLOB | LUP_RETURN_ADDR | LUP_RES_SERVICE; + /* For NS_BTH, WSALookupService only looks for LUP_CONTAINERS. If this flag is set, then it performs device + * inquiry. Otherwise, it performs service discovery. Other flags seem to be ignored. */ + DWORD init_flags = LUP_CONTAINERS | LUP_NOCONTAINERS, i = 0, buf_len, orig_len; + BTH_QUERY_DEVICE query_device_params = {0}; + WSAQUERYSETA queryA = {0}, *results; + BLOB device_inquiry_blob = {0}; + HANDLE lookup_handle; + INT ret, err; + + queryA.dwSize = sizeof( queryA ); + queryA.dwNameSpace = NS_BTH; + if (winetest_interactive) + init_flags |= LUP_FLUSHCACHE; + + device_inquiry_blob.cbSize = sizeof( query_device_params ); + query_device_params.length = 5; + + for (i = 1; i < 1 << ARRAY_SIZE( device_lookup_flags ); i++) + { + DWORD next_flags = get_nth_lookup_flags( i, device_lookup_flags, ARRAY_SIZE( device_lookup_flags )); + lookup_handle = NULL; + + switch (i) + { + case 1: + /* WSASLookupServiceBeginA will ignore an invalid or NULL BLOB and perform device inquiry with the default + * timeout of 6 seconds. */ + queryA.lpBlob = NULL; + break; + case 2: + queryA.lpBlob = &device_inquiry_blob; + queryA.lpBlob->cbSize += 1; + device_inquiry_blob.pBlobData = (BYTE *)&query_device_params; + break; + case 3: + queryA.lpBlob->cbSize = sizeof( query_device_params ); + queryA.lpBlob->pBlobData = NULL; + break; + default: + queryA.lpBlob = &device_inquiry_blob; + queryA.lpBlob->cbSize = sizeof( query_device_params ); + queryA.lpBlob->pBlobData = (BYTE *)&query_device_params; + break; + } + winetest_push_context( "flags=%#lx", next_flags ); + SetLastError( 0xdeadbeef ); + + ret = WSALookupServiceBeginA( &queryA, init_flags, &lookup_handle ); + err = WSAGetLastError(); + if (ret) + { + /* WSASERVICE_NOT_FOUND indicates that no Bluetooth devices were found. */ + todo_wine ok( err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); + ok( !lookup_handle, "Handle should not have been filled\n"); + skip( "No Bluetooth devices found\n" ); + winetest_pop_context(); + continue; + } + + ok( !!lookup_handle, "Handle was not filled\n"); + test_WSALookupServiceNext_bth_devices( lookup_handle, next_flags, next_flags == all_flags ); + + ok( !WSALookupServiceEnd( lookup_handle ), "WSALookupServiceEnd failed: %d\n", WSAGetLastError() ); + winetest_pop_context(); + } + + /* Test that WSALookupServiceNext does not modify the buffer partially when there's insufficient space for other + * params. */ + lookup_handle = NULL; + SetLastError( 0xdeadbeef ); + ret = WSALookupServiceBeginA( &queryA, init_flags, &lookup_handle ); + err = WSAGetLastError(); + if (ret) + { + todo_wine ok( err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", err ); + ok( !lookup_handle, "Handle should not have been filled\n"); + skip( "No Bluetooth devices found\n" ); + return; + } + + todo_wine ok( !!lookup_handle, "Handle was not filled\n" ); + /* Missing space for a BTH_DEVICE_INFO */ + orig_len = buf_len = sizeof( *results ) + sizeof( GUID ) + sizeof( BLOB ); + results = calloc( 1, buf_len ); + results->dwSize = sizeof( *results ); + SetLastError( 0xdeadbeef ); + ret = WSALookupServiceNextA( lookup_handle, LUP_RETURN_TYPE | LUP_RETURN_BLOB, &buf_len, results ); + err = WSAGetLastError(); + ok( ret == -1, "Expected WSALookupServiceNextA to fail\n" ); + todo_wine ok( err == WSAEFAULT, "%d != %d", err, WSAEFAULT ); + todo_wine ok( buf_len > orig_len, "%ld should be greater than %ld\n", buf_len, orig_len ); + ok( !results->lpServiceClassId, "lpServiceClassId should not have been filled\n" ); + ok( !results->lpBlob, "lpBlob should not have been filled\n" ); + free( results ); + ok( !WSALookupServiceEnd( lookup_handle ), "WSALookupServiceEnd failed: %d\n", WSAGetLastError() ); +} + +static void test_WSALookupServiceNext_bth_services( HANDLE lookup_handle ) +{ + WSAQUERYSETA *results; + DWORD buf_len, i = 0; + + buf_len = sizeof( *results ); + for (;;) + { + INT ret, err; + + results = calloc( 1, buf_len ); + results->dwSize = sizeof( *results ); + + SetLastError( 0xdeadbeef ); + ret = WSALookupServiceNextA( lookup_handle, LUP_RETURN_NAME, &buf_len, results ); + err = WSAGetLastError(); + + winetest_push_context( "service %lu", i ); + if (ret) + { + ok( ret == -1, "%d != -1\n", ret ); + ok( err == WSA_E_NO_MORE || err == WSAEFAULT, "WSALookupServiceNextA failed: %d\n", err ); + if (err != WSAEFAULT) + { + free( results ); + winetest_pop_context(); + return; + } + ok( buf_len >= sizeof( *results ), "Expected %lu to be greater than %lu\n", buf_len, (DWORD)sizeof( *results ) ); + free( results ); + winetest_pop_context(); + continue; + } + + i++; + ok( !!results->lpszServiceInstanceName, "Expected lpszServiceInstanceName to not be NULL\n" ); + if (results->lpszServiceInstanceName) + trace( "Service class ID: %s\n", debugstr_a( results->lpszServiceInstanceName ) ); + winetest_pop_context(); + free( results ); + } +} + +static void test_WSALookupService_bth_services( void ) +{ + GUID L2CAP_UUID = {0x0100, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}}; + BLUETOOTH_FIND_RADIO_PARAMS find_params = {.dwSize = sizeof( find_params )}; + BLUETOOTH_RADIO_INFO radio_info = {0}; + HBLUETOOTH_RADIO_FIND radio_find; + SOCKADDR_BTH bth_addr = {0}; + WSAQUERYSETA query = {0}; + char addr_str[64]; + HANDLE radio, lookup = NULL; + DWORD ret, len = sizeof( addr_str ), init_flags = 0; + + + radio_find = BluetoothFindFirstRadio( &find_params, &radio ); + ret = GetLastError(); + if (!radio_find) + { + ok( ret == ERROR_NO_MORE_ITEMS, "BluetoothFindFirstRadio failed with %lu\n", ret ); + skip( "No Bluetooth radios found.\n" ); + return; + } + + radio_info.dwSize = sizeof( radio_info ); + ret = BluetoothGetRadioInfo( radio, &radio_info ); + CloseHandle( radio ); + ok( !ret, "BluetoothGetRadioInfo failed: %lu\n", ret ); + if (ret) + { + skip( "BluetoothGetRadioInfo failed.\n" ); + return; + } + + bth_addr.addressFamily = AF_BTH; + bth_addr.btAddr = radio_info.address.ullLong; + addr_str[0] = 0; + ret = WSAAddressToStringA( (SOCKADDR *)&bth_addr, sizeof( bth_addr ), NULL, addr_str, &len ); + ok( !ret, "WSAAddressToStringA failed: %d\n", WSAGetLastError() ); + + + query.dwSize = sizeof( query ); + query.dwNameSpace = NS_BTH; + query.lpServiceClassId = &L2CAP_UUID; + if (winetest_interactive) + init_flags |= LUP_FLUSHCACHE; + query.lpszContext = addr_str; + + ret = WSALookupServiceBeginA( &query, init_flags, &lookup ); + if (ret) + { + todo_wine ok( ret == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); + skip( "WSALookupServiceBeginA failed.\n" ); + return; + } + + test_WSALookupServiceNext_bth_services( lookup ); + ret = WSALookupServiceEnd( lookup ); + ok( !ret, "WSALookupServiceEnd failed: %d\n", WSAGetLastError() ); + + /* As with device discovery, LUP_NOCONTAINERS is ignored here as well. */ + ret = WSALookupServiceBeginA( &query, init_flags | LUP_NOCONTAINERS, &lookup ); + if (ret) + { + todo_wine ok( ret == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); + skip( "WSALookupServiceBeginA failed.\n" ); + return; + } + + test_WSALookupServiceNext_bth_services( lookup ); + ret = WSALookupServiceEnd( lookup ); + ok( !ret, "WSALookupServiceEnd failed: %d\n", WSAGetLastError() ); +} + #define WM_ASYNCCOMPLETE (WM_USER + 100) static HWND create_async_message_window(void) { @@ -3154,6 +3499,8 @@ START_TEST( protocol )
test_getservbyname(); test_WSALookupService(); + test_WSALookupService_bth_devices(); + test_WSALookupService_bth_services();
test_inet_ntoa(); test_inet_addr(); diff --git a/include/winsock2.h b/include/winsock2.h index f7b88322f49..8e1e5800a96 100644 --- a/include/winsock2.h +++ b/include/winsock2.h @@ -468,6 +468,8 @@ extern "C" {
/* Constants for WSALookupServiceBegin() */ #define LUP_DEEP 0x0001 +#define LUP_CONTAINERS 0x0002 +#define LUP_NOCONTAINERS 0x0004 #define LUP_RETURN_NAME 0x0010 #define LUP_RETURN_TYPE 0x0020 #define LUP_RETURN_VERSION 0x0040 @@ -476,6 +478,9 @@ extern "C" { #define LUP_RETURN_BLOB 0x0200 #define LUP_RETURN_ALIASES 0x0400 #define LUP_RETURN_QUERY_STRING 0x0800 +#define LUP_FLUSHCACHE 0x1000 +#define LUP_FLUSHPREVIOUS 0x2000 +#define LUP_RES_SERVICE 0x8000 #define LUP_RETURN_ALL (LUP_RETURN_ADDR|LUP_RETURN_BLOB|LUP_RETURN_ALIASES|LUP_RETURN_QUERY_STRING \ |LUP_RETURN_NAME|LUP_RETURN_TYPE|LUP_RETURN_VERSION|LUP_RETURN_COMMENT)
diff --git a/include/ws2bth.h b/include/ws2bth.h index ee28f0122cc..d6f7a328399 100644 --- a/include/ws2bth.h +++ b/include/ws2bth.h @@ -29,6 +29,12 @@ typedef struct _SOCKADDR_BTH ULONG port; } SOCKADDR_BTH, *PSOCKADDR_BTH;
+typedef struct _BTH_QUERY_DEVICE +{ + ULONG LAP; + UCHAR length; +} BTH_QUERY_DEVICE, *PBTH_QUERY_DEVICE, BTHNS_INQUIRYBLOB, *PBTHNS_INQUIRYBLOB; + #include <poppack.h>
#endif /* __WS2BTH_H__ */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/Makefile.in | 2 +- dlls/ws2_32/protocol.c | 352 +++++++++++++++++++++++++++++++++-- dlls/ws2_32/tests/protocol.c | 26 +-- dlls/ws2_32/ws2_32_private.h | 3 + 4 files changed, 359 insertions(+), 24 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..873e536f825 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -22,6 +22,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "wine/winebth.h" #include "ws2_32_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winsock); @@ -2073,35 +2074,364 @@ 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 +{ + unsigned int lookup_devices : 1; + union { + struct ws_bth_query_device device; + } data; +}; + +struct ws_lookup_service_ctx +{ + DWORD namespace; + union { + struct ws_bth_query_ctx bth; + } 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; +} + +struct bth_device_discovery_data +{ + unsigned int device_inquiry : 1; + DWORD timeout_ms; + BTH_DEVICE_INFO_LIST **list; +}; + +static void bth_radio_append_device_list( HANDLE radio, void *data ) +{ + ULONG num_devices = 1; + struct bth_device_discovery_data *params = data; + BTH_DEVICE_INFO_LIST *final_list = *params->list, *list, **ret = params->list; + + if (params->device_inquiry) + { + DWORD bytes; + + if (DeviceIoControl( radio, IOCTL_WINEBTH_RADIO_START_DISCOVERY, NULL, 0, NULL, 0, &bytes, NULL )) + { + Sleep( params->timeout_ms ); + if (!DeviceIoControl( radio, IOCTL_WINEBTH_RADIO_STOP_DISCOVERY, NULL, 0, NULL, 0, &bytes, NULL )) + ERR( "Failed to stop device inquiry scan on radio %p: %lu\n", radio, GetLastError() ); + } + else + ERR( "Failed to start device inquiry scan on radio %p: %lu\n", radio, GetLastError() ); + + } + + for (;;) + { + DWORD size, bytes; + + size = offsetof( BTH_DEVICE_INFO_LIST, deviceList[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, offsetof( BTH_DEVICE_INFO_LIST, + deviceList[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 ) +{ + struct bth_device_discovery_data data = {0}; + DWORD err; + + TRACE( "(%p, %#lx, %p)\n", blob, flags, query ); + + + if (flags & LUP_FLUSHCACHE) + { + DWORD duration_ms = 6000; + const BTH_QUERY_DEVICE *query; + + if (blob && blob->cbSize == sizeof( *query ) && blob->pBlobData) + { + query = (BTH_QUERY_DEVICE *)blob->pBlobData; + /* Windows caps the duration at 60 seconds. */ + duration_ms = min( query->length, 60 ) * 1000; + } + data.device_inquiry = 1; + data.timeout_ms = duration_ms; + } + + query->idx = 0; + query->list = NULL; + data.list = &query->list; + err = bth_for_all_radios( bth_radio_append_device_list, &data ); + if (err) + { + 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; +} + +/* Flags relevant to Bluetooth for WSALookupServiceBegin: + * + * LUP_CONTAINERS: If present, go through all Bluetooth devices. Otherwise, lookup bluetooth services on local radio(s) + * or a remote device (as determined by WSAQUERYSET). + * LUP_FLUSHCACHE: When performing a device lookup, perform an actual device inquiry procedure (discovery scan) first, + * instead of only returning devices in the local cached. Similarly for service lookup, query remote + * devices over SDP instead of returning cached SDP records. +*/ +static INT ws_bth_lookup_service_begin( const BLOB *blob, DWORD flags, struct ws_bth_query_ctx *ctx ) +{ + TRACE( "(%p, %#lx, %p)\n", blob, flags, ctx ); + + ctx->lookup_devices = !!(flags & LUP_CONTAINERS); + + if (ctx->lookup_devices) + return bth_lookup_devices( blob, flags, &ctx->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 ); + +struct flags_info +{ + DWORD val; + const char *name; +}; + +/* Taken from dlls/dmusic/dmusic_main.c */ +static const char *debugstr_flags( DWORD flags, const struct flags_info* info, DWORD len ) +{ + char buffer[256], *ptr = buffer; + DWORD i, flags_left = flags, buf_left = sizeof( buffer ); + + if (!flags) + return wine_dbg_sprintf( "0" ); + + for (i = 0; i < len; i++) + { + if (flags_left & info[i].val) + { + int len = snprintf( ptr, buf_left, buf_left == sizeof( buffer ) ? "%s" : " | %s", info[i].name ); + if (len < 0 || len >= buf_left) + return wine_dbg_sprintf( "%#lx", flags ); + ptr += len; + buf_left -= len; + flags_left &= ~info[i].val; + } + } + + return flags_left ? wine_dbg_sprintf( "(%s | %#lx)", buffer, flags_left ) : wine_dbg_sprintf( "(%s)", buffer ); +} + +static const char *debugstr_WSALookupService_flags( DWORD flags ) +{ + const static struct flags_info lookup_flags[] = { + { LUP_DEEP, "LUP_DEEP" }, + { LUP_CONTAINERS, "LUP_CONTAINERS" }, + { LUP_RETURN_NAME, "LUP_RETURN_NAME" }, + { LUP_RETURN_TYPE, "LUP_RETURN_TYPE" }, + { LUP_RETURN_VERSION, "LUP_RETURN_VERSION" }, + { LUP_RETURN_COMMENT, "LUP_RETURN_COMMENT" }, + { LUP_RETURN_ADDR, "LUP_RETURN_ADDR" }, + { LUP_RETURN_BLOB, "LUP_RETURN_BLOB" }, + { LUP_RETURN_ALIASES, "LUP_RETURN_ALIASES" }, + { LUP_RETURN_QUERY_STRING, "LUP_RETURN_QUERY_STRING" }, + { LUP_FLUSHCACHE, "LUP_FLUSHCACHE" }, + { LUP_FLUSHPREVIOUS, "LUP_FLUSHPREVIOUS" }, + { LUP_RES_SERVICE, "LUP_RES_SERVICE" } + }; + + return flags == LUP_RETURN_ALL ? "(LUP_RETURN_ALL)" + : debugstr_flags( flags, lookup_flags, ARRAY_SIZE( lookup_flags ) ); +}
/*********************************************************************** * 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 *ret, lookup = {0};
+ TRACE( "(%p %s %p)\n", query, debugstr_WSALookupService_flags( flags ), lookup_handle ); + + if (!query || !lookup_handle) + { + WSASetLastError( WSAEFAULT ); + return -1; + } + if (query->dwSize != sizeof( *query )) + { + WSASetLastError( WSAEINVAL ); + return -1; + } + switch (query->dwNameSpace) + { + case NS_BTH: + if (ws_bth_lookup_service_begin( query->lpBlob, flags, &lookup.data.bth )) + return -1; + break; + default: + FIXME( "Unsupported dwNameSpace: %lu\n", query->dwNameSpace ); + SetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; + } + if (!(ret = calloc( 1, sizeof( *ret ) ))) + { + ws_bth_lookup_service_end( &lookup.data.bth ); + WSASetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; + } + + ret->namespace = query->dwNameSpace; + ret->data = lookup.data; + *lookup_handle = ret; + + return 0; +}
/*********************************************************************** * WSALookupServiceBeginW (ws2_32.@) */ -int WINAPI WSALookupServiceBeginW( WSAQUERYSETW *query, DWORD flags, HANDLE *lookup ) +int WINAPI WSALookupServiceBeginW( WSAQUERYSETW *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 *ret, lookup = {0}; + + TRACE( "(%p %s %p)\n", query, debugstr_WSALookupService_flags( flags ), lookup_handle ); + + if (!query || !lookup_handle) + { + WSASetLastError( WSAEFAULT ); + return -1; + } + if (query->dwSize != sizeof( *query )) + { + WSASetLastError( WSAEINVAL ); + return -1; + } + switch (query->dwNameSpace) + { + case NS_BTH: + if (ws_bth_lookup_service_begin( query->lpBlob, flags, &lookup.data.bth )) + return -1; + break; + default: + FIXME( "Unsupported dwNameSpace: %lu\n", query->dwNameSpace ); + SetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; + } + if (!(ret = calloc( 1, sizeof( *ret ) ))) + { + ws_bth_lookup_service_end( &lookup.data.bth ); + WSASetLastError( WSA_NOT_ENOUGH_MEMORY ); + return -1; + } + + ret->namespace = query->dwNameSpace; + ret->data = lookup.data; + *lookup_handle = ret; + + return 0; }
+static void ws_bth_lookup_service_end( struct ws_bth_query_ctx *handle ) +{ + if (handle->lookup_devices) + 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) + { + 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 0542aad9ca8..8897b053104 100644 --- a/dlls/ws2_32/tests/protocol.c +++ b/dlls/ws2_32/tests/protocol.c @@ -400,27 +400,23 @@ static void test_WSALookupService(void) ret = WSALookupServiceBeginW(NULL, 0, &handle); error = WSAGetLastError(); ok(ret == SOCKET_ERROR, "WSALookupServiceBeginW should have failed\n"); - todo_wine ok(error == WSAEFAULT, "expected 10014, got %ld\n", error);
ret = WSALookupServiceBeginW(qs, 0, NULL); error = WSAGetLastError(); ok(ret == SOCKET_ERROR, "WSALookupServiceBeginW should have failed\n"); - todo_wine ok(error == WSAEFAULT, "expected 10014, got %ld\n", error);
ret = WSALookupServiceBeginW(qs, 0, &handle); ok(ret == SOCKET_ERROR, "WSALookupServiceBeginW should have failed\n"); - todo_wine ok(WSAGetLastError() == WSAEINVAL - || broken(WSAGetLastError() == ERROR_INVALID_PARAMETER) - || broken(WSAGetLastError() == WSASERVICE_NOT_FOUND) /* win10 1809 */, - "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAEINVAL + || broken(WSAGetLastError() == ERROR_INVALID_PARAMETER) + || broken(WSAGetLastError() == WSASERVICE_NOT_FOUND) /* win10 1809 */, + "got error %u\n", WSAGetLastError());
ret = WSALookupServiceEnd(NULL); error = WSAGetLastError(); - todo_wine ok(ret == SOCKET_ERROR, "WSALookupServiceEnd should have failed\n"); - todo_wine ok(error == ERROR_INVALID_HANDLE, "expected 6, got %ld\n", error);
/* standard network list query */ @@ -439,6 +435,12 @@ static void test_WSALookupService(void) todo_wine ok(handle != (HANDLE)0xdeadbeef, "Handle was not filled\n");
+ if (ret) + { + skip( "WSALookupServiceBeginW failed, skipping.\n" ); + return; + } + offset = 0; do { @@ -573,7 +575,7 @@ static void test_WSALookupServiceNext_bth_devices( HANDLE lookup_handle, DWORD f if (ret) { ok( ret == -1, "%d != -1\n", ret ); - todo_wine ok( err == WSA_E_NO_MORE || err == WSAEFAULT, "WSALookupServiceNextA failed: %d\n", err ); + ok( err == WSA_E_NO_MORE || err == WSAEFAULT, "WSALookupServiceNextA failed: %d\n", err ); if (err != WSAEFAULT) { free( results ); @@ -721,7 +723,7 @@ static void test_WSALookupService_bth_devices( void ) if (ret) { /* WSASERVICE_NOT_FOUND indicates that no Bluetooth devices were found. */ - todo_wine ok( err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); + ok( err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", WSAGetLastError() ); ok( !lookup_handle, "Handle should not have been filled\n"); skip( "No Bluetooth devices found\n" ); winetest_pop_context(); @@ -743,13 +745,13 @@ static void test_WSALookupService_bth_devices( void ) err = WSAGetLastError(); if (ret) { - todo_wine ok( err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", err ); + ok( err == WSASERVICE_NOT_FOUND, "WSALookupServiceBeginA failed: %d\n", err ); ok( !lookup_handle, "Handle should not have been filled\n"); skip( "No Bluetooth devices found\n" ); return; }
- todo_wine ok( !!lookup_handle, "Handle was not filled\n" ); + ok( !!lookup_handle, "Handle was not filled\n" ); /* Missing space for a BTH_DEVICE_INFO */ orig_len = buf_len = sizeof( *results ) + sizeof( GUID ) + sizeof( BLOB ); results = calloc( 1, buf_len ); diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 9a4d0794151..30a839360b6 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" @@ -52,6 +54,7 @@ #include "ip2string.h" #include "windns.h" #include "wine/afd.h" +#include "wine/winebth.h" #include "wine/debug.h" #include "wine/unixlib.h"
From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/protocol.c | 223 +++++++++++++++++++++++++++++++++-- dlls/ws2_32/tests/protocol.c | 12 +- 2 files changed, 221 insertions(+), 14 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 873e536f825..a32c69c2123 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -2436,25 +2436,232 @@ int WINAPI WSALookupServiceEnd( HANDLE lookup_handle ) }
+/* Known flags for device discovery: + * + * LUP_FLUSHPREVIOUS: Skip to the next device in the list. + * LUP_RETURN_TYPE: Return the class of device code inside the Data1 field of lpServiceClassId (yes, really). + * LUP_RETURN_NAME: Return the device name in lpszServiceInstanceName. + * LUP_RETURN_ADDR: Return the device address in lpcsaBuffer.LocalAddr as a SOCKADDR_BTH value. + * LUP_RES_SERVICE: If LUP_RETURN_ADDR is set, return the local address in lpcsaBuffer.RemoteAddr similarly as well. + * LUP_RETURN_BLOB: Return the BTH_DEVICE_INFO value associated with the device in lpBlob. + */ +static INT bth_devices_next( struct ws_bth_query_device *devices, DWORD flags, DWORD *buf_len, void *queryset, BOOL unicode ) +{ + union { + WSAQUERYSETA resultsA; + WSAQUERYSETW resultsW; + } *results = queryset; + DWORD queryset_size = (unicode ? sizeof( results->resultsW ) : sizeof( results->resultsA )); + char *buf_start = (char *)queryset + queryset_size; + DWORD buf_required = queryset_size; + const BTH_DEVICE_INFO *device_info; + + if (devices->list->numOfDevices == devices->idx) + { + SetLastError( WSA_E_NO_MORE ); + return -1; + } + + if (flags & LUP_RETURN_TYPE) + buf_required += sizeof( GUID ); + if (flags & LUP_RETURN_NAME) + /* Windows will always require the maximum buffer length for storing a name, regardless of the name's actual length. */ + buf_required += unicode ? BTH_MAX_NAME_SIZE * sizeof( WCHAR ) : BTH_MAX_NAME_SIZE; + if (flags & LUP_RETURN_ADDR) + { + buf_required += sizeof( CSADDR_INFO ) + sizeof( SOCKADDR_BTH ); + if (flags & LUP_RES_SERVICE) + buf_required += sizeof( SOCKADDR_BTH ); + } + if (flags & LUP_RETURN_BLOB) + buf_required += sizeof( BLOB ) + sizeof( BTH_DEVICE_INFO ); + + if (*buf_len < buf_required) + { + *buf_len = buf_required; + WSASetLastError( WSAEFAULT ); + return -1; + } + + if (flags & LUP_FLUSHPREVIOUS) + { + devices->idx++; + return bth_devices_next( devices, flags & ~LUP_FLUSHPREVIOUS, buf_len, queryset, unicode ); + } + device_info = &devices->list->deviceList[devices->idx++]; + + if (flags & LUP_RETURN_TYPE) + { + GUID *cod = (GUID *)buf_start; + + memset( cod, 0, sizeof( *cod )); + cod->Data1 = device_info->classOfDevice; + buf_start += sizeof( *cod ); + if (unicode) + results->resultsW.lpServiceClassId = cod; + else + results->resultsA.lpServiceClassId = cod; + } + if (flags & LUP_RETURN_NAME) + { + if (unicode) + { + DWORD lenW = MultiByteToWideChar( CP_ACP, 0, device_info->name, -1, NULL, 0 ); + results->resultsW.lpszServiceInstanceName = (WCHAR *)buf_start; + buf_start += lenW * sizeof( WCHAR ); + MultiByteToWideChar( CP_ACP, 0, device_info->name, -1, results->resultsW.lpszServiceInstanceName, + lenW ); + } + else + { + DWORD lenA = strlen( device_info->name ) + 1; + results->resultsA.lpszServiceInstanceName = buf_start; + buf_start += lenA; + memcpy( results->resultsA.lpszServiceInstanceName, device_info->name, lenA + 1 ); + } + } + if (flags & LUP_RETURN_ADDR) + { + CSADDR_INFO *addr_info; + SOCKADDR_BTH *bth_addr; + + addr_info = (CSADDR_INFO *)buf_start; + buf_start += sizeof( *addr_info ); + bth_addr = (SOCKADDR_BTH *)buf_start; + buf_start += sizeof( *bth_addr ); + + addr_info->RemoteAddr.iSockaddrLength = sizeof( *bth_addr ); + addr_info->RemoteAddr.lpSockaddr = (SOCKADDR *)bth_addr; + memset( bth_addr, 0, sizeof( *bth_addr )); + bth_addr->addressFamily = AF_BTH; + bth_addr->btAddr = device_info->address; + if (flags & LUP_RES_SERVICE) + { + FIXME( "LUP_RES_SERVICE: semi-stub!\n" ); + bth_addr = (SOCKADDR_BTH *)buf_start; + buf_start += sizeof( *bth_addr ); + memset( bth_addr, 0, sizeof( *bth_addr )); + bth_addr->addressFamily = AF_BTH; + addr_info->LocalAddr.iSockaddrLength = sizeof( *bth_addr ); + addr_info->LocalAddr.lpSockaddr = (SOCKADDR *)bth_addr; + } + if (unicode) + results->resultsW.lpcsaBuffer = addr_info; + else + results->resultsA.lpcsaBuffer = addr_info; + } + if (flags & LUP_RETURN_BLOB) + { + BLOB *blob; + BTH_DEVICE_INFO *info; + + blob = (BLOB *)buf_start; + buf_start += sizeof( *blob ); + info = (BTH_DEVICE_INFO *)buf_start; + buf_start += sizeof( *info ); + + blob->cbSize = sizeof( *device_info ); + blob->pBlobData = (BYTE *)info; + info->address = device_info->address; + info->classOfDevice = device_info->classOfDevice; + info->flags = device_info->flags; + if (flags & LUP_RETURN_NAME) + lstrcpynA( info->name, device_info->name, sizeof( info->name ) ); + + if (unicode) + results->resultsW.lpBlob = blob; + else + results->resultsA.lpBlob = blob; + } + + WSASetLastError( ERROR_SUCCESS ); + return 0; +} + +static INT ws_bth_lookup_service_next( struct ws_bth_query_ctx *handle, DWORD flags, DWORD *buf_len, void *results, + BOOL unicode ) +{ + TRACE( "(%p, %#lx, %p, %p)\n", handle, flags, buf_len, results ); + + if (handle->lookup_devices) + return bth_devices_next( &handle->data.device, flags, buf_len, results, unicode ); + + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; +} + /*********************************************************************** * WSALookupServiceNextA (ws2_32.@) */ -int WINAPI WSALookupServiceNextA( HANDLE lookup, DWORD flags, DWORD *len, WSAQUERYSETA *results ) +int WINAPI WSALookupServiceNextA( HANDLE lookup_handle, DWORD flags, DWORD *len, WSAQUERYSETA *results ) { - FIXME( "(%p %#lx %p %p) Stub!\n", lookup, flags, len, results ); - SetLastError( WSA_E_NO_MORE ); - return -1; + struct ws_lookup_service_ctx *lookup = lookup_handle; + + TRACE( "(%p %s %p %p)\n", lookup_handle, debugstr_WSALookupService_flags( flags ), len, results ); + + if (!len || !results || results->dwSize != sizeof( *results )) + { + WSASetLastError( WSAEINVAL ); + return -1; + } + if (*len < sizeof( *results )) + { + *len = sizeof( *results ); + WSASetLastError( WSAEFAULT ); + return -1; + } + if (!lookup) + { + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; + } + + switch (lookup->namespace) + { + case NS_BTH: + return ws_bth_lookup_service_next( &lookup->data.bth, flags, len, results, FALSE ); + default: + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; + } }
/*********************************************************************** * WSALookupServiceNextW (ws2_32.@) */ -int WINAPI WSALookupServiceNextW( HANDLE lookup, DWORD flags, DWORD *len, WSAQUERYSETW *results ) +int WINAPI WSALookupServiceNextW( HANDLE lookup_handle, DWORD flags, DWORD *len, WSAQUERYSETW *results ) { - FIXME( "(%p %#lx %p %p) Stub!\n", lookup, flags, len, results ); - SetLastError( WSA_E_NO_MORE ); - return -1; + struct ws_lookup_service_ctx *lookup = lookup_handle; + + TRACE( "(%p %s %p %p)\n", lookup, debugstr_WSALookupService_flags( flags ), len, results ); + + if (!len || !results || results->dwSize != sizeof( *results )) + { + WSASetLastError( WSAEINVAL ); + return -1; + } + if (*len < sizeof ( *results )) + { + *len = sizeof( *results ); + WSASetLastError( WSAEFAULT ); + return -1; + } + if (!lookup) + { + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; + } + + + switch (lookup->namespace) + { + case NS_BTH: + return ws_bth_lookup_service_next( &lookup->data.bth, flags, len, results, TRUE ); + default: + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; + } }
diff --git a/dlls/ws2_32/tests/protocol.c b/dlls/ws2_32/tests/protocol.c index 8897b053104..94cfca462df 100644 --- a/dlls/ws2_32/tests/protocol.c +++ b/dlls/ws2_32/tests/protocol.c @@ -591,21 +591,21 @@ static void test_WSALookupServiceNext_bth_devices( HANDLE lookup_handle, DWORD f
if (flags & LUP_RETURN_NAME) { - todo_wine ok( !!results->lpszServiceInstanceName, "Expected lpszServiceInstanceName to not be NULL\n" ); + ok( !!results->lpszServiceInstanceName, "Expected lpszServiceInstanceName to not be NULL\n" ); if (verbose) trace( "Name: %s\n", debugstr_a( results->lpszServiceInstanceName ) ); }
if (flags & LUP_RETURN_TYPE) { - todo_wine ok( !!results->lpServiceClassId, "Expected lpServiceClassId to not be NULL\n" ); + ok( !!results->lpServiceClassId, "Expected lpServiceClassId to not be NULL\n" ); if (results->lpServiceClassId && verbose) trace( "CoD: %#lx\n", results->lpServiceClassId->Data1 ); }
if (flags & LUP_RETURN_BLOB) { - todo_wine ok( !!results->lpBlob, "Expected lpBlob to not be NULL\n" ); + ok( !!results->lpBlob, "Expected lpBlob to not be NULL\n" ); if (results->lpBlob) { info = (BTH_DEVICE_INFO *)results->lpBlob->pBlobData; @@ -628,7 +628,7 @@ static void test_WSALookupServiceNext_bth_devices( HANDLE lookup_handle, DWORD f
if (flags & LUP_RETURN_ADDR) { - todo_wine ok( !!results->lpcsaBuffer, "Expected lpcsaBuffer to not be NULL\n" ); + ok( !!results->lpcsaBuffer, "Expected lpcsaBuffer to not be NULL\n" ); if (results->lpcsaBuffer) { const SOCKET_ADDRESS *remote_sock_addr = &results->lpcsaBuffer->RemoteAddr; @@ -760,8 +760,8 @@ static void test_WSALookupService_bth_devices( void ) ret = WSALookupServiceNextA( lookup_handle, LUP_RETURN_TYPE | LUP_RETURN_BLOB, &buf_len, results ); err = WSAGetLastError(); ok( ret == -1, "Expected WSALookupServiceNextA to fail\n" ); - todo_wine ok( err == WSAEFAULT, "%d != %d", err, WSAEFAULT ); - todo_wine ok( buf_len > orig_len, "%ld should be greater than %ld\n", buf_len, orig_len ); + ok( err == WSAEFAULT, "%d != %d\n", err, WSAEFAULT ); + ok( buf_len > orig_len, "%ld should be greater than %ld\n", buf_len, orig_len ); ok( !results->lpServiceClassId, "lpServiceClassId should not have been filled\n" ); ok( !results->lpBlob, "lpBlob should not have been filled\n" ); free( results );
On Wed Mar 19 00:33:33 2025 +0000, Elizabeth Figura wrote:
Sorry, let me clarify. According to my reading of the documentation alone—which is of course not to be trusted, but also isn't tested in this patch series—the parameters to WSALookupServiceBegin() are only filters. In particular, the flags LUP_CONTAINERS and LUP_NOCONTAINERS both exist. I would *assume* that specifying LUP_CONTAINERS causes only containers to be returned, LUP_NOCONTAINERS causes only services to be returned, and specifying neither flag means that both containers and services will be returned. Possibly this is not actually what happens. Actually, a similar issue is suggested by the documentation for the first parameter: the dwNameSpace parameter can be NS_ALL, which implies that having any unions at all in struct ws_lookup_service_ctx is problematic. This is not to say that we need to go as far as testing LUP_NOCONTAINERS or NS_ALL. In fact, I am inclined to suspect this patch goes to excessive lengths to future-proof the code. It's not like putting things in unions after the fact is generally that much of a problem, in my opinion. At the same time, I as a maintainer would not necessarily reject a future-proof design that I feel is sufficiently unobtrusive and/or likely to be necessary. But it's not clear that this design *is* going in the right direction; the documentation suggests it's not and it doesn't have any tests (even external informal ones) to contradict the documentation.
Ah. I've been relying on MSDN's Bluetooth specific [documentation for Winsock here](https://learn.microsoft.com/en-us/windows/win32/bluetooth/bluetooth-and-wsal...). According to that, `LUP_NOCONTAINERS` is entirely ignored (the docs explicitly say that any flags except for `LUP_CONTAINERS` and `LUP_FLUSHCACHE` are ignored for `NS_BTH`).
If flags to `WSALookupServiceBegin` are supposed to act like filters, the Bluetooth-specific functionality for this method is completely different. Device and service discovery are mutually exclusive, and which one of the two is going to happen seems to be set in stone after the first `WSALookupServiceBegin` call.
I've added to the `protocol.c` tests in the latest revision which demonstrate this behavior a little more clearly.
As to `NS_ALL`, you're right, I'm not sure how this fits in with that. But given `NS_BTH`'s behavior, I'm not even sure if `NS_ALL` would include Bluetooth data in the first place.
We're plumbing "blob" all the way down to this function and then never using it. It should be left out until its future use, if there is one.
v3 adds support for performing discovery, so it should be used now.
No need for the 'if' here.
Fixed, thanks.
On Thu Mar 20 17:35:21 2025 +0000, Vibhav Pant wrote:
Ah. I've been relying on MSDN's Bluetooth specific [documentation for Winsock here](https://learn.microsoft.com/en-us/windows/win32/bluetooth/bluetooth-and-wsal...). According to that, `LUP_NOCONTAINERS` is entirely ignored (the docs explicitly say that any flags except for `LUP_CONTAINERS` and `LUP_FLUSHCACHE` are ignored for `NS_BTH`). If flags to `WSALookupServiceBegin` are supposed to act like filters, the Bluetooth-specific functionality for this method is completely different. Device and service discovery are mutually exclusive, and which one of the two is going to happen seems to be set in stone after the first `WSALookupServiceBegin` call, which is why I went for the unions. I've added to the `protocol.c` tests in the latest revision which demonstrate this behavior a little more clearly. As to `NS_ALL`, you're right, I'm not sure how this fits in with that. But given `NS_BTH`'s behavior, I'm not even sure if `NS_ALL` would include Bluetooth data in the first place.
Okay, that's fine then.
This merge request was approved by Elizabeth Figura.