third_party: Add OWNERS for re2 library.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_task_manager_win.cc
blob4ebaa1012cc37e063530150da28eea9ce68d868d
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_.get())
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_.IsValid())
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_.Get(), 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_.IsValid()) {
335 if (!powered)
336 BluetoothEnableDiscovery(adapter_handle_.Get(), false);
337 success =
338 !!BluetoothEnableIncomingConnections(adapter_handle_.Get(), powered);
341 if (success) {
342 PostAdapterStateToUi();
343 ui_task_runner_->PostTask(FROM_HERE, callback);
344 } else {
345 ui_task_runner_->PostTask(FROM_HERE, error_callback);
349 void BluetoothTaskManagerWin::StartDiscovery() {
350 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
351 ui_task_runner_->PostTask(
352 FROM_HERE,
353 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
354 this,
355 adapter_handle_.IsValid()));
356 if (!adapter_handle_.IsValid())
357 return;
358 discovering_ = true;
360 DiscoverDevices(1);
363 void BluetoothTaskManagerWin::StopDiscovery() {
364 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
365 discovering_ = false;
366 ui_task_runner_->PostTask(
367 FROM_HERE,
368 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
371 void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
372 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
373 if (!discovering_ || !adapter_handle_.IsValid()) {
374 ui_task_runner_->PostTask(
375 FROM_HERE,
376 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
377 return;
380 scoped_ptr<ScopedVector<DeviceState> > device_list(
381 new ScopedVector<DeviceState>());
382 if (SearchDevices(timeout_multiplier, false, device_list.get())) {
383 ui_task_runner_->PostTask(
384 FROM_HERE,
385 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
386 this,
387 base::Owned(device_list.release())));
390 if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
391 ++timeout_multiplier;
392 bluetooth_task_runner_->PostTask(
393 FROM_HERE,
394 base::Bind(
395 &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
398 void BluetoothTaskManagerWin::GetKnownDevices() {
399 scoped_ptr<ScopedVector<DeviceState> > device_list(
400 new ScopedVector<DeviceState>());
401 if (SearchDevices(1, true, device_list.get())) {
402 ui_task_runner_->PostTask(
403 FROM_HERE,
404 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
405 this,
406 base::Owned(device_list.release())));
410 bool BluetoothTaskManagerWin::SearchDevices(
411 int timeout_multiplier,
412 bool search_cached_devices_only,
413 ScopedVector<DeviceState>* device_list) {
414 return SearchClassicDevices(
415 timeout_multiplier, search_cached_devices_only, device_list) &&
416 SearchLowEnergyDevices(device_list) &&
417 DiscoverServices(device_list, search_cached_devices_only);
420 bool BluetoothTaskManagerWin::SearchClassicDevices(
421 int timeout_multiplier,
422 bool search_cached_devices_only,
423 ScopedVector<DeviceState>* device_list) {
424 // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds.
425 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params;
426 ZeroMemory(&device_search_params, sizeof(device_search_params));
427 device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
428 device_search_params.fReturnAuthenticated = 1;
429 device_search_params.fReturnRemembered = 1;
430 device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1);
431 device_search_params.fReturnConnected = 1;
432 device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1);
433 device_search_params.cTimeoutMultiplier = timeout_multiplier;
435 BLUETOOTH_DEVICE_INFO device_info;
436 ZeroMemory(&device_info, sizeof(device_info));
437 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
438 HBLUETOOTH_DEVICE_FIND handle =
439 BluetoothFindFirstDevice(&device_search_params, &device_info);
440 if (!handle) {
441 int last_error = GetLastError();
442 if (last_error == ERROR_NO_MORE_ITEMS) {
443 return true; // No devices is not an error.
445 LogPollingError("Error calling BluetoothFindFirstDevice", last_error);
446 return false;
449 while (true) {
450 DeviceState* device_state = new DeviceState();
451 GetDeviceState(device_info, device_state);
452 device_list->push_back(device_state);
454 // Reset device info before next call (as a safety precaution).
455 ZeroMemory(&device_info, sizeof(device_info));
456 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
457 if (!BluetoothFindNextDevice(handle, &device_info)) {
458 int last_error = GetLastError();
459 if (last_error == ERROR_NO_MORE_ITEMS) {
460 break; // No more items is expected error when done enumerating.
462 LogPollingError("Error calling BluetoothFindNextDevice", last_error);
463 BluetoothFindDeviceClose(handle);
464 return false;
468 if (!BluetoothFindDeviceClose(handle)) {
469 LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError());
470 return false;
472 return true;
475 bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
476 ScopedVector<DeviceState>* device_list) {
477 if (!win::IsBluetoothLowEnergySupported())
478 return true; // Bluetooth LE not supported is not an error.
480 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
481 std::string error;
482 bool success =
483 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
484 if (!success) {
485 LogPollingError(error.c_str(), 0);
486 return false;
489 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
490 btle_devices.begin();
491 iter != btle_devices.end();
492 ++iter) {
493 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
494 DeviceState* device_state = new DeviceState();
495 device_state->name = device_info->friendly_name;
496 device_state->address =
497 BluetoothAddressToCanonicalString(device_info->address);
498 device_state->visible = device_info->visible;
499 device_state->authenticated = device_info->authenticated;
500 device_state->connected = device_info->connected;
501 device_state->path = device_info->path;
502 device_list->push_back(device_state);
504 return true;
507 bool BluetoothTaskManagerWin::DiscoverServices(
508 ScopedVector<DeviceState>* device_list,
509 bool search_cached_services_only) {
510 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
511 net::EnsureWinsockInit();
512 for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
513 iter != device_list->end();
514 ++iter) {
515 DeviceState* device = (*iter);
516 ScopedVector<ServiceRecordState>* service_record_states =
517 &(*iter)->service_record_states;
519 if ((*iter)->is_bluetooth_classic()) {
520 if (!DiscoverClassicDeviceServices(device->address,
521 L2CAP_PROTOCOL_UUID,
522 search_cached_services_only,
523 service_record_states)) {
524 return false;
526 } else {
527 if (!DiscoverLowEnergyDeviceServices(device->path,
528 service_record_states)) {
529 return false;
533 return true;
536 bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
537 const std::string& device_address,
538 const GUID& protocol_uuid,
539 bool search_cached_services_only,
540 ScopedVector<ServiceRecordState>* service_record_states) {
541 int error_code =
542 DiscoverClassicDeviceServicesWorker(device_address,
543 protocol_uuid,
544 search_cached_services_only,
545 service_record_states);
546 // If the device is "offline", no services are returned when specifying
547 // "LUP_FLUSHCACHE". Try again without flushing the cache so that the list
548 // of previously known services is returned.
549 if (!search_cached_services_only &&
550 (error_code == WSASERVICE_NOT_FOUND || error_code == WSANO_DATA)) {
551 error_code = DiscoverClassicDeviceServicesWorker(
552 device_address, protocol_uuid, true, service_record_states);
555 return (error_code == ERROR_SUCCESS);
558 int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker(
559 const std::string& device_address,
560 const GUID& protocol_uuid,
561 bool search_cached_services_only,
562 ScopedVector<ServiceRecordState>* service_record_states) {
563 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
564 WSAQUERYSET sdp_query;
565 ZeroMemory(&sdp_query, sizeof(sdp_query));
566 sdp_query.dwSize = sizeof(sdp_query);
567 GUID protocol = protocol_uuid;
568 sdp_query.lpServiceClassId = &protocol;
569 sdp_query.dwNameSpace = NS_BTH;
570 wchar_t device_address_context[kMaxNumDeviceAddressChar];
571 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
572 device_address_context, kMaxNumDeviceAddressChar);
573 device_address_context[length] = NULL;
574 sdp_query.lpszContext = device_address_context;
575 DWORD control_flags = LUP_RETURN_ALL;
576 // See http://goo.gl/t1Hulo: "Applications should generally specify
577 // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached
578 // information and establish an over-the-air SDP connection to the specified
579 // device to perform the SDP search. This non-cached operation may take
580 // several seconds (whereas a cached search returns quickly)."
581 // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list
582 // of services for devices which have not been discovered before.
583 if (!search_cached_services_only)
584 control_flags |= LUP_FLUSHCACHE;
585 HANDLE sdp_handle;
586 if (ERROR_SUCCESS !=
587 WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) {
588 int last_error = WSAGetLastError();
589 // If the device is "offline", no services are returned when specifying
590 // "LUP_FLUSHCACHE". Don't log error in that case.
591 if (!search_cached_services_only &&
592 (last_error == WSASERVICE_NOT_FOUND || last_error == WSANO_DATA)) {
593 return last_error;
595 LogPollingError("Error calling WSALookupServiceBegin", last_error);
596 return last_error;
598 char sdp_buffer[kServiceDiscoveryResultBufferSize];
599 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
600 while (true) {
601 DWORD sdp_buffer_size = sizeof(sdp_buffer);
602 if (ERROR_SUCCESS !=
603 WSALookupServiceNext(
604 sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) {
605 int last_error = WSAGetLastError();
606 if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) {
607 break;
609 LogPollingError("Error calling WSALookupServiceNext", last_error);
610 WSALookupServiceEnd(sdp_handle);
611 return last_error;
613 ServiceRecordState* service_record_state = new ServiceRecordState();
614 service_record_state->name =
615 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
616 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
617 service_record_state->sdp_bytes.push_back(
618 sdp_result_data->lpBlob->pBlobData[i]);
620 service_record_states->push_back(service_record_state);
622 if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
623 int last_error = WSAGetLastError();
624 LogPollingError("Error calling WSALookupServiceEnd", last_error);
625 return last_error;
628 return ERROR_SUCCESS;
631 bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
632 const base::FilePath& device_path,
633 ScopedVector<ServiceRecordState>* service_record_states) {
634 if (!win::IsBluetoothLowEnergySupported())
635 return true; // Bluetooth LE not supported is not an error.
637 std::string error;
638 ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
639 bool success = win::EnumerateKnownBluetoothLowEnergyServices(
640 device_path, &services, &error);
641 if (!success) {
642 LogPollingError(error.c_str(), 0);
643 return false;
646 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 =
647 services.begin();
648 iter2 != services.end();
649 ++iter2) {
650 ServiceRecordState* service_state = new ServiceRecordState();
651 service_state->gatt_uuid =
652 BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid);
653 service_record_states->push_back(service_state);
655 return true;
658 } // namespace device