Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / device / bluetooth / bluetooth_task_manager_win.cc
blobd89c1a03fde3b11707bd23b2ebff4132d2fb77f4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_task_manager_win.h"
7 #include <winsock2.h>
9 #include <string>
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/win/scoped_handle.h"
20 #include "device/bluetooth/bluetooth_device.h"
21 #include "device/bluetooth/bluetooth_init_win.h"
22 #include "device/bluetooth/bluetooth_low_energy_win.h"
23 #include "device/bluetooth/bluetooth_service_record_win.h"
24 #include "net/base/winsock_init.h"
26 namespace {
28 const int kNumThreadsInWorkerPool = 3;
29 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
30 const int kMaxNumDeviceAddressChar = 127;
31 const int kServiceDiscoveryResultBufferSize = 5000;
33 // See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time
34 // out for the inquiry, expressed in increments of 1.28 seconds. For example, an
35 // inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum
36 // value for this member is 48. When a value greater than 48 is used, the
37 // calling function immediately fails and returns
38 const int kMaxDeviceDiscoveryTimeoutMultiplier = 48;
40 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
42 // Note: The string returned here must have the same format as
43 // BluetoothDevice::CanonicalizeAddress.
44 std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) {
45 std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
46 btha.rgBytes[5],
47 btha.rgBytes[4],
48 btha.rgBytes[3],
49 btha.rgBytes[2],
50 btha.rgBytes[1],
51 btha.rgBytes[0]);
52 DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result));
53 return result;
56 device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid(
57 const BTH_LE_UUID& bth_le_uuid) {
58 if (bth_le_uuid.IsShortUuid) {
59 std::string uuid_hex =
60 base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid);
61 return device::BluetoothUUID(uuid_hex);
62 } else {
63 return device::BluetoothUUID(
64 base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
65 bth_le_uuid.Value.LongUuid.Data1,
66 bth_le_uuid.Value.LongUuid.Data2,
67 bth_le_uuid.Value.LongUuid.Data3,
68 bth_le_uuid.Value.LongUuid.Data4[0],
69 bth_le_uuid.Value.LongUuid.Data4[1],
70 bth_le_uuid.Value.LongUuid.Data4[2],
71 bth_le_uuid.Value.LongUuid.Data4[3],
72 bth_le_uuid.Value.LongUuid.Data4[4],
73 bth_le_uuid.Value.LongUuid.Data4[5],
74 bth_le_uuid.Value.LongUuid.Data4[6],
75 bth_le_uuid.Value.LongUuid.Data4[7]));
79 // Populates bluetooth adapter state using adapter_handle.
80 void GetAdapterState(HANDLE adapter_handle,
81 device::BluetoothTaskManagerWin::AdapterState* state) {
82 std::string name;
83 std::string address;
84 bool powered = false;
85 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
86 if (adapter_handle &&
87 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
88 &adapter_info)) {
89 name = base::SysWideToUTF8(adapter_info.szName);
90 address = BluetoothAddressToCanonicalString(adapter_info.address);
91 powered = !!BluetoothIsConnectable(adapter_handle);
93 state->name = name;
94 state->address = address;
95 state->powered = powered;
98 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
99 device::BluetoothTaskManagerWin::DeviceState* state) {
100 state->name = base::SysWideToUTF8(device_info.szName);
101 state->address = BluetoothAddressToCanonicalString(device_info.Address);
102 state->bluetooth_class = device_info.ulClassofDevice;
103 state->visible = true;
104 state->connected = !!device_info.fConnected;
105 state->authenticated = !!device_info.fAuthenticated;
108 } // namespace
110 namespace device {
112 // static
113 const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
115 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) {
118 BluetoothTaskManagerWin::AdapterState::~AdapterState() {
121 BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() {
124 BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() {
127 BluetoothTaskManagerWin::DeviceState::DeviceState()
128 : bluetooth_class(0),
129 visible(false),
130 connected(false),
131 authenticated(false) {
134 BluetoothTaskManagerWin::DeviceState::~DeviceState() {
137 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
138 scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
139 : ui_task_runner_(ui_task_runner),
140 discovering_(false),
141 current_logging_batch_count_(0) {
144 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
147 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
148 DCHECK(observer);
149 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
150 observers_.AddObserver(observer);
153 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
154 DCHECK(observer);
155 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
156 observers_.RemoveObserver(observer);
159 void BluetoothTaskManagerWin::Initialize() {
160 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
161 worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool,
162 kBluetoothThreadName);
163 InitializeWithBluetoothTaskRunner(
164 worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
165 worker_pool_->GetSequenceToken(),
166 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
169 void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
170 scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
171 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
172 bluetooth_task_runner_ = bluetooth_task_runner;
173 bluetooth_task_runner_->PostTask(
174 FROM_HERE,
175 base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
178 void BluetoothTaskManagerWin::StartPolling() {
179 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
181 if (device::bluetooth_init_win::HasBluetoothStack()) {
182 PollAdapter();
183 } else {
184 // IF the bluetooth stack is not available, we still send an empty state
185 // to BluetoothAdapter so that it is marked initialized, but the adapter
186 // will not be present.
187 AdapterState* state = new AdapterState();
188 ui_task_runner_->PostTask(
189 FROM_HERE,
190 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
191 this,
192 base::Owned(state)));
196 void BluetoothTaskManagerWin::Shutdown() {
197 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
198 if (worker_pool_)
199 worker_pool_->Shutdown();
202 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
203 bool powered,
204 const base::Closure& callback,
205 const BluetoothAdapter::ErrorCallback& error_callback) {
206 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
207 bluetooth_task_runner_->PostTask(
208 FROM_HERE,
209 base::Bind(&BluetoothTaskManagerWin::SetPowered,
210 this,
211 powered,
212 callback,
213 error_callback));
216 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
217 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
218 bluetooth_task_runner_->PostTask(
219 FROM_HERE,
220 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
223 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
224 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
225 bluetooth_task_runner_->PostTask(
226 FROM_HERE,
227 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
230 void BluetoothTaskManagerWin::LogPollingError(const char* message,
231 int win32_error) {
232 const int kLogPeriodInMilliseconds = 60 * 1000;
233 const int kMaxMessagesPerLogPeriod = 10;
235 // Check if we need to discard this message
236 if (!current_logging_batch_ticks_.is_null()) {
237 if (base::TimeTicks::Now() - current_logging_batch_ticks_ <=
238 base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) {
239 if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod)
240 return;
241 } else {
242 // The batch expired, reset it to "null".
243 current_logging_batch_ticks_ = base::TimeTicks();
247 // Keep track of this batch of messages
248 if (current_logging_batch_ticks_.is_null()) {
249 current_logging_batch_ticks_ = base::TimeTicks::Now();
250 current_logging_batch_count_ = 0;
252 ++current_logging_batch_count_;
254 // Log the message
255 if (win32_error == 0)
256 LOG(WARNING) << message;
257 else
258 LOG(WARNING) << message << ": "
259 << logging::SystemErrorCodeToString(win32_error);
262 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
263 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
264 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
265 AdapterStateChanged(*state));
268 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
269 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
270 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
271 DiscoveryStarted(success));
274 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
275 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
276 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
277 DiscoveryStopped());
280 void BluetoothTaskManagerWin::OnDevicesPolled(
281 const ScopedVector<DeviceState>* devices) {
282 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
283 FOR_EACH_OBSERVER(
284 BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices));
287 void BluetoothTaskManagerWin::PollAdapter() {
288 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
290 // Skips updating the adapter info if the adapter is in discovery mode.
291 if (!discovering_) {
292 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
293 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
294 if (adapter_handle_)
295 adapter_handle_.Close();
296 HANDLE temp_adapter_handle;
297 HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
298 &adapter_param, &temp_adapter_handle);
300 if (handle) {
301 adapter_handle_.Set(temp_adapter_handle);
302 GetKnownDevices();
303 BluetoothFindRadioClose(handle);
306 PostAdapterStateToUi();
309 // Re-poll.
310 bluetooth_task_runner_->PostDelayedTask(
311 FROM_HERE,
312 base::Bind(&BluetoothTaskManagerWin::PollAdapter,
313 this),
314 base::TimeDelta::FromMilliseconds(kPollIntervalMs));
317 void BluetoothTaskManagerWin::PostAdapterStateToUi() {
318 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
319 AdapterState* state = new AdapterState();
320 GetAdapterState(adapter_handle_, state);
321 ui_task_runner_->PostTask(
322 FROM_HERE,
323 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
324 this,
325 base::Owned(state)));
328 void BluetoothTaskManagerWin::SetPowered(
329 bool powered,
330 const base::Closure& callback,
331 const BluetoothAdapter::ErrorCallback& error_callback) {
332 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
333 bool success = false;
334 if (adapter_handle_) {
335 if (!powered)
336 BluetoothEnableDiscovery(adapter_handle_, false);
337 success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
340 if (success) {
341 PostAdapterStateToUi();
342 ui_task_runner_->PostTask(FROM_HERE, callback);
343 } else {
344 ui_task_runner_->PostTask(FROM_HERE, error_callback);
348 void BluetoothTaskManagerWin::StartDiscovery() {
349 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
350 ui_task_runner_->PostTask(
351 FROM_HERE,
352 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
353 this,
354 !!adapter_handle_));
355 if (!adapter_handle_)
356 return;
357 discovering_ = true;
359 DiscoverDevices(1);
362 void BluetoothTaskManagerWin::StopDiscovery() {
363 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
364 discovering_ = false;
365 ui_task_runner_->PostTask(
366 FROM_HERE,
367 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
370 void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
371 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
372 if (!discovering_ || !adapter_handle_) {
373 ui_task_runner_->PostTask(
374 FROM_HERE,
375 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
376 return;
379 scoped_ptr<ScopedVector<DeviceState> > device_list(
380 new ScopedVector<DeviceState>());
381 if (SearchDevices(timeout_multiplier, false, device_list.get())) {
382 ui_task_runner_->PostTask(
383 FROM_HERE,
384 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
385 this,
386 base::Owned(device_list.release())));
389 if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
390 ++timeout_multiplier;
391 bluetooth_task_runner_->PostTask(
392 FROM_HERE,
393 base::Bind(
394 &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
397 void BluetoothTaskManagerWin::GetKnownDevices() {
398 scoped_ptr<ScopedVector<DeviceState> > device_list(
399 new ScopedVector<DeviceState>());
400 if (SearchDevices(1, true, device_list.get())) {
401 ui_task_runner_->PostTask(
402 FROM_HERE,
403 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
404 this,
405 base::Owned(device_list.release())));
409 bool BluetoothTaskManagerWin::SearchDevices(
410 int timeout_multiplier,
411 bool search_cached_devices_only,
412 ScopedVector<DeviceState>* device_list) {
413 return SearchClassicDevices(
414 timeout_multiplier, search_cached_devices_only, device_list) &&
415 SearchLowEnergyDevices(device_list) &&
416 DiscoverServices(device_list, search_cached_devices_only);
419 bool BluetoothTaskManagerWin::SearchClassicDevices(
420 int timeout_multiplier,
421 bool search_cached_devices_only,
422 ScopedVector<DeviceState>* device_list) {
423 // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds.
424 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params;
425 ZeroMemory(&device_search_params, sizeof(device_search_params));
426 device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
427 device_search_params.fReturnAuthenticated = 1;
428 device_search_params.fReturnRemembered = 1;
429 device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1);
430 device_search_params.fReturnConnected = 1;
431 device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1);
432 device_search_params.cTimeoutMultiplier = timeout_multiplier;
434 BLUETOOTH_DEVICE_INFO device_info;
435 ZeroMemory(&device_info, sizeof(device_info));
436 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
437 HBLUETOOTH_DEVICE_FIND handle =
438 BluetoothFindFirstDevice(&device_search_params, &device_info);
439 if (!handle) {
440 int last_error = GetLastError();
441 if (last_error == ERROR_NO_MORE_ITEMS) {
442 return true; // No devices is not an error.
444 LogPollingError("Error calling BluetoothFindFirstDevice", last_error);
445 return false;
448 while (true) {
449 DeviceState* device_state = new DeviceState();
450 GetDeviceState(device_info, device_state);
451 device_list->push_back(device_state);
453 // Reset device info before next call (as a safety precaution).
454 ZeroMemory(&device_info, sizeof(device_info));
455 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
456 if (!BluetoothFindNextDevice(handle, &device_info)) {
457 int last_error = GetLastError();
458 if (last_error == ERROR_NO_MORE_ITEMS) {
459 break; // No more items is expected error when done enumerating.
461 LogPollingError("Error calling BluetoothFindNextDevice", last_error);
462 BluetoothFindDeviceClose(handle);
463 return false;
467 if (!BluetoothFindDeviceClose(handle)) {
468 LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError());
469 return false;
471 return true;
474 bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
475 ScopedVector<DeviceState>* device_list) {
476 if (!win::IsBluetoothLowEnergySupported())
477 return true; // Bluetooth LE not supported is not an error.
479 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
480 std::string error;
481 bool success =
482 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
483 if (!success) {
484 LogPollingError(error.c_str(), 0);
485 return false;
488 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
489 btle_devices.begin();
490 iter != btle_devices.end();
491 ++iter) {
492 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
493 DeviceState* device_state = new DeviceState();
494 device_state->name = device_info->friendly_name;
495 device_state->address =
496 BluetoothAddressToCanonicalString(device_info->address);
497 device_state->visible = device_info->visible;
498 device_state->authenticated = device_info->authenticated;
499 device_state->connected = device_info->connected;
500 device_state->path = device_info->path;
501 device_list->push_back(device_state);
503 return true;
506 bool BluetoothTaskManagerWin::DiscoverServices(
507 ScopedVector<DeviceState>* device_list,
508 bool search_cached_services_only) {
509 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
510 net::EnsureWinsockInit();
511 for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
512 iter != device_list->end();
513 ++iter) {
514 DeviceState* device = (*iter);
515 ScopedVector<ServiceRecordState>* service_record_states =
516 &(*iter)->service_record_states;
518 if ((*iter)->is_bluetooth_classic()) {
519 if (!DiscoverClassicDeviceServices(device->address,
520 L2CAP_PROTOCOL_UUID,
521 search_cached_services_only,
522 service_record_states)) {
523 return false;
525 } else {
526 if (!DiscoverLowEnergyDeviceServices(device->path,
527 service_record_states)) {
528 return false;
532 return true;
535 bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
536 const std::string& device_address,
537 const GUID& protocol_uuid,
538 bool search_cached_services_only,
539 ScopedVector<ServiceRecordState>* service_record_states) {
540 int error_code =
541 DiscoverClassicDeviceServicesWorker(device_address,
542 protocol_uuid,
543 search_cached_services_only,
544 service_record_states);
545 // If the device is "offline", no services are returned when specifying
546 // "LUP_FLUSHCACHE". Try again without flushing the cache so that the list
547 // of previously known services is returned.
548 if (!search_cached_services_only &&
549 (error_code == WSASERVICE_NOT_FOUND || error_code == WSANO_DATA)) {
550 error_code = DiscoverClassicDeviceServicesWorker(
551 device_address, protocol_uuid, true, service_record_states);
554 return (error_code == ERROR_SUCCESS);
557 int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker(
558 const std::string& device_address,
559 const GUID& protocol_uuid,
560 bool search_cached_services_only,
561 ScopedVector<ServiceRecordState>* service_record_states) {
562 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
563 WSAQUERYSET sdp_query;
564 ZeroMemory(&sdp_query, sizeof(sdp_query));
565 sdp_query.dwSize = sizeof(sdp_query);
566 GUID protocol = protocol_uuid;
567 sdp_query.lpServiceClassId = &protocol;
568 sdp_query.dwNameSpace = NS_BTH;
569 wchar_t device_address_context[kMaxNumDeviceAddressChar];
570 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
571 device_address_context, kMaxNumDeviceAddressChar);
572 device_address_context[length] = NULL;
573 sdp_query.lpszContext = device_address_context;
574 DWORD control_flags = LUP_RETURN_ALL;
575 // See http://goo.gl/t1Hulo: "Applications should generally specify
576 // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached
577 // information and establish an over-the-air SDP connection to the specified
578 // device to perform the SDP search. This non-cached operation may take
579 // several seconds (whereas a cached search returns quickly)."
580 // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list
581 // of services for devices which have not been discovered before.
582 if (!search_cached_services_only)
583 control_flags |= LUP_FLUSHCACHE;
584 HANDLE sdp_handle;
585 if (ERROR_SUCCESS !=
586 WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) {
587 int last_error = WSAGetLastError();
588 // If the device is "offline", no services are returned when specifying
589 // "LUP_FLUSHCACHE". Don't log error in that case.
590 if (!search_cached_services_only &&
591 (last_error == WSASERVICE_NOT_FOUND || last_error == WSANO_DATA)) {
592 return last_error;
594 LogPollingError("Error calling WSALookupServiceBegin", last_error);
595 return last_error;
597 char sdp_buffer[kServiceDiscoveryResultBufferSize];
598 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
599 while (true) {
600 DWORD sdp_buffer_size = sizeof(sdp_buffer);
601 if (ERROR_SUCCESS !=
602 WSALookupServiceNext(
603 sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) {
604 int last_error = WSAGetLastError();
605 if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) {
606 break;
608 LogPollingError("Error calling WSALookupServiceNext", last_error);
609 WSALookupServiceEnd(sdp_handle);
610 return last_error;
612 ServiceRecordState* service_record_state = new ServiceRecordState();
613 service_record_state->name =
614 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
615 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
616 service_record_state->sdp_bytes.push_back(
617 sdp_result_data->lpBlob->pBlobData[i]);
619 service_record_states->push_back(service_record_state);
621 if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
622 int last_error = WSAGetLastError();
623 LogPollingError("Error calling WSALookupServiceEnd", last_error);
624 return last_error;
627 return ERROR_SUCCESS;
630 bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
631 const base::FilePath& device_path,
632 ScopedVector<ServiceRecordState>* service_record_states) {
633 if (!win::IsBluetoothLowEnergySupported())
634 return true; // Bluetooth LE not supported is not an error.
636 std::string error;
637 ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
638 bool success = win::EnumerateKnownBluetoothLowEnergyServices(
639 device_path, &services, &error);
640 if (!success) {
641 LogPollingError(error.c_str(), 0);
642 return false;
645 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 =
646 services.begin();
647 iter2 != services.end();
648 ++iter2) {
649 ServiceRecordState* service_state = new ServiceRecordState();
650 service_state->gatt_uuid =
651 BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid);
652 service_record_states->push_back(service_state);
654 return true;
657 } // namespace device