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/objc/IOBluetoothDevice.h> |
8 #import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h> | 8 #import <IOBluetooth/objc/IOBluetoothRFCOMMChannel.h> |
9 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h> | 9 #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h> |
10 | 10 |
11 #include <limits> | 11 #include <limits> |
| 12 #include <sstream> |
12 #include <string> | 13 #include <string> |
13 | 14 |
14 #include "base/basictypes.h" | 15 #include "base/basictypes.h" |
| 16 #include "base/callback_helpers.h" |
15 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
16 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
17 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
| 20 #include "base/threading/thread_restrictions.h" |
18 #include "device/bluetooth/bluetooth_service_record.h" | 21 #include "device/bluetooth/bluetooth_service_record.h" |
19 #include "device/bluetooth/bluetooth_service_record_mac.h" | 22 #include "device/bluetooth/bluetooth_service_record_mac.h" |
20 #include "net/base/io_buffer.h" | 23 #include "net/base/io_buffer.h" |
21 | 24 |
22 // Replicate specific 10.7 SDK declarations for building with prior SDKs. | 25 // Replicate specific 10.7 SDK declarations for building with prior SDKs. |
23 #if !defined(MAC_OS_X_VERSION_10_7) || \ | 26 #if !defined(MAC_OS_X_VERSION_10_7) || \ |
24 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 | 27 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
25 | 28 |
26 @interface IOBluetoothDevice (LionSDKDeclarations) | 29 @interface IOBluetoothDevice (LionSDKDeclarations) |
27 - (NSString*)addressString; | 30 - (NSString*)addressString; |
(...skipping 13 matching lines...) Expand all Loading... |
41 | 44 |
42 @implementation BluetoothRFCOMMChannelDelegate | 45 @implementation BluetoothRFCOMMChannelDelegate |
43 | 46 |
44 - (id)initWithSocket:(device::BluetoothSocketMac*)socket { | 47 - (id)initWithSocket:(device::BluetoothSocketMac*)socket { |
45 if ((self = [super init])) | 48 if ((self = [super init])) |
46 socket_ = socket; | 49 socket_ = socket; |
47 | 50 |
48 return self; | 51 return self; |
49 } | 52 } |
50 | 53 |
| 54 - (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 55 status:(IOReturn)error { |
| 56 socket_->OnChannelOpened(rfcommChannel, error); |
| 57 } |
| 58 |
| 59 - (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel |
| 60 refcon:(void*)refcon |
| 61 status:(IOReturn)error { |
| 62 socket_->OnChannelWriteComplete(rfcommChannel, refcon, error); |
| 63 } |
| 64 |
51 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel | 65 - (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel |
52 data:(void*)dataPointer | 66 data:(void*)dataPointer |
53 length:(size_t)dataLength { | 67 length:(size_t)dataLength { |
54 socket_->OnDataReceived(rfcommChannel, dataPointer, dataLength); | 68 socket_->OnChannelDataReceived(rfcommChannel, dataPointer, dataLength); |
| 69 } |
| 70 |
| 71 - (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel { |
| 72 socket_->OnChannelClosed(rfcommChannel); |
55 } | 73 } |
56 | 74 |
57 @end | 75 @end |
58 | 76 |
| 77 namespace { |
| 78 |
| 79 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocol is not supported"; |
| 80 const char kSocketConnecting[] = "The socket is currently connecting"; |
| 81 const char kSocketAlreadyConnected[] = "The socket is already connected"; |
| 82 const char kSocketNotConnected[] = "The socket is not connected"; |
| 83 const char kReceivePending[] = "A Receive operation is pending"; |
| 84 |
| 85 template <class T> |
| 86 void empty_queue(std::queue<T>& queue) { |
| 87 std::queue<T> empty; |
| 88 std::swap(queue, empty); |
| 89 } |
| 90 |
| 91 } // namespace |
| 92 |
59 namespace device { | 93 namespace device { |
60 | 94 |
61 BluetoothSocketMac::BluetoothSocketMac(IOBluetoothRFCOMMChannel* rfcomm_channel) | 95 BluetoothSocketMac::SendRequest::SendRequest() |
62 : rfcomm_channel_(rfcomm_channel), | 96 : status(kIOReturnSuccess), active_async_writes(0), error_signaled(false) {} |
63 delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]) { | 97 |
| 98 BluetoothSocketMac::SendRequest::~SendRequest() {} |
| 99 |
| 100 BluetoothSocketMac::ReceiveCallbacks::ReceiveCallbacks() {} |
| 101 |
| 102 BluetoothSocketMac::ReceiveCallbacks::~ReceiveCallbacks() {} |
| 103 |
| 104 BluetoothSocketMac::ConnectCallbacks::ConnectCallbacks() {} |
| 105 |
| 106 BluetoothSocketMac::ConnectCallbacks::~ConnectCallbacks() {} |
| 107 |
| 108 // static |
| 109 scoped_refptr<BluetoothSocketMac> BluetoothSocketMac::CreateBluetoothSocket( |
| 110 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, |
| 111 IOBluetoothSDPServiceRecord* record) { |
| 112 return new BluetoothSocketMac(ui_task_runner, record); |
| 113 } |
| 114 |
| 115 BluetoothSocketMac::BluetoothSocketMac( |
| 116 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, |
| 117 IOBluetoothSDPServiceRecord* record) |
| 118 : ui_task_runner_(ui_task_runner), |
| 119 record_(record), |
| 120 delegate_([[BluetoothRFCOMMChannelDelegate alloc] initWithSocket:this]), |
| 121 rfcomm_channel_(nil) { |
| 122 DCHECK(thread_checker_.CalledOnValidThread()); |
| 123 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 124 [record_ retain]; |
| 125 } |
| 126 |
| 127 BluetoothSocketMac::~BluetoothSocketMac() { |
| 128 DCHECK(thread_checker_.CalledOnValidThread()); |
| 129 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 130 ReleaseChannel(); |
| 131 [delegate_ release]; |
| 132 [record_ release]; |
| 133 } |
| 134 |
| 135 void BluetoothSocketMac::ReleaseChannel() { |
| 136 DCHECK(thread_checker_.CalledOnValidThread()); |
| 137 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 138 if (rfcomm_channel_ != nil) { |
| 139 [rfcomm_channel_ setDelegate:nil]; |
| 140 [rfcomm_channel_ closeChannel]; |
| 141 [rfcomm_channel_ release]; |
| 142 rfcomm_channel_ = nil; |
| 143 } |
| 144 |
| 145 // Closing the channel above prevents the callback delegate from being called |
| 146 // so it is now safe to release all callback state. |
| 147 connect_callbacks_.reset(NULL); |
| 148 receive_callbacks_.reset(NULL); |
| 149 empty_queue(receive_queue_); |
| 150 empty_queue(send_queue_); |
| 151 } |
| 152 |
| 153 void BluetoothSocketMac::Connect( |
| 154 const base::Closure& success_callback, |
| 155 const ErrorCompletionCallback& error_callback) { |
| 156 DCHECK(thread_checker_.CalledOnValidThread()); |
| 157 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 158 |
| 159 if (connecting()) { |
| 160 error_callback.Run(kSocketConnecting); |
| 161 return; |
| 162 } |
| 163 |
| 164 if (rfcomm_channel_ != nil) { |
| 165 error_callback.Run(kSocketAlreadyConnected); |
| 166 return; |
| 167 } |
| 168 |
| 169 uint8 rfcomm_channel_id; |
| 170 IOReturn status = [record_ getRFCOMMChannelID:&rfcomm_channel_id]; |
| 171 if (status != kIOReturnSuccess) { |
| 172 // TODO(youngki) add support for L2CAP sockets as well. |
| 173 error_callback.Run(kL2CAPNotSupported); |
| 174 return; |
| 175 } |
| 176 |
| 177 IOBluetoothDevice* device = [record_ device]; |
| 178 IOBluetoothRFCOMMChannel* rfcomm_channel; |
| 179 status = [device openRFCOMMChannelAsync:&rfcomm_channel |
| 180 withChannelID:rfcomm_channel_id |
| 181 delegate:delegate_]; |
| 182 if (status != kIOReturnSuccess) { |
| 183 std::stringstream error; |
| 184 error << std::string("Failed to connect bluetooth socket (") |
| 185 << base::SysNSStringToUTF8([device addressString]) << "): (" << status |
| 186 << std::string(")"); |
| 187 error_callback.Run(error.str()); |
| 188 return; |
| 189 } |
| 190 |
| 191 connect_callbacks_.reset(new ConnectCallbacks()); |
| 192 connect_callbacks_->success_callback = success_callback; |
| 193 connect_callbacks_->error_callback = error_callback; |
| 194 rfcomm_channel_ = rfcomm_channel; |
64 [rfcomm_channel_ setDelegate:delegate_]; | 195 [rfcomm_channel_ setDelegate:delegate_]; |
65 ResetIncomingDataBuffer(); | 196 } |
66 } | 197 |
67 | 198 void BluetoothSocketMac::OnChannelOpened( |
68 BluetoothSocketMac::~BluetoothSocketMac() { | 199 IOBluetoothRFCOMMChannel* rfcomm_channel, |
69 [rfcomm_channel_ setDelegate:nil]; | 200 IOReturn status) { |
70 [rfcomm_channel_ closeChannel]; | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
71 [rfcomm_channel_ release]; | 202 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
72 [delegate_ release]; | 203 DCHECK(rfcomm_channel_ == rfcomm_channel); |
73 } | 204 DCHECK(connecting()); |
74 | 205 |
75 // static | 206 scoped_ptr<ConnectCallbacks> temp = connect_callbacks_.Pass(); |
76 scoped_refptr<BluetoothSocket> BluetoothSocketMac::CreateBluetoothSocket( | 207 if (status != kIOReturnSuccess) { |
77 const BluetoothServiceRecord& service_record) { | 208 ReleaseChannel(); |
78 BluetoothSocketMac* bluetooth_socket = NULL; | 209 std::stringstream error; |
79 if (service_record.SupportsRfcomm()) { | 210 error << "Failed to connect bluetooth socket (" |
80 const BluetoothServiceRecordMac* service_record_mac = | 211 << base::SysNSStringToUTF8([[record_ device] addressString]) << "): (" |
81 static_cast<const BluetoothServiceRecordMac*>(&service_record); | 212 << status << ")"; |
82 IOBluetoothDevice* device = service_record_mac->GetIOBluetoothDevice(); | 213 temp->error_callback.Run(error.str()); |
83 IOBluetoothRFCOMMChannel* rfcomm_channel; | 214 return; |
84 IOReturn status = | 215 } |
85 [device openRFCOMMChannelAsync:&rfcomm_channel | 216 |
86 withChannelID:service_record.rfcomm_channel() | 217 temp->success_callback.Run(); |
87 delegate:nil]; | 218 } |
88 if (status == kIOReturnSuccess) { | 219 |
89 bluetooth_socket = new BluetoothSocketMac(rfcomm_channel); | 220 void BluetoothSocketMac::Close() { |
90 } else { | 221 DCHECK(thread_checker_.CalledOnValidThread()); |
91 LOG(ERROR) << "Failed to connect bluetooth socket (" | 222 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
92 << service_record.address() << "): (" << status << ")"; | 223 |
93 } | 224 ReleaseChannel(); |
94 } | 225 } |
95 // TODO(youngki): add support for L2CAP sockets as well. | |
96 | |
97 return scoped_refptr<BluetoothSocketMac>(bluetooth_socket); | |
98 } | |
99 | |
100 // static | |
101 scoped_refptr<BluetoothSocket> BluetoothSocketMac::CreateBluetoothSocket( | |
102 IOBluetoothSDPServiceRecord* record) { | |
103 BluetoothSocketMac* bluetooth_socket = NULL; | |
104 uint8 rfcomm_channel_id; | |
105 if ([record getRFCOMMChannelID:&rfcomm_channel_id] == kIOReturnSuccess) { | |
106 IOBluetoothDevice* device = [record device]; | |
107 IOBluetoothRFCOMMChannel* rfcomm_channel; | |
108 IOReturn status = | |
109 [device openRFCOMMChannelAsync:&rfcomm_channel | |
110 withChannelID:rfcomm_channel_id | |
111 delegate:nil]; | |
112 if (status == kIOReturnSuccess) { | |
113 bluetooth_socket = new BluetoothSocketMac(rfcomm_channel); | |
114 } else { | |
115 LOG(ERROR) << "Failed to connect bluetooth socket (" | |
116 << base::SysNSStringToUTF8([device addressString]) << "): (" << status | |
117 << ")"; | |
118 } | |
119 } | |
120 | |
121 // TODO(youngki): Add support for L2CAP sockets as well. | |
122 | |
123 return scoped_refptr<BluetoothSocketMac>(bluetooth_socket); | |
124 } | |
125 | |
126 void BluetoothSocketMac::Close() { NOTIMPLEMENTED(); } | |
127 | 226 |
128 void BluetoothSocketMac::Disconnect(const base::Closure& callback) { | 227 void BluetoothSocketMac::Disconnect(const base::Closure& callback) { |
129 NOTIMPLEMENTED(); | 228 DCHECK(thread_checker_.CalledOnValidThread()); |
| 229 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 230 |
| 231 ReleaseChannel(); |
| 232 callback.Run(); |
130 } | 233 } |
131 | 234 |
132 void BluetoothSocketMac::Receive( | 235 void BluetoothSocketMac::Receive( |
133 int count, | 236 int count, |
134 const ReceiveCompletionCallback& success_callback, | 237 const ReceiveCompletionCallback& success_callback, |
135 const ReceiveErrorCompletionCallback& error_callback) { | 238 const ReceiveErrorCompletionCallback& error_callback) { |
136 NOTIMPLEMENTED(); | 239 DCHECK(thread_checker_.CalledOnValidThread()); |
| 240 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 241 |
| 242 if (connecting()) { |
| 243 error_callback.Run(BluetoothSocket::kSystemError, kSocketConnecting); |
| 244 return; |
| 245 } |
| 246 |
| 247 if (rfcomm_channel_ == nil) { |
| 248 error_callback.Run(BluetoothSocket::kDisconnected, kSocketNotConnected); |
| 249 return; |
| 250 } |
| 251 |
| 252 // Only one pending read at a time |
| 253 if (receive_callbacks_) { |
| 254 error_callback.Run(BluetoothSocket::kIOPending, kReceivePending); |
| 255 return; |
| 256 } |
| 257 |
| 258 // If there is at least one packet, consume it and succeed right away. |
| 259 if (!receive_queue_.empty()) { |
| 260 scoped_refptr<net::IOBufferWithSize> buffer = receive_queue_.front(); |
| 261 receive_queue_.pop(); |
| 262 success_callback.Run(buffer->size(), buffer); |
| 263 return; |
| 264 } |
| 265 |
| 266 // Set the receive callback to use when data is received. |
| 267 receive_callbacks_.reset(new ReceiveCallbacks()); |
| 268 receive_callbacks_->success_callback = success_callback; |
| 269 receive_callbacks_->error_callback = error_callback; |
| 270 } |
| 271 |
| 272 void BluetoothSocketMac::OnChannelDataReceived( |
| 273 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 274 void* data, |
| 275 size_t length) { |
| 276 DCHECK(thread_checker_.CalledOnValidThread()); |
| 277 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 278 DCHECK(rfcomm_channel_ == rfcomm_channel); |
| 279 DCHECK(!connecting()); |
| 280 CHECK_LT(length, static_cast<size_t>(std::numeric_limits<int>::max())); |
| 281 |
| 282 int data_size = static_cast<int>(length); |
| 283 scoped_refptr<net::IOBufferWithSize> buffer( |
| 284 new net::IOBufferWithSize(data_size)); |
| 285 memcpy(buffer->data(), data, buffer->size()); |
| 286 |
| 287 // If there is a pending read callback, call it now. |
| 288 if (receive_callbacks_) { |
| 289 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); |
| 290 temp->success_callback.Run(buffer->size(), buffer); |
| 291 return; |
| 292 } |
| 293 |
| 294 // Otherwise, enqueue the buffer for later use |
| 295 receive_queue_.push(buffer); |
137 } | 296 } |
138 | 297 |
139 void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer, | 298 void BluetoothSocketMac::Send(scoped_refptr<net::IOBuffer> buffer, |
140 int buffer_size, | 299 int buffer_size, |
141 const SendCompletionCallback& success_callback, | 300 const SendCompletionCallback& success_callback, |
142 const ErrorCompletionCallback& error_callback) { | 301 const ErrorCompletionCallback& error_callback) { |
143 NOTIMPLEMENTED(); | 302 DCHECK(thread_checker_.CalledOnValidThread()); |
144 } | 303 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
145 | 304 |
146 #if 0 | 305 if (connecting()) { |
147 bool BluetoothSocketMac::Receive(net::GrowableIOBuffer* buffer) { | 306 error_callback.Run(kSocketConnecting); |
148 CHECK(buffer->offset() == 0); | 307 return; |
149 int length = incoming_data_buffer_->offset(); | 308 } |
150 if (length > 0) { | 309 |
151 buffer->SetCapacity(length); | 310 if (rfcomm_channel_ == nil) { |
152 memcpy(buffer->data(), incoming_data_buffer_->StartOfBuffer(), length); | 311 error_callback.Run(kSocketNotConnected); |
153 buffer->set_offset(length); | 312 return; |
154 | 313 } |
155 ResetIncomingDataBuffer(); | 314 |
156 } | 315 // Create and enqueue request in preparation of async writes. |
157 return true; | 316 linked_ptr<SendRequest> request(new SendRequest()); |
158 } | 317 request->buffer_size = buffer_size; |
159 | 318 request->success_callback = success_callback; |
160 bool BluetoothSocketMac::Send(net::DrainableIOBuffer* buffer) { | 319 request->error_callback = error_callback; |
161 int bytes_written = buffer->BytesRemaining(); | 320 send_queue_.push(request); |
162 IOReturn status = [rfcomm_channel_ writeAsync:buffer->data() | 321 |
163 length:bytes_written | 322 // |writeAsync| accepts buffers of max. mtu bytes per call, so we need to emit |
164 refcon:nil]; | 323 // multiple write operations if buffer_size > mtu. |
| 324 BluetoothRFCOMMMTU mtu = [rfcomm_channel_ getMTU]; |
| 325 scoped_refptr<net::DrainableIOBuffer> send_buffer( |
| 326 new net::DrainableIOBuffer(buffer, buffer_size)); |
| 327 while (send_buffer->BytesRemaining() > 0) { |
| 328 int byte_count = send_buffer->BytesRemaining(); |
| 329 if (byte_count > mtu) |
| 330 byte_count = mtu; |
| 331 IOReturn status = [rfcomm_channel_ writeAsync:send_buffer->data() |
| 332 length:byte_count |
| 333 refcon:request.get()]; |
| 334 if (status != kIOReturnSuccess) { |
| 335 std::stringstream error; |
| 336 error << "Failed to connect bluetooth socket (" |
| 337 << base::SysNSStringToUTF8([[record_ device] addressString]) |
| 338 << "): (" << status << ")"; |
| 339 // Remember the first error only |
| 340 if (request->status == kIOReturnSuccess) |
| 341 request->status = status; |
| 342 request->error_signaled = true; |
| 343 request->error_callback.Run(error.str()); |
| 344 // We may have failed to issue any write operation. In that case, there |
| 345 // will be no corresponding completion callback for this particular |
| 346 // request, so we must forget about it now. |
| 347 if (request->active_async_writes == 0) { |
| 348 send_queue_.pop(); |
| 349 } |
| 350 return; |
| 351 } |
| 352 |
| 353 request->active_async_writes++; |
| 354 send_buffer->DidConsume(byte_count); |
| 355 } |
| 356 } |
| 357 |
| 358 void BluetoothSocketMac::OnChannelWriteComplete( |
| 359 IOBluetoothRFCOMMChannel* rfcomm_channel, |
| 360 void* refcon, |
| 361 IOReturn status) { |
| 362 DCHECK(thread_checker_.CalledOnValidThread()); |
| 363 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 364 |
| 365 // Note: We use "CHECK" below to ensure we never run into unforeseen |
| 366 // occurrences of asynchronous callbacks, which could lead to data |
| 367 // corruption. |
| 368 CHECK(rfcomm_channel_ == rfcomm_channel); |
| 369 CHECK(static_cast<SendRequest*>(refcon) == send_queue_.front().get()); |
| 370 |
| 371 // Keep a local linked_ptr to avoid releasing the request too early if we end |
| 372 // up removing it from the queue. |
| 373 linked_ptr<SendRequest> request = send_queue_.front(); |
| 374 |
| 375 // Remember the first error only |
165 if (status != kIOReturnSuccess) { | 376 if (status != kIOReturnSuccess) { |
166 error_message_ = base::StringPrintf( | 377 if (request->status == kIOReturnSuccess) |
167 "Failed to send data. IOReturn code: %u", status); | 378 request->status = status; |
168 return false; | 379 } |
169 } | 380 |
170 | 381 // Figure out if we are done with this async request |
171 buffer->DidConsume(bytes_written); | 382 request->active_async_writes--; |
172 return true; | 383 if (request->active_async_writes > 0) |
173 } | 384 return; |
174 | 385 |
175 std::string BluetoothSocketMac::GetLastErrorMessage() const { | 386 // If this was the last active async write for this request, remove it from |
176 return error_message_; | 387 // the queue and call the appropriate callback associated to the request. |
177 } | 388 send_queue_.pop(); |
178 #endif | 389 if (request->status != kIOReturnSuccess) { |
179 void BluetoothSocketMac::OnDataReceived( | 390 if (!request->error_signaled) { |
180 IOBluetoothRFCOMMChannel* rfcomm_channel, void* data, size_t length) { | 391 std::stringstream error; |
| 392 error << "Failed to connect bluetooth socket (" |
| 393 << base::SysNSStringToUTF8([[record_ device] addressString]) |
| 394 << "): (" << status << ")"; |
| 395 request->error_signaled = true; |
| 396 request->error_callback.Run(error.str()); |
| 397 } |
| 398 } else { |
| 399 request->success_callback.Run(request->buffer_size); |
| 400 } |
| 401 } |
| 402 |
| 403 void BluetoothSocketMac::OnChannelClosed( |
| 404 IOBluetoothRFCOMMChannel* rfcomm_channel) { |
| 405 DCHECK(thread_checker_.CalledOnValidThread()); |
| 406 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
181 DCHECK(rfcomm_channel_ == rfcomm_channel); | 407 DCHECK(rfcomm_channel_ == rfcomm_channel); |
182 CHECK_LT(length, static_cast<size_t>(std::numeric_limits<int>::max())); | 408 |
183 int data_size = static_cast<int>(length); | 409 if (receive_callbacks_) { |
184 if (incoming_data_buffer_->RemainingCapacity() < data_size) { | 410 scoped_ptr<ReceiveCallbacks> temp = receive_callbacks_.Pass(); |
185 int additional_capacity = | 411 temp->error_callback.Run(BluetoothSocket::kDisconnected, |
186 std::max(data_size, incoming_data_buffer_->capacity()); | 412 kSocketNotConnected); |
187 CHECK_LT( | 413 } |
188 additional_capacity, | 414 |
189 std::numeric_limits<int>::max() - incoming_data_buffer_->capacity()); | 415 ReleaseChannel(); |
190 incoming_data_buffer_->SetCapacity( | |
191 incoming_data_buffer_->capacity() + additional_capacity); | |
192 } | |
193 memcpy(incoming_data_buffer_->data(), data, data_size); | |
194 incoming_data_buffer_->set_offset( | |
195 incoming_data_buffer_->offset() + data_size); | |
196 } | |
197 | |
198 void BluetoothSocketMac::ResetIncomingDataBuffer() { | |
199 incoming_data_buffer_ = new net::GrowableIOBuffer(); | |
200 incoming_data_buffer_->SetCapacity(1024); | |
201 } | 416 } |
202 | 417 |
203 } // namespace device | 418 } // namespace device |
OLD | NEW |