From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/Makefile.in | 3 +- dlls/ws2_32/protocol.c | 141 +++++++++++++++++++++++++-- dlls/ws2_32/protocol_bth.c | 161 +++++++++++++++++++++++++++++++ dlls/ws2_32/tests/protocol_bth.c | 4 +- dlls/ws2_32/ws2_32_private.h | 20 ++++ 5 files changed, 316 insertions(+), 13 deletions(-) create mode 100644 dlls/ws2_32/protocol_bth.c
diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in index e80def64881..6fe2ec2b4a0 100644 --- a/dlls/ws2_32/Makefile.in +++ b/dlls/ws2_32/Makefile.in @@ -2,13 +2,14 @@ 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 = \ async.c \ inaddr.c \ protocol.c \ + protocol_bth.c \ socket.c \ unixlib.c \ version.rc diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 2699593a2f3..31e7263cd0e 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,154 @@ int WINAPI WSAGetServiceClassNameByClassIdW( GUID *class, WCHAR *service, DWORD return -1; }
+#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; +};
/*********************************************************************** * 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}; + INT ret = -1; + + TRACE( "(%p %#lx %p)\n", query, flags, lookup_handle ); + + if (!query || !lookup_handle) + { + WSASetLastError( WSAEFAULT ); + return -1; + }
+ __TRY + { + if (query->dwSize == sizeof( *query )) + { + switch (query->dwNameSpace) + { + case NS_BTH: + ret = ws_bth_lookup_service_begin( query, flags, &lookup_data.bth ); + break; + default: + FIXME( "Unsupported dwNameSpace: %lu\n", query->dwNameSpace ); + SetLastError( WSA_NOT_ENOUGH_MEMORY ); + ret = -1; + break; + } + if (!ret) + { + lookup = calloc( 1, sizeof( *lookup ) ); + if (lookup) + { + lookup->magic = WS_LOOKUP_SERVICE_HANDLE_MAGIC; + lookup->namespace = query->dwNameSpace; + lookup->data = lookup_data; + *lookup_handle = lookup; + } + else + { + ws_bth_lookup_service_end( &lookup_data.bth ); + ret = -1; + WSASetLastError( WSA_NOT_ENOUGH_MEMORY ); + } + } + } + else + WSASetLastError( WSAEFAULT ); + } + __EXCEPT_PAGE_FAULT + { + ret = -1; + WSASetLastError( WSAEFAULT ); + } + __ENDTRY; + + if (ret && lookup) + WSALookupServiceEnd( lookup ); + + return ret; +}
/*********************************************************************** * 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}; + INT ret = 0; + + TRACE( "(%p %#lx %p)\n", query, flags, lookup ); + + if (!query || !lookup) + { + WSASetLastError( WSAEFAULT ); + return -1; + } + + queryA.dwSize = sizeof( queryA ); + __TRY + { + if (query->dwSize == sizeof( *query )) + { + /* These are the only fields that we use right now. */ + queryA.dwNameSpace = query->dwNameSpace; + queryA.lpBlob = query->lpBlob; + } + else + { + ret = -1; + WSASetLastError( WSAEFAULT ); + } + } + __EXCEPT_PAGE_FAULT + { + ret = -1; + WSASetLastError( WSAEFAULT ); + } + __ENDTRY; + + return ret ? ret : WSALookupServiceBeginA( &queryA, flags, lookup ); }
/*********************************************************************** * 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/protocol_bth.c b/dlls/ws2_32/protocol_bth.c new file mode 100644 index 00000000000..c01a6ee05b5 --- /dev/null +++ b/dlls/ws2_32/protocol_bth.c @@ -0,0 +1,161 @@ +/* + * Support for the NS_BTH namespace. + * + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> + +#include "ws2_32_private.h" + +#include <winerror.h> +#include <winsock2.h> +#include <bthsdpdef.h> +#include <bluetoothapis.h> +#include <ws2bth.h> +#include <bthdef.h> +#include <winioctl.h> +#include <bthioctl.h> + +WINE_DEFAULT_DEBUG_CHANNEL( winsock ); + +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; +} + +void ws_bth_lookup_service_end( struct ws_bth_query_ctx *handle ) +{ + if (handle->flags & LUP_CONTAINERS) + free( handle->data.device.list ); +} + +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; +} diff --git a/dlls/ws2_32/tests/protocol_bth.c b/dlls/ws2_32/tests/protocol_bth.c index ed1102a6f08..275904bb2c9 100644 --- a/dlls/ws2_32/tests/protocol_bth.c +++ b/dlls/ws2_32/tests/protocol_bth.c @@ -183,8 +183,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..050a5f78f2a 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" @@ -147,4 +149,22 @@ enum ws_unix_funcs ws_unix_funcs_count, };
+/* 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; +}; + +extern INT ws_bth_lookup_service_begin( WSAQUERYSETA *query, DWORD flags, struct ws_bth_query_ctx *handle ); +extern void ws_bth_lookup_service_end( struct ws_bth_query_ctx *handle ); + #endif