OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_profile_win.h" | 5 #include "device/bluetooth/bluetooth_profile_win.h" |
6 | 6 |
| 7 #include <objbase.h> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" |
8 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
9 #include "base/sequenced_task_runner.h" | 12 #include "base/sequenced_task_runner.h" |
| 13 #include "base/strings/string16.h" |
| 14 #include "base/strings/stringprintf.h" |
| 15 #include "base/strings/utf_string_conversions.h" |
10 #include "device/bluetooth/bluetooth_adapter_factory.h" | 16 #include "device/bluetooth/bluetooth_adapter_factory.h" |
| 17 #include "device/bluetooth/bluetooth_adapter_win.h" |
11 #include "device/bluetooth/bluetooth_device_win.h" | 18 #include "device/bluetooth/bluetooth_device_win.h" |
12 #include "device/bluetooth/bluetooth_service_record.h" | 19 #include "device/bluetooth/bluetooth_service_record.h" |
13 #include "device/bluetooth/bluetooth_socket_thread_win.h" | 20 #include "device/bluetooth/bluetooth_socket_thread_win.h" |
14 #include "device/bluetooth/bluetooth_socket_win.h" | 21 #include "device/bluetooth/bluetooth_socket_win.h" |
| 22 #include "net/base/net_errors.h" |
| 23 #include "net/socket/tcp_socket.h" |
15 | 24 |
16 namespace { | 25 namespace { |
17 | 26 |
18 using device::BluetoothAdapter; | 27 using device::BluetoothAdapter; |
19 using device::BluetoothDevice; | 28 using device::BluetoothDevice; |
20 using device::BluetoothProfileWin; | 29 using device::BluetoothProfileWin; |
21 using device::BluetoothSocket; | 30 using device::BluetoothSocket; |
22 using device::BluetoothSocketWin; | 31 using device::BluetoothSocketWin; |
23 | 32 |
24 const char kNoConnectionCallback[] = "Connection callback not set"; | 33 const char kNoConnectionCallback[] = "Connection callback not set"; |
(...skipping 30 matching lines...) Expand all Loading... |
55 socket)); | 64 socket)); |
56 } | 65 } |
57 | 66 |
58 void OnConnectErrorUI(scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | 67 void OnConnectErrorUI(scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
59 const BluetoothProfileWin::ErrorCallback& error_callback, | 68 const BluetoothProfileWin::ErrorCallback& error_callback, |
60 const std::string& error) { | 69 const std::string& error) { |
61 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); | 70 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); |
62 error_callback.Run(error); | 71 error_callback.Run(error); |
63 } | 72 } |
64 | 73 |
| 74 std::string IPEndPointToBluetoothAddress(const net::IPEndPoint& end_point) { |
| 75 const size_t kBtAddressSize = 6; |
| 76 if (end_point.address().size() != kBtAddressSize) |
| 77 return std::string(); |
| 78 return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", |
| 79 end_point.address()[5], |
| 80 end_point.address()[4], |
| 81 end_point.address()[3], |
| 82 end_point.address()[2], |
| 83 end_point.address()[1], |
| 84 end_point.address()[0]); |
| 85 } |
| 86 |
65 } // namespace | 87 } // namespace |
66 | 88 |
67 namespace device { | 89 namespace device { |
68 | 90 |
69 BluetoothProfileWin::BluetoothProfileWin(const BluetoothUUID& uuid, | 91 struct BluetoothProfileWin::ProfileRegData { |
70 const std::string& name) | 92 ProfileRegData() { |
71 : BluetoothProfile(), uuid_(uuid), name_(name) { | 93 ZeroMemory(this, sizeof(ProfileRegData)); |
| 94 } |
| 95 |
| 96 SOCKADDR_BTH address; |
| 97 CSADDR_INFO address_info; |
| 98 GUID uuid; |
| 99 base::string16 name; |
| 100 WSAQUERYSET service; |
| 101 }; |
| 102 |
| 103 BluetoothProfileWin::BluetoothProfileWin() |
| 104 : BluetoothProfile(), rfcomm_channel_(0), weak_ptr_factory_(this) { |
72 } | 105 } |
73 | 106 |
74 BluetoothProfileWin::~BluetoothProfileWin() { | 107 BluetoothProfileWin::~BluetoothProfileWin() { |
75 } | 108 } |
76 | 109 |
77 void BluetoothProfileWin::Unregister() { | 110 void BluetoothProfileWin::Unregister() { |
| 111 if (adapter_) { |
| 112 if (profile_reg_data_) { |
| 113 adapter()->socket_thread()->task_runner()->PostTask( |
| 114 FROM_HERE, |
| 115 base::Bind(&BluetoothProfileWin::UnregisterProfileOnSocketThread, |
| 116 base::Passed(&profile_reg_data_))); |
| 117 } |
| 118 if (profile_socket_) |
| 119 profile_socket_->Close(); |
| 120 |
| 121 adapter()->socket_thread()->OnSocketDeactivate(); |
| 122 } |
| 123 |
78 delete this; | 124 delete this; |
79 } | 125 } |
80 | 126 |
81 void BluetoothProfileWin::SetConnectionCallback( | 127 void BluetoothProfileWin::SetConnectionCallback( |
82 const ConnectionCallback& callback) { | 128 const ConnectionCallback& callback) { |
83 connection_callback_ = callback; | 129 connection_callback_ = callback; |
84 } | 130 } |
85 | 131 |
| 132 void BluetoothProfileWin::Init(const BluetoothUUID& uuid, |
| 133 const BluetoothProfile::Options& options, |
| 134 const ProfileCallback& callback) { |
| 135 uuid_ = uuid; |
| 136 name_ = options.name; |
| 137 rfcomm_channel_ = options.channel; |
| 138 |
| 139 BluetoothAdapterFactory::GetAdapter( |
| 140 base::Bind(&BluetoothProfileWin::OnGetAdapter, |
| 141 weak_ptr_factory_.GetWeakPtr(), |
| 142 callback)); |
| 143 } |
| 144 |
86 void BluetoothProfileWin::Connect( | 145 void BluetoothProfileWin::Connect( |
87 const BluetoothDeviceWin* device, | 146 const BluetoothDeviceWin* device, |
88 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | 147 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
89 scoped_refptr<BluetoothSocketThreadWin> socket_thread, | 148 scoped_refptr<BluetoothSocketThreadWin> socket_thread, |
90 net::NetLog* net_log, | 149 net::NetLog* net_log, |
91 const net::NetLog::Source& source, | 150 const net::NetLog::Source& source, |
92 const base::Closure& success_callback, | 151 const base::Closure& success_callback, |
93 const ErrorCallback& error_callback) { | 152 const ErrorCallback& error_callback) { |
94 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); | 153 DCHECK(ui_task_runner->RunsTasksOnCurrentThread()); |
95 if (connection_callback_.is_null()) { | 154 if (connection_callback_.is_null()) { |
(...skipping 13 matching lines...) Expand all Loading... |
109 | 168 |
110 socket->Connect(base::Bind(&OnConnectSuccessUI, | 169 socket->Connect(base::Bind(&OnConnectSuccessUI, |
111 ui_task_runner, | 170 ui_task_runner, |
112 success_callback, | 171 success_callback, |
113 connection_callback_, | 172 connection_callback_, |
114 device->GetAddress(), | 173 device->GetAddress(), |
115 socket), | 174 socket), |
116 error_callback); | 175 error_callback); |
117 } | 176 } |
118 | 177 |
| 178 void BluetoothProfileWin::OnGetAdapter( |
| 179 const ProfileCallback& callback, |
| 180 scoped_refptr<BluetoothAdapter> in_adapter) { |
| 181 DCHECK(!adapter_); |
| 182 DCHECK(!profile_socket_); |
| 183 DCHECK(!profile_reg_data_); |
| 184 |
| 185 adapter_ = in_adapter; |
| 186 adapter()->socket_thread()->OnSocketActivate(); |
| 187 |
| 188 // The followings are owned by register profile reply callback. |
| 189 bool* success = new bool(false); |
| 190 scoped_ptr<net::TCPSocket>* socket = new scoped_ptr<net::TCPSocket>; |
| 191 scoped_ptr<ProfileRegData>* reg_data = new scoped_ptr<ProfileRegData>; |
| 192 |
| 193 adapter()->socket_thread()->task_runner() |
| 194 ->PostTaskAndReply( |
| 195 FROM_HERE, |
| 196 base::Bind(&BluetoothProfileWin::RegisterProfileOnSocketThread, |
| 197 uuid_, |
| 198 name_, |
| 199 rfcomm_channel_, |
| 200 success, |
| 201 socket, |
| 202 reg_data), |
| 203 base::Bind(&BluetoothProfileWin::OnRegisterProfileOnUI, |
| 204 weak_ptr_factory_.GetWeakPtr(), |
| 205 base::Owned(success), |
| 206 base::Owned(socket), |
| 207 base::Owned(reg_data), |
| 208 callback)); |
| 209 } |
| 210 |
| 211 // static |
| 212 void BluetoothProfileWin::RegisterProfileOnSocketThread( |
| 213 const device::BluetoothUUID& uuid, |
| 214 const std::string& name, |
| 215 int rfcomm_channel, |
| 216 bool* out_success, |
| 217 scoped_ptr<net::TCPSocket>* out_socket, |
| 218 scoped_ptr<ProfileRegData>* out_reg_data) { |
| 219 *out_success = false; |
| 220 |
| 221 // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the |
| 222 // valid RFCOMM port numbers of SOCKADDR_BTH. |
| 223 if (rfcomm_channel < 0 || rfcomm_channel > 30) { |
| 224 LOG(WARNING) << "Failed to register profile: " |
| 225 << "Invalid RFCCOMM port " << rfcomm_channel |
| 226 << ", uuid=" << uuid.value(); |
| 227 return; |
| 228 } |
| 229 |
| 230 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); |
| 231 if (socket_fd == INVALID_SOCKET) { |
| 232 LOG(WARNING) << "Failed to register profile: create socket, " |
| 233 << "winsock err=" << WSAGetLastError(); |
| 234 return; |
| 235 } |
| 236 |
| 237 scoped_ptr<net::TCPSocket> scoped_socket( |
| 238 new net::TCPSocket(NULL, net::NetLog::Source())); |
| 239 scoped_socket->AdoptBoundSocket(socket_fd); |
| 240 |
| 241 SOCKADDR_BTH sa; |
| 242 struct sockaddr* sock_addr = reinterpret_cast<struct sockaddr*>(&sa); |
| 243 int sock_addr_len = sizeof(sa); |
| 244 ZeroMemory(&sa, sock_addr_len); |
| 245 sa.addressFamily = AF_BTH; |
| 246 sa.port = rfcomm_channel ? rfcomm_channel : BT_PORT_ANY; |
| 247 if (bind(socket_fd, sock_addr, sock_addr_len) < 0) { |
| 248 LOG(WARNING) << "Failed to register profile: create socket, " |
| 249 << "winsock err=" << WSAGetLastError(); |
| 250 return; |
| 251 } |
| 252 |
| 253 const int kListenBacklog = 5; |
| 254 if (scoped_socket->Listen(kListenBacklog) < 0) { |
| 255 LOG(WARNING) << "Failed to register profile: Listen" |
| 256 << "winsock err=" << WSAGetLastError(); |
| 257 return; |
| 258 } |
| 259 |
| 260 scoped_ptr<ProfileRegData> reg_data(new ProfileRegData); |
| 261 reg_data->name = base::UTF8ToUTF16(name); |
| 262 |
| 263 if (getsockname(socket_fd, sock_addr, &sock_addr_len)) { |
| 264 LOG(WARNING) << "Failed to register profile: getsockname, " |
| 265 << "winsock err=" << WSAGetLastError(); |
| 266 return; |
| 267 } |
| 268 reg_data->address = sa; |
| 269 |
| 270 reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa); |
| 271 reg_data->address_info.LocalAddr.lpSockaddr = |
| 272 reinterpret_cast<struct sockaddr*>(®_data->address); |
| 273 reg_data->address_info.iSocketType = SOCK_STREAM; |
| 274 reg_data->address_info.iProtocol = BTHPROTO_RFCOMM; |
| 275 |
| 276 base::string16 cannonical_uuid = L"{" + base::ASCIIToUTF16( |
| 277 uuid.canonical_value()) + L"}"; |
| 278 if (!SUCCEEDED(CLSIDFromString(cannonical_uuid.c_str(), ®_data->uuid))) { |
| 279 LOG(WARNING) << "Failed to register profile: " |
| 280 << ", bad uuid=" << cannonical_uuid; |
| 281 return; |
| 282 } |
| 283 |
| 284 reg_data->service.dwSize = sizeof(WSAQUERYSET); |
| 285 reg_data->service.lpszServiceInstanceName = |
| 286 const_cast<LPWSTR>(reg_data->name.c_str()); |
| 287 reg_data->service.lpServiceClassId = ®_data->uuid; |
| 288 reg_data->service.dwNameSpace = NS_BTH; |
| 289 reg_data->service.dwNumberOfCsAddrs = 1; |
| 290 reg_data->service.lpcsaBuffer = ®_data->address_info; |
| 291 |
| 292 if (WSASetService(®_data->service, |
| 293 RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) { |
| 294 LOG(WARNING) << "Failed to register profile: WSASetService" |
| 295 << "winsock err=" << WSAGetLastError(); |
| 296 return; |
| 297 } |
| 298 |
| 299 *out_socket = scoped_socket.Pass(); |
| 300 *out_reg_data = reg_data.Pass(); |
| 301 *out_success = true; |
| 302 } |
| 303 |
| 304 void BluetoothProfileWin::OnRegisterProfileOnUI( |
| 305 bool* success, |
| 306 scoped_ptr<net::TCPSocket>* socket, |
| 307 scoped_ptr<ProfileRegData>* reg_data, |
| 308 const ProfileCallback& callback) { |
| 309 DCHECK(adapter()->ui_task_runner()->RunsTasksOnCurrentThread()); |
| 310 |
| 311 if (!(*success)) { |
| 312 callback.Run(NULL); |
| 313 delete this; |
| 314 return; |
| 315 } |
| 316 |
| 317 DCHECK(*socket); |
| 318 DCHECK(*reg_data); |
| 319 |
| 320 profile_socket_ = BluetoothSocketWin::CreateBluetoothSocket( |
| 321 socket->Pass(), |
| 322 adapter()->ui_task_runner(), |
| 323 adapter()->socket_thread(), |
| 324 NULL, |
| 325 net::NetLog::Source()); |
| 326 profile_reg_data_ = reg_data->Pass(); |
| 327 |
| 328 profile_socket_->Accept(base::Bind(&BluetoothProfileWin::OnNewConnection, |
| 329 weak_ptr_factory_.GetWeakPtr())); |
| 330 callback.Run(this); |
| 331 } |
| 332 |
| 333 // static |
| 334 void BluetoothProfileWin::UnregisterProfileOnSocketThread( |
| 335 scoped_ptr<BluetoothProfileWin::ProfileRegData> reg_data) { |
| 336 if (WSASetService(®_data->service,RNRSERVICE_DELETE, 0) == SOCKET_ERROR) |
| 337 LOG(WARNING) << "Failed to unregister profile"; |
| 338 } |
| 339 |
| 340 void BluetoothProfileWin::OnNewConnection( |
| 341 scoped_refptr<BluetoothSocketWin> connected, |
| 342 const net::IPEndPoint& peer_address) { |
| 343 DCHECK(adapter()->ui_task_runner()->RunsTasksOnCurrentThread()); |
| 344 if (connection_callback_.is_null()) |
| 345 return; |
| 346 |
| 347 std::string device_address = IPEndPointToBluetoothAddress(peer_address); |
| 348 if (device_address.empty()) { |
| 349 LOG(WARNING) << "Failed to accept connection for profile " |
| 350 << "uuid=" << uuid_.value() |
| 351 << ", unexpected peer device address."; |
| 352 return; |
| 353 } |
| 354 |
| 355 BluetoothDevice* device = adapter_->GetDevice(device_address); |
| 356 if (!device) { |
| 357 LOG(WARNING) << "Failed to accept connection for profile" |
| 358 << ",uuid=" << uuid_.value() |
| 359 << ", unknown device=" << device_address; |
| 360 return; |
| 361 } |
| 362 |
| 363 connection_callback_.Run(device, connected); |
| 364 } |
| 365 |
| 366 BluetoothAdapterWin* BluetoothProfileWin::adapter() const { |
| 367 DCHECK(adapter_); |
| 368 return static_cast<BluetoothAdapterWin*>(adapter_.get()); |
| 369 } |
| 370 |
119 } // namespace device | 371 } // namespace device |
OLD | NEW |