Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: device/bluetooth/bluetooth_socket_mac.mm

Issue 243963002: Implement Bluetooth server socket support for RFCOMM on Mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Short url Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « device/bluetooth/bluetooth_socket_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 }
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
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
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
OLDNEW
« no previous file with comments | « device/bluetooth/bluetooth_socket_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698