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. 4 5 #include "device/bluetooth/bluetooth_task_manager_win.h" 6 7 #include <winsock2.h> 8 9 #include <string> 10 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" 25 26 namespace { 27 28 const int kNumThreadsInWorkerPool = 3; 29 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; 30 const int kMaxNumDeviceAddressChar = 127; 31 const int kServiceDiscoveryResultBufferSize = 5000; 32 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; 39 40 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; 41 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; 54 } 55 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])); 76 } 77 } 78 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); 92 } 93 state->name = name; 94 state->address = address; 95 state->powered = powered; 96 } 97 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; 106 } 107 108 } // namespace 109 110 namespace device { 111 112 // static 113 const int BluetoothTaskManagerWin::kPollIntervalMs = 500; 114 115 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) { 116 } 117 118 BluetoothTaskManagerWin::AdapterState::~AdapterState() { 119 } 120 121 BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() { 122 } 123 124 BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() { 125 } 126 127 BluetoothTaskManagerWin::DeviceState::DeviceState() 128 : bluetooth_class(0), 129 visible(false), 130 connected(false), 131 authenticated(false) { 132 } 133 134 BluetoothTaskManagerWin::DeviceState::~DeviceState() { 135 } 136 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) { 142 } 143 144 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { 145 } 146 147 void BluetoothTaskManagerWin::AddObserver(Observer* observer) { 148 DCHECK(observer); 149 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 150 observers_.AddObserver(observer); 151 } 152 153 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) { 154 DCHECK(observer); 155 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 156 observers_.RemoveObserver(observer); 157 } 158 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)); 167 } 168 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)); 176 } 177 178 void BluetoothTaskManagerWin::StartPolling() { 179 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 180 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))); 193 } 194 } 195 196 void BluetoothTaskManagerWin::Shutdown() { 197 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 198 if (worker_pool_) 199 worker_pool_->Shutdown(); 200 } 201 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)); 214 } 215 216 void BluetoothTaskManagerWin::PostStartDiscoveryTask() { 217 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 218 bluetooth_task_runner_->PostTask( 219 FROM_HERE, 220 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); 221 } 222 223 void BluetoothTaskManagerWin::PostStopDiscoveryTask() { 224 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 225 bluetooth_task_runner_->PostTask( 226 FROM_HERE, 227 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); 228 } 229 230 void BluetoothTaskManagerWin::LogPollingError(const char* message, 231 int win32_error) { 232 const int kLogPeriodInMilliseconds = 60 * 1000; 233 const int kMaxMessagesPerLogPeriod = 10; 234 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(); 244 } 245 } 246 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; 251 } 252 ++current_logging_batch_count_; 253 254 // Log the message 255 if (win32_error == 0) 256 LOG(WARNING) << message; 257 else 258 LOG(WARNING) << message << ": " 259 << logging::SystemErrorCodeToString(win32_error); 260 } 261 262 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { 263 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 264 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 265 AdapterStateChanged(*state)); 266 } 267 268 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { 269 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 270 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 271 DiscoveryStarted(success)); 272 } 273 274 void BluetoothTaskManagerWin::OnDiscoveryStopped() { 275 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 276 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 277 DiscoveryStopped()); 278 } 279 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)); 285 } 286 287 void BluetoothTaskManagerWin::PollAdapter() { 288 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 289 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); 299 300 if (handle) { 301 adapter_handle_.Set(temp_adapter_handle); 302 GetKnownDevices(); 303 BluetoothFindRadioClose(handle); 304 } 305 306 PostAdapterStateToUi(); 307 } 308 309 // Re-poll. 310 bluetooth_task_runner_->PostDelayedTask( 311 FROM_HERE, 312 base::Bind(&BluetoothTaskManagerWin::PollAdapter, 313 this), 314 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); 315 } 316 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))); 326 } 327 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); 338 } 339 340 if (success) { 341 PostAdapterStateToUi(); 342 ui_task_runner_->PostTask(FROM_HERE, callback); 343 } else { 344 ui_task_runner_->PostTask(FROM_HERE, error_callback); 345 } 346 } 347 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; 358 359 DiscoverDevices(1); 360 } 361 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)); 368 } 369 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; 377 } 378 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()))); 387 } 388 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)); 395 } 396 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()))); 406 } 407 } 408 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); 417 } 418 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; 433 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. 443 } 444 LogPollingError("Error calling BluetoothFindFirstDevice", last_error); 445 return false; 446 } 447 448 while (true) { 449 DeviceState* device_state = new DeviceState(); 450 GetDeviceState(device_info, device_state); 451 device_list->push_back(device_state); 452 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. 460 } 461 LogPollingError("Error calling BluetoothFindNextDevice", last_error); 462 BluetoothFindDeviceClose(handle); 463 return false; 464 } 465 } 466 467 if (!BluetoothFindDeviceClose(handle)) { 468 LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError()); 469 return false; 470 } 471 return true; 472 } 473 474 bool BluetoothTaskManagerWin::SearchLowEnergyDevices( 475 ScopedVector<DeviceState>* device_list) { 476 if (!win::IsBluetoothLowEnergySupported()) 477 return true; // Bluetooth LE not supported is not an error. 478 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; 486 } 487 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); 502 } 503 return true; 504 } 505 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; 517 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; 524 } 525 } else { 526 if (!DiscoverLowEnergyDeviceServices(device->path, 527 service_record_states)) { 528 return false; 529 } 530 } 531 } 532 return true; 533 } 534 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); 552 } 553 554 return (error_code == ERROR_SUCCESS); 555 } 556 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; 593 } 594 LogPollingError("Error calling WSALookupServiceBegin", last_error); 595 return last_error; 596 } 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; 607 } 608 LogPollingError("Error calling WSALookupServiceNext", last_error); 609 WSALookupServiceEnd(sdp_handle); 610 return last_error; 611 } 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]); 618 } 619 service_record_states->push_back(service_record_state); 620 } 621 if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) { 622 int last_error = WSAGetLastError(); 623 LogPollingError("Error calling WSALookupServiceEnd", last_error); 624 return last_error; 625 } 626 627 return ERROR_SUCCESS; 628 } 629 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. 635 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; 643 } 644 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); 653 } 654 return true; 655 } 656 657 } // namespace device 658