Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/bluetooth/bluetooth_socket_win.h" | 5 #include "device/bluetooth/bluetooth_socket_win.h" |
| 6 | 6 |
| 7 #include <objbase.h> | |
| 8 | |
| 7 #include <string> | 9 #include <string> |
| 8 | 10 |
| 9 #include "base/logging.h" | 11 #include "base/logging.h" |
| 10 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
| 11 #include "base/sequenced_task_runner.h" | 13 #include "base/sequenced_task_runner.h" |
| 12 #include "base/strings/sys_string_conversions.h" | 14 #include "base/strings/sys_string_conversions.h" |
| 15 #include "base/strings/utf_string_conversions.h" | |
| 13 #include "base/threading/thread_restrictions.h" | 16 #include "base/threading/thread_restrictions.h" |
| 14 #include "device/bluetooth/bluetooth_init_win.h" | 17 #include "device/bluetooth/bluetooth_init_win.h" |
| 15 #include "device/bluetooth/bluetooth_service_record_win.h" | 18 #include "device/bluetooth/bluetooth_service_record_win.h" |
| 16 #include "device/bluetooth/bluetooth_socket_thread_win.h" | 19 #include "device/bluetooth/bluetooth_socket_thread_win.h" |
| 17 #include "net/base/io_buffer.h" | 20 #include "net/base/io_buffer.h" |
| 18 #include "net/base/ip_endpoint.h" | 21 #include "net/base/ip_endpoint.h" |
| 19 #include "net/base/net_errors.h" | 22 #include "net/base/net_errors.h" |
| 20 #include "net/base/winsock_init.h" | 23 #include "net/base/winsock_init.h" |
| 21 | 24 |
| 22 namespace { | 25 namespace { |
| 23 | 26 |
| 24 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported"; | 27 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported"; |
| 25 const char kSocketAlreadyConnected[] = "Socket is already connected."; | 28 const char kSocketAlreadyConnected[] = "Socket is already connected."; |
| 26 const char kSocketNotConnected[] = "Socket is not connected."; | 29 const char kSocketNotConnected[] = "Socket is not connected."; |
| 30 const char kInvalidRfcommPort[] = "Invalid RFCCOMM port."; | |
| 31 const char kFailedToCreateSocket[] = "Failed to create socket."; | |
| 32 const char kFailedToBindSocket[] = "Failed to bind socket."; | |
| 33 const char kFailedToListenOnSocket[] = "Failed to listen on socket."; | |
| 34 const char kFailedToGetSockNameForSocket[] = "Failed to getsockname."; | |
| 35 const char kBadUuid[] = "Bad uuid."; | |
| 36 const char kWsaSetServiceError[] = "WSASetService error."; | |
| 27 | 37 |
| 28 using device::BluetoothSocketWin; | 38 using device::BluetoothSocketWin; |
| 29 | 39 |
| 30 std::string FormatErrorMessage(DWORD error_code) { | 40 std::string FormatErrorMessage(DWORD error_code) { |
| 31 TCHAR error_msg[1024]; | 41 TCHAR error_msg[1024]; |
| 32 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, | 42 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, |
| 33 0, | 43 0, |
| 34 error_code, | 44 error_code, |
| 35 0, | 45 0, |
| 36 error_msg, | 46 error_msg, |
| 37 1024, | 47 1024, |
| 38 NULL); | 48 NULL); |
| 39 return base::SysWideToUTF8(error_msg); | 49 return base::SysWideToUTF8(error_msg); |
| 40 } | 50 } |
| 41 | 51 |
| 42 static void DeactivateSocket( | 52 static void DeactivateSocket( |
| 43 const scoped_refptr<device::BluetoothSocketThreadWin>& socket_thread) { | 53 const scoped_refptr<device::BluetoothSocketThreadWin>& socket_thread) { |
| 44 socket_thread->OnSocketDeactivate(); | 54 socket_thread->OnSocketDeactivate(); |
| 45 } | 55 } |
| 46 | 56 |
| 47 } // namespace | 57 } // namespace |
| 48 | 58 |
| 49 namespace device { | 59 namespace device { |
| 50 | 60 |
| 61 struct BluetoothSocketWin::ServiceRegData { | |
| 62 ServiceRegData() { | |
| 63 ZeroMemory(this, sizeof(ServiceRegData)); | |
|
rpaquay
2014/04/23 22:52:06
Is it safe to ZeroMemory a struct that contains a
xiyuan
2014/04/23 23:19:42
Nope. Replaced with ZeroMemory on individual membe
| |
| 64 } | |
| 65 | |
| 66 SOCKADDR_BTH address; | |
| 67 CSADDR_INFO address_info; | |
| 68 GUID uuid; | |
| 69 base::string16 name; | |
| 70 WSAQUERYSET service; | |
| 71 }; | |
| 72 | |
| 51 // static | 73 // static |
| 52 scoped_refptr<BluetoothSocketWin> BluetoothSocketWin::CreateBluetoothSocket( | 74 scoped_refptr<BluetoothSocketWin> BluetoothSocketWin::CreateBluetoothSocket( |
| 53 const BluetoothServiceRecord& service_record, | |
| 54 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | 75 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
| 55 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | 76 scoped_refptr<BluetoothSocketThreadWin> socket_thread, |
| 56 net::NetLog* net_log, | 77 net::NetLog* net_log, |
| 57 const net::NetLog::Source& source) { | 78 const net::NetLog::Source& source) { |
| 58 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); | 79 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); |
| 59 const BluetoothServiceRecordWin* service_record_win = | |
| 60 static_cast<const BluetoothServiceRecordWin*>(&service_record); | |
| 61 | 80 |
| 62 scoped_refptr<BluetoothSocketWin> result( | 81 return make_scoped_refptr( |
| 63 new BluetoothSocketWin(ui_task_runner, socket_thread, net_log, source)); | 82 new BluetoothSocketWin(ui_task_runner, socket_thread, net_log, source)); |
| 64 result->device_address_ = service_record_win->address(); | |
| 65 if (service_record.SupportsRfcomm()) { | |
| 66 result->supports_rfcomm_ = true; | |
| 67 result->rfcomm_channel_ = service_record_win->rfcomm_channel(); | |
| 68 result->bth_addr_ = service_record_win->bth_addr(); | |
| 69 } | |
| 70 | |
| 71 return result; | |
| 72 } | 83 } |
| 73 | 84 |
| 74 BluetoothSocketWin::BluetoothSocketWin( | 85 BluetoothSocketWin::BluetoothSocketWin( |
| 75 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | 86 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
| 76 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | 87 scoped_refptr<BluetoothSocketThreadWin> socket_thread, |
| 77 net::NetLog* net_log, | 88 net::NetLog* net_log, |
| 78 const net::NetLog::Source& source) | 89 const net::NetLog::Source& source) |
| 79 : ui_task_runner_(ui_task_runner), | 90 : ui_task_runner_(ui_task_runner), |
| 80 socket_thread_(socket_thread), | 91 socket_thread_(socket_thread), |
| 81 net_log_(net_log), | 92 net_log_(net_log), |
| 82 source_(source), | 93 source_(source), |
| 83 supports_rfcomm_(false), | 94 supports_rfcomm_(false), |
| 84 rfcomm_channel_(-1), | 95 rfcomm_channel_(-1), |
| 85 bth_addr_(BTH_ADDR_NULL) { | 96 bth_addr_(BTH_ADDR_NULL) { |
| 86 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 97 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 87 socket_thread->OnSocketActivate(); | 98 socket_thread->OnSocketActivate(); |
| 88 } | 99 } |
| 89 | 100 |
| 90 BluetoothSocketWin::~BluetoothSocketWin() { | 101 BluetoothSocketWin::~BluetoothSocketWin() { |
| 91 ui_task_runner_->PostTask(FROM_HERE, | 102 ui_task_runner_->PostTask(FROM_HERE, |
| 92 base::Bind(&DeactivateSocket, socket_thread_)); | 103 base::Bind(&DeactivateSocket, socket_thread_)); |
| 93 } | 104 } |
| 94 | 105 |
| 106 void BluetoothSocketWin::StartService( | |
| 107 const BluetoothUUID& uuid, | |
| 108 const std::string& name, | |
| 109 int rfcomm_channel, | |
| 110 const base::Closure& success_callback, | |
| 111 const ErrorCompletionCallback& error_callback, | |
| 112 const OnNewConnectionCallback& new_connection_callback) { | |
| 113 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 114 | |
| 115 socket_thread_->task_runner()->PostTask( | |
| 116 FROM_HERE, | |
| 117 base::Bind(&BluetoothSocketWin::DoStartService, | |
| 118 this, | |
| 119 uuid, | |
| 120 name, | |
| 121 rfcomm_channel, | |
| 122 success_callback, | |
| 123 error_callback, | |
| 124 new_connection_callback)); | |
| 125 } | |
| 126 | |
| 95 void BluetoothSocketWin::Close() { | 127 void BluetoothSocketWin::Close() { |
| 96 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 128 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 97 socket_thread_->task_runner()->PostTask( | 129 socket_thread_->task_runner()->PostTask( |
| 98 FROM_HERE, base::Bind(&BluetoothSocketWin::DoClose, this)); | 130 FROM_HERE, base::Bind(&BluetoothSocketWin::DoClose, this)); |
| 99 } | 131 } |
| 100 | 132 |
| 101 void BluetoothSocketWin::Connect( | 133 void BluetoothSocketWin::Connect( |
| 134 const BluetoothServiceRecord& service_record, | |
| 102 const base::Closure& success_callback, | 135 const base::Closure& success_callback, |
| 103 const ErrorCompletionCallback& error_callback) { | 136 const ErrorCompletionCallback& error_callback) { |
| 104 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 137 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 138 | |
| 139 const BluetoothServiceRecordWin* service_record_win = | |
| 140 static_cast<const BluetoothServiceRecordWin*>(&service_record); | |
| 141 device_address_ = service_record_win->address(); | |
| 142 if (service_record.SupportsRfcomm()) { | |
| 143 supports_rfcomm_ = true; | |
| 144 rfcomm_channel_ = service_record_win->rfcomm_channel(); | |
| 145 bth_addr_ = service_record_win->bth_addr(); | |
| 146 } | |
| 147 | |
| 105 socket_thread_->task_runner()->PostTask( | 148 socket_thread_->task_runner()->PostTask( |
| 106 FROM_HERE, | 149 FROM_HERE, |
| 107 base::Bind( | 150 base::Bind( |
| 108 &BluetoothSocketWin::DoConnect, | 151 &BluetoothSocketWin::DoConnect, |
| 109 this, | 152 this, |
| 110 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback), | 153 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback), |
| 111 base::Bind( | 154 base::Bind( |
| 112 &BluetoothSocketWin::PostErrorCompletion, this, error_callback))); | 155 &BluetoothSocketWin::PostErrorCompletion, this, error_callback))); |
| 113 } | 156 } |
| 114 | 157 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 tcp_socket_->Close(); | 210 tcp_socket_->Close(); |
| 168 tcp_socket_.reset(NULL); | 211 tcp_socket_.reset(NULL); |
| 169 } | 212 } |
| 170 | 213 |
| 171 // Note: Closing |tcp_socket_| above released all potential pending | 214 // Note: Closing |tcp_socket_| above released all potential pending |
| 172 // Send/Receive operations, so we can no safely release the state associated | 215 // Send/Receive operations, so we can no safely release the state associated |
| 173 // to those pending operations. | 216 // to those pending operations. |
| 174 read_buffer_ = NULL; | 217 read_buffer_ = NULL; |
| 175 std::queue<linked_ptr<WriteRequest> > empty; | 218 std::queue<linked_ptr<WriteRequest> > empty; |
| 176 write_queue_.swap(empty); | 219 write_queue_.swap(empty); |
| 220 | |
| 221 if (service_reg_data_) { | |
| 222 if (WSASetService(&service_reg_data_->service,RNRSERVICE_DELETE, 0) == | |
| 223 SOCKET_ERROR) { | |
| 224 LOG(WARNING) << "Failed to unregister service."; | |
| 225 } | |
| 226 service_reg_data_.reset(); | |
| 227 } | |
| 177 } | 228 } |
| 178 | 229 |
| 179 void BluetoothSocketWin::DoConnect( | 230 void BluetoothSocketWin::DoConnect( |
| 180 const base::Closure& success_callback, | 231 const base::Closure& success_callback, |
| 181 const ErrorCompletionCallback& error_callback) { | 232 const ErrorCompletionCallback& error_callback) { |
| 182 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | 233 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); |
| 183 base::ThreadRestrictions::AssertIOAllowed(); | 234 base::ThreadRestrictions::AssertIOAllowed(); |
| 184 | 235 |
| 185 if (tcp_socket_) { | 236 if (tcp_socket_) { |
| 186 error_callback.Run(kSocketAlreadyConnected); | 237 error_callback.Run(kSocketAlreadyConnected); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 ui_task_runner_->PostTask(FROM_HERE, | 443 ui_task_runner_->PostTask(FROM_HERE, |
| 393 base::Bind(callback, reason, error_message)); | 444 base::Bind(callback, reason, error_message)); |
| 394 } | 445 } |
| 395 | 446 |
| 396 void BluetoothSocketWin::PostSendCompletion( | 447 void BluetoothSocketWin::PostSendCompletion( |
| 397 const SendCompletionCallback& callback, | 448 const SendCompletionCallback& callback, |
| 398 int bytes_written) { | 449 int bytes_written) { |
| 399 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written)); | 450 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written)); |
| 400 } | 451 } |
| 401 | 452 |
| 453 void BluetoothSocketWin::DoStartService( | |
| 454 const BluetoothUUID& uuid, | |
| 455 const std::string& name, | |
| 456 int rfcomm_channel, | |
| 457 const base::Closure& success_callback, | |
| 458 const ErrorCompletionCallback& error_callback, | |
| 459 const OnNewConnectionCallback& new_connection_callback) { | |
| 460 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 461 DCHECK(!tcp_socket_ && | |
| 462 !service_reg_data_ && | |
| 463 on_new_connection_callback_.is_null()); | |
| 464 | |
| 465 // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the | |
| 466 // valid RFCOMM port numbers of SOCKADDR_BTH. | |
| 467 if (rfcomm_channel < 0 || rfcomm_channel > 30) { | |
| 468 LOG(WARNING) << "Failed to start service: " | |
| 469 << "Invalid RFCCOMM port " << rfcomm_channel | |
| 470 << ", uuid=" << uuid.value(); | |
| 471 PostErrorCompletion(error_callback, kInvalidRfcommPort); | |
| 472 return; | |
| 473 } | |
| 474 | |
| 475 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); | |
| 476 if (socket_fd == INVALID_SOCKET) { | |
| 477 LOG(WARNING) << "Failed to start service: create socket, " | |
| 478 << "winsock err=" << WSAGetLastError(); | |
| 479 PostErrorCompletion(error_callback, kFailedToCreateSocket); | |
| 480 return; | |
| 481 } | |
| 482 | |
| 483 scoped_ptr<net::TCPSocket> scoped_socket( | |
| 484 new net::TCPSocket(NULL, net::NetLog::Source())); | |
| 485 scoped_socket->AdoptBoundSocket(socket_fd); | |
| 486 | |
| 487 SOCKADDR_BTH sa; | |
| 488 struct sockaddr* sock_addr = reinterpret_cast<struct sockaddr*>(&sa); | |
| 489 int sock_addr_len = sizeof(sa); | |
| 490 ZeroMemory(&sa, sock_addr_len); | |
| 491 sa.addressFamily = AF_BTH; | |
| 492 sa.port = rfcomm_channel ? rfcomm_channel : BT_PORT_ANY; | |
| 493 if (bind(socket_fd, sock_addr, sock_addr_len) < 0) { | |
| 494 LOG(WARNING) << "Failed to start service: create socket, " | |
| 495 << "winsock err=" << WSAGetLastError(); | |
| 496 PostErrorCompletion(error_callback, kFailedToBindSocket); | |
| 497 return; | |
| 498 } | |
| 499 | |
| 500 const int kListenBacklog = 5; | |
| 501 if (scoped_socket->Listen(kListenBacklog) < 0) { | |
| 502 LOG(WARNING) << "Failed to start service: Listen" | |
| 503 << "winsock err=" << WSAGetLastError(); | |
| 504 PostErrorCompletion(error_callback, kFailedToListenOnSocket); | |
| 505 return; | |
| 506 } | |
| 507 | |
| 508 scoped_ptr<ServiceRegData> reg_data(new ServiceRegData); | |
| 509 reg_data->name = base::UTF8ToUTF16(name); | |
| 510 | |
| 511 if (getsockname(socket_fd, sock_addr, &sock_addr_len)) { | |
| 512 LOG(WARNING) << "Failed to start service: getsockname, " | |
| 513 << "winsock err=" << WSAGetLastError(); | |
| 514 PostErrorCompletion(error_callback, kFailedToGetSockNameForSocket); | |
| 515 return; | |
| 516 } | |
| 517 reg_data->address = sa; | |
| 518 | |
| 519 reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa); | |
| 520 reg_data->address_info.LocalAddr.lpSockaddr = | |
| 521 reinterpret_cast<struct sockaddr*>(®_data->address); | |
| 522 reg_data->address_info.iSocketType = SOCK_STREAM; | |
| 523 reg_data->address_info.iProtocol = BTHPROTO_RFCOMM; | |
| 524 | |
| 525 base::string16 cannonical_uuid = L"{" + base::ASCIIToUTF16( | |
| 526 uuid.canonical_value()) + L"}"; | |
| 527 if (!SUCCEEDED(CLSIDFromString(cannonical_uuid.c_str(), ®_data->uuid))) { | |
| 528 LOG(WARNING) << "Failed to start service: " | |
| 529 << ", bad uuid=" << cannonical_uuid; | |
| 530 PostErrorCompletion(error_callback, kBadUuid); | |
| 531 return; | |
| 532 } | |
| 533 | |
| 534 reg_data->service.dwSize = sizeof(WSAQUERYSET); | |
| 535 reg_data->service.lpszServiceInstanceName = | |
| 536 const_cast<LPWSTR>(reg_data->name.c_str()); | |
| 537 reg_data->service.lpServiceClassId = ®_data->uuid; | |
| 538 reg_data->service.dwNameSpace = NS_BTH; | |
| 539 reg_data->service.dwNumberOfCsAddrs = 1; | |
| 540 reg_data->service.lpcsaBuffer = ®_data->address_info; | |
| 541 | |
| 542 if (WSASetService(®_data->service, | |
| 543 RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) { | |
| 544 LOG(WARNING) << "Failed to register profile: WSASetService" | |
| 545 << "winsock err=" << WSAGetLastError(); | |
| 546 PostErrorCompletion(error_callback, kWsaSetServiceError); | |
| 547 return; | |
| 548 } | |
| 549 | |
| 550 tcp_socket_ = scoped_socket.Pass(); | |
| 551 service_reg_data_ = reg_data.Pass(); | |
| 552 on_new_connection_callback_ = new_connection_callback; | |
| 553 DoAccept(); | |
| 554 | |
| 555 PostSuccess(success_callback); | |
| 556 } | |
| 557 | |
| 558 void BluetoothSocketWin::DoAccept() { | |
| 559 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 560 int result = tcp_socket_->Accept( | |
| 561 &accept_socket_, | |
| 562 &accept_address_, | |
| 563 base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread, this)); | |
| 564 if (result != net::OK && result != net::ERR_IO_PENDING) | |
| 565 LOG(WARNING) << "Failed to accept, net err=" << result; | |
| 566 } | |
| 567 | |
| 568 void BluetoothSocketWin::OnAcceptOnSocketThread(int accept_result) { | |
| 569 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 570 if (accept_result != net::OK) { | |
| 571 LOG(WARNING) << "OnAccept error, net err=" << accept_result; | |
| 572 return; | |
| 573 } | |
| 574 | |
| 575 ui_task_runner_->PostTask( | |
| 576 FROM_HERE, | |
| 577 base::Bind(&BluetoothSocketWin::OnAcceptOnUI, | |
| 578 this, | |
| 579 base::Passed(&accept_socket_), | |
| 580 accept_address_)); | |
| 581 DoAccept(); | |
| 582 } | |
| 583 | |
| 584 void BluetoothSocketWin::OnAcceptOnUI( | |
| 585 scoped_ptr<net::TCPSocket> accept_socket, | |
| 586 const net::IPEndPoint& peer_address) { | |
| 587 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
| 588 | |
| 589 scoped_refptr<BluetoothSocketWin> peer = CreateBluetoothSocket( | |
| 590 ui_task_runner_, | |
| 591 socket_thread_, | |
| 592 net_log_, | |
| 593 source_); | |
| 594 peer->tcp_socket_ = accept_socket.Pass(); | |
| 595 | |
| 596 on_new_connection_callback_.Run(peer, peer_address); | |
| 597 } | |
| 598 | |
| 402 } // namespace device | 599 } // namespace device |
| OLD | NEW |