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_socket_mac.h" | 5 #include "device/bluetooth/bluetooth_socket_mac.h" |
6 | 6 |
7 #import <IOBluetooth/objc/IOBluetoothDevice.h> | 7 #import <IOBluetooth/IOBluetooth.h> |
8 #import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h> | |
9 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h> | |
10 | 8 |
11 #include <limits> | 9 #include <limits> |
12 #include <sstream> | 10 #include <sstream> |
13 #include <string> | 11 #include <string> |
14 | 12 |
15 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
14 #include "base/bind.h" | |
16 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
17 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
18 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
19 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
20 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
21 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
22 #include "device/bluetooth/bluetooth_service_record.h" | 21 #include "device/bluetooth/bluetooth_service_record.h" |
23 #include "device/bluetooth/bluetooth_service_record_mac.h" | 22 #include "device/bluetooth/bluetooth_service_record_mac.h" |
24 #include "net/base/io_buffer.h" | 23 #include "net/base/io_buffer.h" |
25 | 24 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
100 | 99 |
101 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} | 100 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} |
102 | 101 |
103 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} | 102 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} |
104 | 103 |
105 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} | 104 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} |
106 | 105 |
107 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} | 106 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} |
108 | 107 |
109 // static | 108 // static |
110 scoped_refptr<BluetoothSocketMac> BluetoothSocketMac::CreateBluetoothSocket( | 109 void BluetoothSocketMac::Connect( |
111 IOBluetoothSDPServiceRecord* record) { | 110 IOBluetoothSDPServiceRecord* record, |
112 return new BluetoothSocketMac(record); | 111 const ConnectSuccessCallback& success_callback, |
112 const ErrorCompletionCallback& error_callback) { | |
113 scoped_refptr<BluetoothSocketMac> socket(new BluetoothSocketMac()); | |
114 socket->ConnectImpl(record, success_callback, error_callback); | |
113 } | 115 } |
114 | 116 |
115 BluetoothSocketMac::BluetoothSocketMac( | 117 // static |
116 IOBluetoothSDPServiceRecord* record) | 118 void BluetoothSocketMac::AcceptConnection( |
117 : record_([record retain]), | 119 IOBluetoothRFCOMMChannel* rfcomm_channel, |
118 delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) { | 120 const ConnectSuccessCallback& success_callback, |
119 DCHECK(thread_checker_.CalledOnValidThread()); | 121 const ErrorCompletionCallback& error_callback) { |
122 scoped_refptr<BluetoothSocketMac> socket(new BluetoothSocketMac()); | |
123 socket->AcceptConnectionImpl( | |
124 rfcomm_channel, success_callback, error_callback); | |
125 } | |
rpaquay
2014/04/23 22:15:55
There is little common code between a client and a
Ilya Sherman
2014/04/24 06:50:10
I actually originally planned to create a separate
| |
126 | |
127 BluetoothSocketMac::BluetoothSocketMac() | |
128 : delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) { | |
120 } | 129 } |
121 | 130 |
122 BluetoothSocketMac::~BluetoothSocketMac() { | 131 BluetoothSocketMac::~BluetoothSocketMac() { |
123 DCHECK(thread_checker_.CalledOnValidThread()); | 132 DCHECK(thread_checker_.CalledOnValidThread()); |
124 ReleaseChannel(); | 133 ReleaseChannel(); |
125 } | 134 } |
126 | 135 |
127 void BluetoothSocketMac::ReleaseChannel() { | 136 void BluetoothSocketMac::ReleaseChannel() { |
128 DCHECK(thread_checker_.CalledOnValidThread()); | 137 DCHECK(thread_checker_.CalledOnValidThread()); |
129 if (rfcomm_channel_) { | 138 if (rfcomm_channel_) { |
130 [rfcomm_channel_ setDelegate:nil]; | 139 [rfcomm_channel_ setDelegate:nil]; |
131 [rfcomm_channel_ closeChannel]; | 140 [rfcomm_channel_ closeChannel]; |
132 rfcomm_channel_.reset(); | 141 rfcomm_channel_.reset(); |
133 } | 142 } |
134 | 143 |
135 // Closing the channel above prevents the callback delegate from being called | 144 // Closing the channel above prevents the callback delegate from being called |
136 // so it is now safe to release all callback state. | 145 // so it is now safe to release all callback state. |
137 connect_callbacks_.reset(); | 146 connect_callbacks_.reset(); |
138 receive_callbacks_.reset(); | 147 receive_callbacks_.reset(); |
139 empty_queue(receive_queue_); | 148 empty_queue(receive_queue_); |
140 empty_queue(send_queue_); | 149 empty_queue(send_queue_); |
141 } | 150 } |
142 | 151 |
143 void BluetoothSocketMac::Connect( | 152 void BluetoothSocketMac::ConnectImpl( |
144 const base::Closure& success_callback, | 153 IOBluetoothSDPServiceRecord* record, |
154 const ConnectSuccessCallback& success_callback, | |
145 const ErrorCompletionCallback& error_callback) { | 155 const ErrorCompletionCallback& error_callback) { |
146 DCHECK(thread_checker_.CalledOnValidThread()); | 156 DCHECK(thread_checker_.CalledOnValidThread()); |
147 | 157 |
148 if (connecting()) { | 158 if (connecting()) { |
149 error_callback.Run(kSocketConnecting); | 159 error_callback.Run(kSocketConnecting); |
150 return; | 160 return; |
151 } | 161 } |
152 | 162 |
153 if (rfcomm_channel_) { | 163 if (rfcomm_channel_) { |
154 error_callback.Run(kSocketAlreadyConnected); | 164 error_callback.Run(kSocketAlreadyConnected); |
155 return; | 165 return; |
156 } | 166 } |
157 | 167 |
158 uint8 rfcomm_channel_id; | 168 uint8 rfcomm_channel_id; |
159 IOReturn status = [record_ getRFCOMMChannelID:&rfcomm_channel_id]; | 169 IOReturn status = [record getRFCOMMChannelID:&rfcomm_channel_id]; |
160 if (status != kIOReturnSuccess) { | 170 if (status != kIOReturnSuccess) { |
161 // TODO(youngki) add support for L2CAP sockets as well. | 171 // TODO(youngki) add support for L2CAP sockets as well. |
162 error_callback.Run(kL2CAPNotSupported); | 172 error_callback.Run(kL2CAPNotSupported); |
163 return; | 173 return; |
164 } | 174 } |
165 | 175 |
166 IOBluetoothDevice* device = [record_ device]; | 176 IOBluetoothDevice* device = [record device]; |
167 IOBluetoothRFCOMMChannel* rfcomm_channel; | 177 IOBluetoothRFCOMMChannel* rfcomm_channel; |
168 status = [device openRFCOMMChannelAsync:&rfcomm_channel | 178 status = [device openRFCOMMChannelAsync:&rfcomm_channel |
169 withChannelID:rfcomm_channel_id | 179 withChannelID:rfcomm_channel_id |
170 delegate:delegate_]; | 180 delegate:delegate_]; |
171 if (status != kIOReturnSuccess) { | 181 if (status != kIOReturnSuccess) { |
172 std::stringstream error; | 182 std::stringstream error; |
173 error << "Failed to connect bluetooth socket (" | 183 error << "Failed to connect bluetooth socket (" |
174 << base::SysNSStringToUTF8([device addressString]) << "): (" << status | 184 << base::SysNSStringToUTF8([device addressString]) << "): (" << status |
175 << ")"; | 185 << ")"; |
176 error_callback.Run(error.str()); | 186 error_callback.Run(error.str()); |
177 return; | 187 return; |
178 } | 188 } |
179 | 189 |
190 AcceptConnectionImpl(rfcomm_channel, success_callback, error_callback); | |
191 } | |
192 | |
193 void BluetoothSocketMac::AcceptConnectionImpl( | |
194 IOBluetoothRFCOMMChannel* rfcomm_channel, | |
195 const ConnectSuccessCallback& success_callback, | |
196 const ErrorCompletionCallback& error_callback) { | |
180 connect_callbacks_.reset(new ConnectCallbacks()); | 197 connect_callbacks_.reset(new ConnectCallbacks()); |
181 connect_callbacks_->success_callback = success_callback; | 198 connect_callbacks_->success_callback = |
199 base::Bind(success_callback, scoped_refptr<BluetoothSocketMac>(this)); | |
182 connect_callbacks_->error_callback = error_callback; | 200 connect_callbacks_->error_callback = error_callback; |
183 rfcomm_channel_.reset(rfcomm_channel); | 201 |
202 // Note: It's important to set the connect callbacks *prior* to setting the | |
203 // delegate, as setting the delegate can synchronously call into | |
204 // OnChannelOpened(). | |
205 rfcomm_channel_.reset([rfcomm_channel retain]); | |
184 [rfcomm_channel_ setDelegate:delegate_]; | 206 [rfcomm_channel_ setDelegate:delegate_]; |
185 } | 207 } |
186 | 208 |
187 void BluetoothSocketMac::OnChannelOpened( | 209 void BluetoothSocketMac::OnChannelOpened( |
188 IOBluetoothRFCOMMChannel* rfcomm_channel, | 210 IOBluetoothRFCOMMChannel* rfcomm_channel, |
189 IOReturn status) { | 211 IOReturn status) { |
190 DCHECK(thread_checker_.CalledOnValidThread()); | 212 DCHECK(thread_checker_.CalledOnValidThread()); |
191 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); | 213 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); |
192 DCHECK(connecting()); | 214 DCHECK(connecting()); |
193 | 215 |
194 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); | 216 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); |
195 if (status != kIOReturnSuccess) { | 217 if (status != kIOReturnSuccess) { |
196 ReleaseChannel(); | 218 ReleaseChannel(); |
197 std::stringstream error; | 219 std::stringstream error; |
198 error << "Failed to connect bluetooth socket (" | 220 error << "Failed to connect bluetooth socket (" |
199 << base::SysNSStringToUTF8([[record_ device] addressString]) << "): (" | 221 << base::SysNSStringToUTF8( |
222 [[rfcomm_channel_ getDevice] addressString]) << "): (" | |
200 << status << ")"; | 223 << status << ")"; |
201 temp->error_callback.Run(error.str()); | 224 temp->error_callback.Run(error.str()); |
202 return; | 225 return; |
203 } | 226 } |
204 | 227 |
205 temp->success_callback.Run(); | 228 temp->success_callback.Run(); |
206 } | 229 } |
207 | 230 |
208 void BluetoothSocketMac::Close() { | 231 void BluetoothSocketMac::Close() { |
209 DCHECK(thread_checker_.CalledOnValidThread()); | 232 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
309 while (send_buffer->BytesRemaining() > 0) { | 332 while (send_buffer->BytesRemaining() > 0) { |
310 int byte_count = send_buffer->BytesRemaining(); | 333 int byte_count = send_buffer->BytesRemaining(); |
311 if (byte_count > mtu) | 334 if (byte_count > mtu) |
312 byte_count = mtu; | 335 byte_count = mtu; |
313 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() | 336 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() |
314 length:byte_count | 337 length:byte_count |
315 refcon:request.get()]; | 338 refcon:request.get()]; |
316 if (status != kIOReturnSuccess) { | 339 if (status != kIOReturnSuccess) { |
317 std::stringstream error; | 340 std::stringstream error; |
318 error << "Failed to connect bluetooth socket (" | 341 error << "Failed to connect bluetooth socket (" |
319 << base::SysNSStringToUTF8([[record_ device] addressString]) | 342 << base::SysNSStringToUTF8( |
343 [[rfcomm_channel_ getDevice] addressString]) | |
320 << "): (" << status << ")"; | 344 << "): (" << status << ")"; |
321 // Remember the first error only | 345 // Remember the first error only |
322 if (request->status == kIOReturnSuccess) | 346 if (request->status == kIOReturnSuccess) |
323 request->status = status; | 347 request->status = status; |
324 request->error_signaled = true; | 348 request->error_signaled = true; |
325 request->error_callback.Run(error.str()); | 349 request->error_callback.Run(error.str()); |
326 // We may have failed to issue any write operation. In that case, there | 350 // We may have failed to issue any write operation. In that case, there |
327 // will be no corresponding completion callback for this particular | 351 // will be no corresponding completion callback for this particular |
328 // request, so we must forget about it now. | 352 // request, so we must forget about it now. |
329 if (request->active_async_writes == 0) { | 353 if (request->active_async_writes == 0) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
364 if (request->active_async_writes > 0) | 388 if (request->active_async_writes > 0) |
365 return; | 389 return; |
366 | 390 |
367 // If this was the last active async write for this request, remove it from | 391 // If this was the last active async write for this request, remove it from |
368 // the queue and call the appropriate callback associated to the request. | 392 // the queue and call the appropriate callback associated to the request. |
369 send_queue_.pop(); | 393 send_queue_.pop(); |
370 if (request->status != kIOReturnSuccess) { | 394 if (request->status != kIOReturnSuccess) { |
371 if (!request->error_signaled) { | 395 if (!request->error_signaled) { |
372 std::stringstream error; | 396 std::stringstream error; |
373 error << "Failed to connect bluetooth socket (" | 397 error << "Failed to connect bluetooth socket (" |
374 << base::SysNSStringToUTF8([[record_ device] addressString]) | 398 << base::SysNSStringToUTF8( |
399 [[rfcomm_channel_ getDevice] addressString]) | |
375 << "): (" << status << ")"; | 400 << "): (" << status << ")"; |
376 request->error_signaled = true; | 401 request->error_signaled = true; |
377 request->error_callback.Run(error.str()); | 402 request->error_callback.Run(error.str()); |
378 } | 403 } |
379 } else { | 404 } else { |
380 request->success_callback.Run(request->buffer_size); | 405 request->success_callback.Run(request->buffer_size); |
381 } | 406 } |
382 } | 407 } |
383 | 408 |
384 void BluetoothSocketMac::OnChannelClosed( | 409 void BluetoothSocketMac::OnChannelClosed( |
385 IOBluetoothRFCOMMChannel* rfcomm_channel) { | 410 IOBluetoothRFCOMMChannel* rfcomm_channel) { |
386 DCHECK(thread_checker_.CalledOnValidThread()); | 411 DCHECK(thread_checker_.CalledOnValidThread()); |
387 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); | 412 DCHECK_EQ(rfcomm_channel_, rfcomm_channel); |
388 | 413 |
389 if (receive_callbacks_) { | 414 if (receive_callbacks_) { |
390 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); | 415 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); |
391 temp->error_callback.Run(BluetoothSocket::kDisconnected, | 416 temp->error_callback.Run(BluetoothSocket::kDisconnected, |
392 kSocketNotConnected); | 417 kSocketNotConnected); |
393 } | 418 } |
394 | 419 |
395 ReleaseChannel(); | 420 ReleaseChannel(); |
396 } | 421 } |
397 | 422 |
398 } // namespace device | 423 } // namespace device |
OLD | NEW |