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 7eb41079228..462d69c1b57 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"