Chromium Code Reviews| Index: device/bluetooth/bluetooth_task_manager_win.cc |
| diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc |
| index 7bfc32b658eda1c961ce5e37e9f423031f114565..54cc5b91ad6671dd89e081ef09ec91936ce6c539 100644 |
| --- a/device/bluetooth/bluetooth_task_manager_win.cc |
| +++ b/device/bluetooth/bluetooth_task_manager_win.cc |
| @@ -17,6 +17,7 @@ |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "base/win/scoped_handle.h" |
| +#include "device/bluetooth/bluetooth_device.h" |
| #include "device/bluetooth/bluetooth_init_win.h" |
| #include "device/bluetooth/bluetooth_low_energy_win.h" |
| #include "device/bluetooth/bluetooth_service_record_win.h" |
| @@ -28,21 +29,31 @@ const int kNumThreadsInWorkerPool = 3; |
| const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; |
| const int kMaxNumDeviceAddressChar = 127; |
| const int kServiceDiscoveryResultBufferSize = 5000; |
| -const int kMaxDeviceDiscoveryTimeout = 48; |
| -typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; |
| +// See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time |
| +// out for the inquiry, expressed in increments of 1.28 seconds. For example, an |
| +// inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum |
| +// value for this member is 48. When a value greater than 48 is used, the |
| +// calling function immediately fails and returns |
| +const int kMaxDeviceDiscoveryTimeoutMultiplier = 48; |
| -std::string BluetoothAddressToString(const BLUETOOTH_ADDRESS& btha) { |
| - return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", |
| - btha.rgBytes[5], |
| - btha.rgBytes[4], |
| - btha.rgBytes[3], |
| - btha.rgBytes[2], |
| - btha.rgBytes[1], |
| - btha.rgBytes[0]); |
| -} |
| +typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; |
| -device::BluetoothUUID BluetoothLowEnergyUuidToUBluetoothUuid( |
| +// Note: The string returned here must have the same format as |
| +// BluetoothDevice::CanonicalizeAddress. |
| +std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) { |
| + std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", |
| + btha.rgBytes[5], |
| + btha.rgBytes[4], |
| + btha.rgBytes[3], |
| + btha.rgBytes[2], |
| + btha.rgBytes[1], |
| + btha.rgBytes[0]); |
| + DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result)); |
| + return result; |
| +} |
| + |
| +device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid( |
| const BTH_LE_UUID& bth_le_uuid) { |
| if (bth_le_uuid.IsShortUuid) { |
| std::string uuid_hex = |
| @@ -76,7 +87,7 @@ void GetAdapterState(HANDLE adapter_handle, |
| ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle, |
| &adapter_info)) { |
| name = base::SysWideToUTF8(adapter_info.szName); |
| - address = BluetoothAddressToString(adapter_info.address); |
| + address = BluetoothAddressToCanonicalString(adapter_info.address); |
| powered = !!BluetoothIsConnectable(adapter_handle); |
| } |
| state->name = name; |
| @@ -87,55 +98,13 @@ void GetAdapterState(HANDLE adapter_handle, |
| void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, |
| device::BluetoothTaskManagerWin::DeviceState* state) { |
| state->name = base::SysWideToUTF8(device_info.szName); |
| - state->address = BluetoothAddressToString(device_info.Address); |
| + state->address = BluetoothAddressToCanonicalString(device_info.Address); |
| state->bluetooth_class = device_info.ulClassofDevice; |
| state->visible = true; |
| state->connected = !!device_info.fConnected; |
| state->authenticated = !!device_info.fAuthenticated; |
| } |
| -void DiscoverDeviceServices( |
| - const std::string& device_address, |
| - const GUID& protocol_uuid, |
| - ScopedVector<ServiceRecordState>* service_record_states) { |
| - // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. |
| - WSAQUERYSET sdp_query; |
| - ZeroMemory(&sdp_query, sizeof(sdp_query)); |
| - sdp_query.dwSize = sizeof(sdp_query); |
| - GUID protocol = protocol_uuid; |
| - sdp_query.lpServiceClassId = &protocol; |
| - sdp_query.dwNameSpace = NS_BTH; |
| - wchar_t device_address_context[kMaxNumDeviceAddressChar]; |
| - std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( |
| - device_address_context, kMaxNumDeviceAddressChar); |
| - device_address_context[length] = NULL; |
| - sdp_query.lpszContext = device_address_context; |
| - HANDLE sdp_handle; |
| - if (ERROR_SUCCESS != |
| - WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) { |
| - return; |
| - } |
| - char sdp_buffer[kServiceDiscoveryResultBufferSize]; |
| - LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); |
| - while (true) { |
| - DWORD sdp_buffer_size = sizeof(sdp_buffer); |
| - if (ERROR_SUCCESS != |
| - WSALookupServiceNext( |
| - sdp_handle, LUP_RETURN_ALL, &sdp_buffer_size, sdp_result_data)) { |
| - break; |
| - } |
| - ServiceRecordState* service_record_state = new ServiceRecordState(); |
| - service_record_state->name = |
| - base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); |
| - for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { |
| - service_record_state->sdp_bytes.push_back( |
| - sdp_result_data->lpBlob->pBlobData[i]); |
| - } |
| - service_record_states->push_back(service_record_state); |
| - } |
| - WSALookupServiceEnd(sdp_handle); |
| -} |
| - |
| } // namespace |
| namespace device { |
| @@ -168,7 +137,8 @@ BluetoothTaskManagerWin::DeviceState::~DeviceState() { |
| BluetoothTaskManagerWin::BluetoothTaskManagerWin( |
| scoped_refptr<base::SequencedTaskRunner> ui_task_runner) |
| : ui_task_runner_(ui_task_runner), |
| - discovering_(false) { |
| + discovering_(false), |
| + current_logging_batch_count_(0) { |
| } |
| BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { |
| @@ -257,6 +227,38 @@ void BluetoothTaskManagerWin::PostStopDiscoveryTask() { |
| base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); |
| } |
| +void BluetoothTaskManagerWin::LogPollingError(const char* message, |
| + int win32_error) { |
| + const int kLogPeriodInMilliseconds = 60 * 1000; |
| + const int kMaxMessagesPerLogPeriod = 10; |
| + |
| + // Check if we need to discard this message |
| + if (!current_logging_batch_ticks_.is_null()) { |
| + if (base::TimeTicks::Now() - current_logging_batch_ticks_ <= |
| + base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) { |
| + if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod) |
| + return; |
| + } else { |
| + // The batch expired, reset it to "null". |
| + current_logging_batch_ticks_ = base::TimeTicks(); |
| + } |
| + } |
| + |
| + // Keep track of this batch of messages |
| + if (current_logging_batch_ticks_.is_null()) { |
| + current_logging_batch_ticks_ = base::TimeTicks::Now(); |
| + current_logging_batch_count_ = 0; |
| + } |
| + current_logging_batch_count_++; |
|
xiyuan
2014/07/30 21:41:47
nit: ++current_logging_batch_count_;
rpaquay
2014/07/30 22:34:25
Done.
|
| + |
| + // Log the message |
| + if (win32_error == 0) |
| + LOG(WARNING) << message; |
| + else |
| + LOG(WARNING) << message << ": " |
| + << logging::SystemErrorCodeToString(win32_error); |
|
xiyuan
2014/07/30 21:41:47
nit: indent looks strange.
rpaquay
2014/07/30 22:34:25
Done.
|
| +} |
| + |
| void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { |
| DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, |
| @@ -275,18 +277,11 @@ void BluetoothTaskManagerWin::OnDiscoveryStopped() { |
| DiscoveryStopped()); |
| } |
| -void BluetoothTaskManagerWin::OnDevicesUpdated( |
| - const ScopedVector<DeviceState>* devices) { |
| - DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| - FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, |
| - DevicesUpdated(*devices)); |
| -} |
| - |
| -void BluetoothTaskManagerWin::OnDevicesDiscovered( |
| +void BluetoothTaskManagerWin::OnDevicesPolled( |
| const ScopedVector<DeviceState>* devices) { |
| DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| - FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, |
| - DevicesDiscovered(*devices)); |
| + FOR_EACH_OBSERVER( |
| + BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices)); |
| } |
| void BluetoothTaskManagerWin::PollAdapter() { |
| @@ -372,7 +367,7 @@ void BluetoothTaskManagerWin::StopDiscovery() { |
| base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); |
| } |
| -void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { |
| +void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) { |
| DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
| if (!discovering_ || !adapter_handle_) { |
| ui_task_runner_->PostTask( |
| @@ -382,132 +377,249 @@ void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { |
| } |
| ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); |
|
xiyuan
2014/07/30 21:41:47
Would we leak |device_list| if SearchDevices() ret
rpaquay
2014/07/30 22:34:25
Done.
|
| - SearchDevices(timeout, false, device_list); |
| - if (device_list->empty()) { |
| - delete device_list; |
| - } else { |
| - DiscoverServices(device_list); |
| + if (SearchDevices(timeout_multiplier, false, device_list)) { |
| ui_task_runner_->PostTask( |
| FROM_HERE, |
| - base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, |
| + base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, |
| this, |
| base::Owned(device_list))); |
| } |
| - if (timeout < kMaxDeviceDiscoveryTimeout) { |
| - bluetooth_task_runner_->PostTask( |
| - FROM_HERE, |
| - base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, |
| - this, |
| - timeout + 1)); |
| - } else { |
| - ui_task_runner_->PostTask( |
| - FROM_HERE, |
| - base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); |
| - discovering_ = false; |
| - } |
| + if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier) |
| + timeout_multiplier++; |
|
xiyuan
2014/07/30 21:41:47
nit: ++timeout_multiplier;
rpaquay
2014/07/30 22:34:25
Done.
|
| + bluetooth_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind( |
| + &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier)); |
| } |
| void BluetoothTaskManagerWin::GetKnownDevices() { |
| ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); |
|
xiyuan
2014/07/30 21:41:47
Same here.
rpaquay
2014/07/30 22:34:25
Done.
|
| - SearchDevices(1, true, device_list); |
| - |
| - // Search for Bluetooth Low Energy devices |
| - if (win::IsBluetoothLowEnergySupported()) { |
| - ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices; |
| - std::string error; |
| - bool success = |
| - win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error); |
| - if (success) { |
| - for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter = |
| - btle_devices.begin(); |
| - iter != btle_devices.end(); |
| - ++iter) { |
| - win::BluetoothLowEnergyDeviceInfo* device_info = (*iter); |
| - |
| - DeviceState* device_state = new DeviceState(); |
| - device_state->name = device_info->friendly_name; |
| - device_state->address = BluetoothAddressToString(device_info->address); |
| - device_state->visible = device_info->visible; |
| - device_state->authenticated = device_info->authenticated; |
| - device_state->connected = device_info->connected; |
| - device_state->path = device_info->path; |
| - |
| - ScopedVector<win::BluetoothLowEnergyServiceInfo> services; |
| - success = win::EnumerateKnownBluetoothLowEnergyServices( |
| - device_info, &services, &error); |
| - if (success) { |
| - for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator |
| - iter2 = services.begin(); |
| - iter2 != services.end(); |
| - ++iter2) { |
| - ServiceRecordState* service_state = new ServiceRecordState(); |
| - service_state->gatt_uuid = |
| - BluetoothLowEnergyUuidToUBluetoothUuid((*iter2)->uuid); |
| - device_state->service_record_states.push_back(service_state); |
| - } |
| - } |
| - device_list->push_back(device_state); |
| - } |
| - } |
| + if (SearchDevices(1, true, device_list)) { |
| + ui_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, |
| + this, |
| + base::Owned(device_list))); |
| } |
| +} |
| - if (device_list->empty()) { |
| - delete device_list; |
| - return; |
| - } |
| - DiscoverServices(device_list); |
| - ui_task_runner_->PostTask( |
| - FROM_HERE, |
| - base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated, |
| - this, |
| - base::Owned(device_list))); |
| +bool BluetoothTaskManagerWin::SearchDevices( |
| + int timeout_multiplier, |
| + bool search_cached_devices_only, |
| + ScopedVector<DeviceState>* device_list) { |
| + return SearchClassicDevices( |
| + timeout_multiplier, search_cached_devices_only, device_list) && |
| + SearchLowEnergyDevices(device_list) && |
| + DiscoverServices(device_list, search_cached_devices_only); |
| } |
| -void BluetoothTaskManagerWin::SearchDevices( |
| - int timeout, |
| +bool BluetoothTaskManagerWin::SearchClassicDevices( |
| + int timeout_multiplier, |
| bool search_cached_devices_only, |
| ScopedVector<DeviceState>* device_list) { |
| - BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { |
| - sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), |
| - 1, // return authenticated devices |
| - 1, // return remembered devicess |
| - search_cached_devices_only ? 0 : 1, // return unknown devices |
| - 1, // return connected devices |
| - search_cached_devices_only ? 0 : 1, // issue a new inquiry |
| - timeout, // timeout for the inquiry in increments of 1.28 seconds |
| - adapter_handle_ |
| - }; |
| - |
| - BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; |
| - // Issues a device inquiry and waits for |timeout| * 1.28 seconds. |
| + // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds. |
| + BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params; |
| + ZeroMemory(&device_search_params, sizeof(device_search_params)); |
| + device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS); |
| + device_search_params.fReturnAuthenticated = 1; |
| + device_search_params.fReturnRemembered = 1; |
| + device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1); |
| + device_search_params.fReturnConnected = 1; |
| + device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1); |
| + device_search_params.cTimeoutMultiplier = timeout_multiplier; |
| + |
| + BLUETOOTH_DEVICE_INFO device_info; |
| + ZeroMemory(&device_info, sizeof(device_info)); |
| + device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); |
| HBLUETOOTH_DEVICE_FIND handle = |
| BluetoothFindFirstDevice(&device_search_params, &device_info); |
| - if (handle) { |
| - do { |
| - DeviceState* device_state = new DeviceState(); |
| - GetDeviceState(device_info, device_state); |
| - device_list->push_back(device_state); |
| - } while (BluetoothFindNextDevice(handle, &device_info)); |
| - |
| - BluetoothFindDeviceClose(handle); |
| + if (!handle) { |
| + int last_error = GetLastError(); |
| + if (last_error == ERROR_NO_MORE_ITEMS) { |
| + return true; // No devices is not an error. |
| + } |
| + LogPollingError("Error calling BluetoothFindFirstDevice", last_error); |
| + return false; |
| } |
| + |
| + while (true) { |
| + DeviceState* device_state = new DeviceState(); |
| + GetDeviceState(device_info, device_state); |
| + device_list->push_back(device_state); |
| + |
| + // Reset device info before next call (as a safety precaution). |
| + ZeroMemory(&device_info, sizeof(device_info)); |
| + device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); |
| + if (!BluetoothFindNextDevice(handle, &device_info)) { |
| + int last_error = GetLastError(); |
| + if (last_error == ERROR_NO_MORE_ITEMS) { |
| + break; // No more items is expected error when done enumerating. |
| + } |
| + LogPollingError("Error calling BluetoothFindNextDevice", last_error); |
| + BluetoothFindDeviceClose(handle); |
| + return false; |
| + } |
| + } |
| + |
| + if (!BluetoothFindDeviceClose(handle)) { |
| + LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError()); |
| + return false; |
| + } |
| + return true; |
| } |
| -void BluetoothTaskManagerWin::DiscoverServices( |
| +bool BluetoothTaskManagerWin::SearchLowEnergyDevices( |
| ScopedVector<DeviceState>* device_list) { |
| + if (!win::IsBluetoothLowEnergySupported()) |
| + return true; // Bluetooth LE not supported is not an error. |
| + |
| + ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices; |
| + std::string error; |
| + bool success = |
| + win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error); |
| + if (!success) { |
| + LogPollingError(error.c_str(), 0); |
| + return false; |
| + } |
| + |
| + for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter = |
| + btle_devices.begin(); |
| + iter != btle_devices.end(); |
| + ++iter) { |
| + win::BluetoothLowEnergyDeviceInfo* device_info = (*iter); |
| + DeviceState* device_state = new DeviceState(); |
| + device_state->name = device_info->friendly_name; |
| + device_state->address = |
| + BluetoothAddressToCanonicalString(device_info->address); |
| + device_state->visible = device_info->visible; |
| + device_state->authenticated = device_info->authenticated; |
| + device_state->connected = device_info->connected; |
| + device_state->path = device_info->path; |
| + device_list->push_back(device_state); |
| + } |
| + return true; |
| +} |
| + |
| +bool BluetoothTaskManagerWin::DiscoverServices( |
| + ScopedVector<DeviceState>* device_list, |
| + bool search_cached_services_only) { |
| DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
| net::EnsureWinsockInit(); |
| for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); |
| iter != device_list->end(); |
| ++iter) { |
| - const std::string device_address = (*iter)->address; |
| + DeviceState* device = (*iter); |
| ScopedVector<ServiceRecordState>* service_record_states = |
| &(*iter)->service_record_states; |
| - DiscoverDeviceServices( |
| - device_address, L2CAP_PROTOCOL_UUID, service_record_states); |
| + if ((*iter)->is_bluetooth_classic()) { |
| + if (!DiscoverClassicDeviceServices(device->address, |
| + L2CAP_PROTOCOL_UUID, |
| + search_cached_services_only, |
| + service_record_states)) { |
| + return false; |
| + } |
| + } else { |
| + if (!DiscoverLowEnergyDeviceServices(device->path, |
| + service_record_states)) { |
| + return false; |
| + } |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices( |
| + const std::string& device_address, |
| + const GUID& protocol_uuid, |
| + bool search_cached_services_only, |
| + ScopedVector<ServiceRecordState>* service_record_states) { |
| + // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. |
| + WSAQUERYSET sdp_query; |
| + ZeroMemory(&sdp_query, sizeof(sdp_query)); |
| + sdp_query.dwSize = sizeof(sdp_query); |
| + GUID protocol = protocol_uuid; |
| + sdp_query.lpServiceClassId = &protocol; |
| + sdp_query.dwNameSpace = NS_BTH; |
| + wchar_t device_address_context[kMaxNumDeviceAddressChar]; |
| + std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( |
| + device_address_context, kMaxNumDeviceAddressChar); |
| + device_address_context[length] = NULL; |
| + sdp_query.lpszContext = device_address_context; |
| + DWORD control_flags = LUP_RETURN_ALL; |
| + // See http://goo.gl/t1Hulo: "Applications should generally specify |
| + // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached |
| + // information and establish an over-the-air SDP connection to the specified |
| + // device to perform the SDP search. This non-cached operation may take |
| + // several seconds (whereas a cached search returns quickly)." |
| + // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list |
| + // of services for devices which have not been discovered before. |
| + if (!search_cached_services_only) |
| + control_flags |= LUP_FLUSHCACHE; |
| + HANDLE sdp_handle; |
| + if (ERROR_SUCCESS != |
| + WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) { |
| + LogPollingError("Error calling WSALookupServiceBegin", WSAGetLastError()); |
| + return false; |
| + } |
| + char sdp_buffer[kServiceDiscoveryResultBufferSize]; |
| + LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); |
| + while (true) { |
| + DWORD sdp_buffer_size = sizeof(sdp_buffer); |
| + if (ERROR_SUCCESS != |
| + WSALookupServiceNext( |
| + sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) { |
| + int last_error = WSAGetLastError(); |
| + if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) { |
| + break; |
| + } |
| + LogPollingError("Error calling WSALookupServiceNext", last_error); |
| + WSALookupServiceEnd(sdp_handle); |
| + return false; |
| + } |
| + ServiceRecordState* service_record_state = new ServiceRecordState(); |
| + service_record_state->name = |
| + base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); |
| + for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { |
| + service_record_state->sdp_bytes.push_back( |
| + sdp_result_data->lpBlob->pBlobData[i]); |
| + } |
| + service_record_states->push_back(service_record_state); |
| + } |
| + if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) { |
| + LogPollingError("Error calling WSALookupServiceEnd", WSAGetLastError()); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices( |
| + const base::FilePath& device_path, |
| + ScopedVector<ServiceRecordState>* service_record_states) { |
| + if (!win::IsBluetoothLowEnergySupported()) |
| + return true; // Bluetooth LE not supported is not an error. |
| + |
| + std::string error; |
| + ScopedVector<win::BluetoothLowEnergyServiceInfo> services; |
| + bool success = win::EnumerateKnownBluetoothLowEnergyServices( |
| + device_path, &services, &error); |
| + if (!success) { |
| + LogPollingError(error.c_str(), 0); |
| + return false; |
| + } |
| + |
| + for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 = |
| + services.begin(); |
| + iter2 != services.end(); |
| + ++iter2) { |
| + ServiceRecordState* service_state = new ServiceRecordState(); |
| + service_state->gatt_uuid = |
| + BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid); |
| + service_record_states->push_back(service_state); |
| } |
| + return true; |
| } |
| } // namespace device |