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(&address, sizeof(address)); |
| 64 ZeroMemory(&address_info, sizeof(address_info)); |
| 65 ZeroMemory(&uuid, sizeof(uuid)); |
| 66 ZeroMemory(&service, sizeof(service)); |
| 67 } |
| 68 |
| 69 SOCKADDR_BTH address; |
| 70 CSADDR_INFO address_info; |
| 71 GUID uuid; |
| 72 base::string16 name; |
| 73 WSAQUERYSET service; |
| 74 }; |
| 75 |
51 // static | 76 // static |
52 scoped_refptr<BluetoothSocketWin> BluetoothSocketWin::CreateBluetoothSocket( | 77 scoped_refptr<BluetoothSocketWin> BluetoothSocketWin::CreateBluetoothSocket( |
53 const BluetoothServiceRecord& service_record, | |
54 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | 78 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
55 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | 79 scoped_refptr<BluetoothSocketThreadWin> socket_thread, |
56 net::NetLog* net_log, | 80 net::NetLog* net_log, |
57 const net::NetLog::Source& source) { | 81 const net::NetLog::Source& source) { |
58 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); | 82 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); |
59 const BluetoothServiceRecordWin* service_record_win = | |
60 static_cast<const BluetoothServiceRecordWin*>(&service_record); | |
61 | 83 |
62 scoped_refptr<BluetoothSocketWin> result( | 84 return make_scoped_refptr( |
63 new BluetoothSocketWin(ui_task_runner, socket_thread, net_log, source)); | 85 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 } | 86 } |
73 | 87 |
74 BluetoothSocketWin::BluetoothSocketWin( | 88 BluetoothSocketWin::BluetoothSocketWin( |
75 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | 89 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
76 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | 90 scoped_refptr<BluetoothSocketThreadWin> socket_thread, |
77 net::NetLog* net_log, | 91 net::NetLog* net_log, |
78 const net::NetLog::Source& source) | 92 const net::NetLog::Source& source) |
79 : ui_task_runner_(ui_task_runner), | 93 : ui_task_runner_(ui_task_runner), |
80 socket_thread_(socket_thread), | 94 socket_thread_(socket_thread), |
81 net_log_(net_log), | 95 net_log_(net_log), |
82 source_(source), | 96 source_(source), |
83 supports_rfcomm_(false), | 97 supports_rfcomm_(false), |
84 rfcomm_channel_(-1), | 98 rfcomm_channel_(-1), |
85 bth_addr_(BTH_ADDR_NULL) { | 99 bth_addr_(BTH_ADDR_NULL) { |
86 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 100 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
87 socket_thread->OnSocketActivate(); | 101 socket_thread->OnSocketActivate(); |
88 } | 102 } |
89 | 103 |
90 BluetoothSocketWin::~BluetoothSocketWin() { | 104 BluetoothSocketWin::~BluetoothSocketWin() { |
91 ui_task_runner_->PostTask(FROM_HERE, | 105 ui_task_runner_->PostTask(FROM_HERE, |
92 base::Bind(&DeactivateSocket, socket_thread_)); | 106 base::Bind(&DeactivateSocket, socket_thread_)); |
93 } | 107 } |
94 | 108 |
| 109 void BluetoothSocketWin::StartService( |
| 110 const BluetoothUUID& uuid, |
| 111 const std::string& name, |
| 112 int rfcomm_channel, |
| 113 const base::Closure& success_callback, |
| 114 const ErrorCompletionCallback& error_callback, |
| 115 const OnNewConnectionCallback& new_connection_callback) { |
| 116 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 117 |
| 118 socket_thread_->task_runner()->PostTask( |
| 119 FROM_HERE, |
| 120 base::Bind(&BluetoothSocketWin::DoStartService, |
| 121 this, |
| 122 uuid, |
| 123 name, |
| 124 rfcomm_channel, |
| 125 success_callback, |
| 126 error_callback, |
| 127 new_connection_callback)); |
| 128 } |
| 129 |
95 void BluetoothSocketWin::Close() { | 130 void BluetoothSocketWin::Close() { |
96 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 131 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
97 socket_thread_->task_runner()->PostTask( | 132 socket_thread_->task_runner()->PostTask( |
98 FROM_HERE, base::Bind(&BluetoothSocketWin::DoClose, this)); | 133 FROM_HERE, base::Bind(&BluetoothSocketWin::DoClose, this)); |
99 } | 134 } |
100 | 135 |
101 void BluetoothSocketWin::Connect( | 136 void BluetoothSocketWin::Connect( |
| 137 const BluetoothServiceRecord& service_record, |
102 const base::Closure& success_callback, | 138 const base::Closure& success_callback, |
103 const ErrorCompletionCallback& error_callback) { | 139 const ErrorCompletionCallback& error_callback) { |
104 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 140 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 141 |
| 142 const BluetoothServiceRecordWin* service_record_win = |
| 143 static_cast<const BluetoothServiceRecordWin*>(&service_record); |
| 144 device_address_ = service_record_win->address(); |
| 145 if (service_record.SupportsRfcomm()) { |
| 146 supports_rfcomm_ = true; |
| 147 rfcomm_channel_ = service_record_win->rfcomm_channel(); |
| 148 bth_addr_ = service_record_win->bth_addr(); |
| 149 } |
| 150 |
105 socket_thread_->task_runner()->PostTask( | 151 socket_thread_->task_runner()->PostTask( |
106 FROM_HERE, | 152 FROM_HERE, |
107 base::Bind( | 153 base::Bind( |
108 &BluetoothSocketWin::DoConnect, | 154 &BluetoothSocketWin::DoConnect, |
109 this, | 155 this, |
110 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback), | 156 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback), |
111 base::Bind( | 157 base::Bind( |
112 &BluetoothSocketWin::PostErrorCompletion, this, error_callback))); | 158 &BluetoothSocketWin::PostErrorCompletion, this, error_callback))); |
113 } | 159 } |
114 | 160 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 tcp_socket_->Close(); | 213 tcp_socket_->Close(); |
168 tcp_socket_.reset(NULL); | 214 tcp_socket_.reset(NULL); |
169 } | 215 } |
170 | 216 |
171 // Note: Closing |tcp_socket_| above released all potential pending | 217 // Note: Closing |tcp_socket_| above released all potential pending |
172 // Send/Receive operations, so we can no safely release the state associated | 218 // Send/Receive operations, so we can no safely release the state associated |
173 // to those pending operations. | 219 // to those pending operations. |
174 read_buffer_ = NULL; | 220 read_buffer_ = NULL; |
175 std::queue<linked_ptr<WriteRequest> > empty; | 221 std::queue<linked_ptr<WriteRequest> > empty; |
176 write_queue_.swap(empty); | 222 write_queue_.swap(empty); |
| 223 |
| 224 if (service_reg_data_) { |
| 225 if (WSASetService(&service_reg_data_->service,RNRSERVICE_DELETE, 0) == |
| 226 SOCKET_ERROR) { |
| 227 LOG(WARNING) << "Failed to unregister service."; |
| 228 } |
| 229 service_reg_data_.reset(); |
| 230 } |
177 } | 231 } |
178 | 232 |
179 void BluetoothSocketWin::DoConnect( | 233 void BluetoothSocketWin::DoConnect( |
180 const base::Closure& success_callback, | 234 const base::Closure& success_callback, |
181 const ErrorCompletionCallback& error_callback) { | 235 const ErrorCompletionCallback& error_callback) { |
182 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); | 236 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); |
183 base::ThreadRestrictions::AssertIOAllowed(); | 237 base::ThreadRestrictions::AssertIOAllowed(); |
184 | 238 |
185 if (tcp_socket_) { | 239 if (tcp_socket_) { |
186 error_callback.Run(kSocketAlreadyConnected); | 240 error_callback.Run(kSocketAlreadyConnected); |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 ui_task_runner_->PostTask(FROM_HERE, | 446 ui_task_runner_->PostTask(FROM_HERE, |
393 base::Bind(callback, reason, error_message)); | 447 base::Bind(callback, reason, error_message)); |
394 } | 448 } |
395 | 449 |
396 void BluetoothSocketWin::PostSendCompletion( | 450 void BluetoothSocketWin::PostSendCompletion( |
397 const SendCompletionCallback& callback, | 451 const SendCompletionCallback& callback, |
398 int bytes_written) { | 452 int bytes_written) { |
399 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written)); | 453 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written)); |
400 } | 454 } |
401 | 455 |
| 456 void BluetoothSocketWin::DoStartService( |
| 457 const BluetoothUUID& uuid, |
| 458 const std::string& name, |
| 459 int rfcomm_channel, |
| 460 const base::Closure& success_callback, |
| 461 const ErrorCompletionCallback& error_callback, |
| 462 const OnNewConnectionCallback& new_connection_callback) { |
| 463 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); |
| 464 DCHECK(!tcp_socket_ && |
| 465 !service_reg_data_ && |
| 466 on_new_connection_callback_.is_null()); |
| 467 |
| 468 // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the |
| 469 // valid RFCOMM port numbers of SOCKADDR_BTH. |
| 470 if (rfcomm_channel < 0 || rfcomm_channel > 30) { |
| 471 LOG(WARNING) << "Failed to start service: " |
| 472 << "Invalid RFCCOMM port " << rfcomm_channel |
| 473 << ", uuid=" << uuid.value(); |
| 474 PostErrorCompletion(error_callback, kInvalidRfcommPort); |
| 475 return; |
| 476 } |
| 477 |
| 478 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); |
| 479 if (socket_fd == INVALID_SOCKET) { |
| 480 LOG(WARNING) << "Failed to start service: create socket, " |
| 481 << "winsock err=" << WSAGetLastError(); |
| 482 PostErrorCompletion(error_callback, kFailedToCreateSocket); |
| 483 return; |
| 484 } |
| 485 |
| 486 scoped_ptr<net::TCPSocket> scoped_socket( |
| 487 new net::TCPSocket(NULL, net::NetLog::Source())); |
| 488 scoped_socket->AdoptBoundSocket(socket_fd); |
| 489 |
| 490 SOCKADDR_BTH sa; |
| 491 struct sockaddr* sock_addr = reinterpret_cast<struct sockaddr*>(&sa); |
| 492 int sock_addr_len = sizeof(sa); |
| 493 ZeroMemory(&sa, sock_addr_len); |
| 494 sa.addressFamily = AF_BTH; |
| 495 sa.port = rfcomm_channel ? rfcomm_channel : BT_PORT_ANY; |
| 496 if (bind(socket_fd, sock_addr, sock_addr_len) < 0) { |
| 497 LOG(WARNING) << "Failed to start service: create socket, " |
| 498 << "winsock err=" << WSAGetLastError(); |
| 499 PostErrorCompletion(error_callback, kFailedToBindSocket); |
| 500 return; |
| 501 } |
| 502 |
| 503 const int kListenBacklog = 5; |
| 504 if (scoped_socket->Listen(kListenBacklog) < 0) { |
| 505 LOG(WARNING) << "Failed to start service: Listen" |
| 506 << "winsock err=" << WSAGetLastError(); |
| 507 PostErrorCompletion(error_callback, kFailedToListenOnSocket); |
| 508 return; |
| 509 } |
| 510 |
| 511 scoped_ptr<ServiceRegData> reg_data(new ServiceRegData); |
| 512 reg_data->name = base::UTF8ToUTF16(name); |
| 513 |
| 514 if (getsockname(socket_fd, sock_addr, &sock_addr_len)) { |
| 515 LOG(WARNING) << "Failed to start service: getsockname, " |
| 516 << "winsock err=" << WSAGetLastError(); |
| 517 PostErrorCompletion(error_callback, kFailedToGetSockNameForSocket); |
| 518 return; |
| 519 } |
| 520 reg_data->address = sa; |
| 521 |
| 522 reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa); |
| 523 reg_data->address_info.LocalAddr.lpSockaddr = |
| 524 reinterpret_cast<struct sockaddr*>(®_data->address); |
| 525 reg_data->address_info.iSocketType = SOCK_STREAM; |
| 526 reg_data->address_info.iProtocol = BTHPROTO_RFCOMM; |
| 527 |
| 528 base::string16 cannonical_uuid = L"{" + base::ASCIIToUTF16( |
| 529 uuid.canonical_value()) + L"}"; |
| 530 if (!SUCCEEDED(CLSIDFromString(cannonical_uuid.c_str(), ®_data->uuid))) { |
| 531 LOG(WARNING) << "Failed to start service: " |
| 532 << ", bad uuid=" << cannonical_uuid; |
| 533 PostErrorCompletion(error_callback, kBadUuid); |
| 534 return; |
| 535 } |
| 536 |
| 537 reg_data->service.dwSize = sizeof(WSAQUERYSET); |
| 538 reg_data->service.lpszServiceInstanceName = |
| 539 const_cast<LPWSTR>(reg_data->name.c_str()); |
| 540 reg_data->service.lpServiceClassId = ®_data->uuid; |
| 541 reg_data->service.dwNameSpace = NS_BTH; |
| 542 reg_data->service.dwNumberOfCsAddrs = 1; |
| 543 reg_data->service.lpcsaBuffer = ®_data->address_info; |
| 544 |
| 545 if (WSASetService(®_data->service, |
| 546 RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) { |
| 547 LOG(WARNING) << "Failed to register profile: WSASetService" |
| 548 << "winsock err=" << WSAGetLastError(); |
| 549 PostErrorCompletion(error_callback, kWsaSetServiceError); |
| 550 return; |
| 551 } |
| 552 |
| 553 tcp_socket_ = scoped_socket.Pass(); |
| 554 service_reg_data_ = reg_data.Pass(); |
| 555 on_new_connection_callback_ = new_connection_callback; |
| 556 DoAccept(); |
| 557 |
| 558 PostSuccess(success_callback); |
| 559 } |
| 560 |
| 561 void BluetoothSocketWin::DoAccept() { |
| 562 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); |
| 563 int result = tcp_socket_->Accept( |
| 564 &accept_socket_, |
| 565 &accept_address_, |
| 566 base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread, this)); |
| 567 if (result != net::OK && result != net::ERR_IO_PENDING) |
| 568 LOG(WARNING) << "Failed to accept, net err=" << result; |
| 569 } |
| 570 |
| 571 void BluetoothSocketWin::OnAcceptOnSocketThread(int accept_result) { |
| 572 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread()); |
| 573 if (accept_result != net::OK) { |
| 574 LOG(WARNING) << "OnAccept error, net err=" << accept_result; |
| 575 return; |
| 576 } |
| 577 |
| 578 ui_task_runner_->PostTask( |
| 579 FROM_HERE, |
| 580 base::Bind(&BluetoothSocketWin::OnAcceptOnUI, |
| 581 this, |
| 582 base::Passed(&accept_socket_), |
| 583 accept_address_)); |
| 584 DoAccept(); |
| 585 } |
| 586 |
| 587 void BluetoothSocketWin::OnAcceptOnUI( |
| 588 scoped_ptr<net::TCPSocket> accept_socket, |
| 589 const net::IPEndPoint& peer_address) { |
| 590 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 591 |
| 592 scoped_refptr<BluetoothSocketWin> peer = CreateBluetoothSocket( |
| 593 ui_task_runner_, |
| 594 socket_thread_, |
| 595 net_log_, |
| 596 source_); |
| 597 peer->tcp_socket_ = accept_socket.Pass(); |
| 598 |
| 599 on_new_connection_callback_.Run(peer, peer_address); |
| 600 } |
| 601 |
402 } // namespace device | 602 } // namespace device |
OLD | NEW |