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 |