From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/protocol.c | 61 ++++++++-- dlls/ws2_32/protocol_bth.c | 184 +++++++++++++++++++++++++++++++ dlls/ws2_32/tests/protocol_bth.c | 10 +- dlls/ws2_32/ws2_32_private.h | 2 + 4 files changed, 244 insertions(+), 13 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 31e7263cd0e..cd2b9a3cc02 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -2230,22 +2230,67 @@ int WINAPI WSALookupServiceEnd( HANDLE lookup_handle ) /*********************************************************************** * 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 %#lx %p %p)\n", lookup_handle, 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 || lookup->magic != WS_LOOKUP_SERVICE_HANDLE_MAGIC) + { + 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 %#lx %p %p)\n", lookup, 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; + } + + 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/protocol_bth.c b/dlls/ws2_32/protocol_bth.c index c01a6ee05b5..3e43d6893d9 100644 --- a/dlls/ws2_32/protocol_bth.c +++ b/dlls/ws2_32/protocol_bth.c @@ -139,12 +139,196 @@ static INT bth_lookup_devices( const BLOB *blob, DWORD flags, struct ws_bth_quer return query->list ? 0 : -1; }
+/* 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. + */ +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_left = *buf_len - queryset_size; + DWORD buf_required = queryset_size; + const BTH_DEVICE_INFO *device_info; + BOOL buf_insufficient = FALSE; + + if (devices->list->numOfDevices == devices->idx) + { + SetLastError( WSA_E_NO_MORE ); + 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) + { + buf_required += sizeof( GUID ); + if (buf_left >= sizeof( GUID )) + { + GUID *cod = (GUID *)buf_start; + + memset( cod, 0, sizeof( *cod )); + cod->Data1 = device_info->classOfDevice; + buf_start += sizeof( *cod ); + buf_left -= sizeof( *cod ); + if (unicode) + results->resultsW.lpServiceClassId = cod; + else + results->resultsA.lpServiceClassId = cod; + } + else + buf_insufficient = TRUE; + } + if (flags & LUP_RETURN_NAME) + { + if (unicode) + { + DWORD lenW = MultiByteToWideChar( CP_ACP, 0, device_info->name, -1, NULL, 0 ); + buf_required += lenW; + if (buf_left >= lenW * sizeof( WCHAR )) + { + results->resultsW.lpszServiceInstanceName = (WCHAR *)buf_start; + buf_start += lenW * sizeof( WCHAR ); + buf_left -= lenW * sizeof( WCHAR ); + MultiByteToWideChar( CP_ACP, 0, device_info->name, -1, results->resultsW.lpszServiceInstanceName, + lenW ); + } + else + buf_insufficient = TRUE; + } + else + { + DWORD lenA = strlen( device_info->name ) + 1; + buf_required += lenA; + if (buf_left >= lenA) + { + results->resultsA.lpszServiceInstanceName = buf_start; + buf_start += lenA; + buf_left -= lenA; + memcpy( results->resultsA.lpszServiceInstanceName, device_info->name, lenA + 1 ); + } + else + buf_insufficient = TRUE; + } + } + if (flags & LUP_RETURN_ADDR) + { + DWORD addr_len = sizeof( CSADDR_INFO ) + sizeof( SOCKADDR_BTH ); + if (flags & LUP_RES_SERVICE) + addr_len += sizeof( SOCKADDR_BTH ); + buf_required += addr_len; + + if (buf_left >= addr_len) + { + 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 ); + buf_left -= sizeof( *bth_addr ) + sizeof( *addr_info ); + + 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 ); + buf_left -= 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; + } + else + buf_insufficient = TRUE; + } + if (flags & LUP_RETURN_BLOB) + { + BLOB *blob; + buf_required += sizeof( *blob ) + sizeof( *device_info ); + if (buf_left >= sizeof( *blob ) + sizeof( *device_info )) + { + BTH_DEVICE_INFO *info; + + blob = (BLOB *)buf_start; + buf_start += sizeof( *blob ); + info = (BTH_DEVICE_INFO *)buf_start; + buf_start += sizeof( *info ); + buf_left -= sizeof( *blob ) + 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; + } + else + buf_insufficient = TRUE; + } + + if (buf_insufficient) + { + WSASetLastError( WSAEFAULT ); + *buf_len = buf_required; + } + else + WSASetLastError( ERROR_SUCCESS ); + + return buf_insufficient ? -1 : 0; +} + 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_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->flags & LUP_CONTAINERS) + return bth_devices_next( &handle->data.device, flags, buf_len, results, unicode ); + + WSASetLastError( WSA_INVALID_HANDLE ); + return -1; +} + INT ws_bth_lookup_service_begin( WSAQUERYSETA *search, DWORD flags, struct ws_bth_query_ctx *handle ) { TRACE( "(%p, %#lx, %p)\n", search, flags, handle ); diff --git a/dlls/ws2_32/tests/protocol_bth.c b/dlls/ws2_32/tests/protocol_bth.c index 275904bb2c9..c649a6f4806 100644 --- a/dlls/ws2_32/tests/protocol_bth.c +++ b/dlls/ws2_32/tests/protocol_bth.c @@ -68,7 +68,7 @@ static void test_WSALookupServiceNext_devices( HANDLE *lookup_handle, DWORD flag winetest_push_context( "device %lu", i); if (ret) { - todo_wine ok( err == WSA_E_NO_MORE || err == WSAENOMORE || err == WSAEFAULT, + ok( err == WSA_E_NO_MORE || err == WSAENOMORE || err == WSAEFAULT, "WSALookupServiceNextA failed: %d\n", WSAGetLastError() ); if (err != WSAEFAULT) { @@ -85,21 +85,21 @@ static void test_WSALookupServiceNext_devices( HANDLE *lookup_handle, DWORD flag
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; @@ -122,7 +122,7 @@ static void test_WSALookupServiceNext_devices( HANDLE *lookup_handle, DWORD flag
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; diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 050a5f78f2a..3531cd823da 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -165,6 +165,8 @@ struct ws_bth_query_ctx };
extern INT ws_bth_lookup_service_begin( WSAQUERYSETA *query, DWORD flags, struct ws_bth_query_ctx *handle ); +extern INT ws_bth_lookup_service_next( struct ws_bth_query_ctx *handle, DWORD flags, DWORD *buf_len, void *results, + BOOL unicode ); extern void ws_bth_lookup_service_end( struct ws_bth_query_ctx *handle );
#endif