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

Side by Side Diff: device/bluetooth/bluetooth_socket_win.cc

Issue 180163009: chrome.bluetooth API improvements. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing + Fix merge conflicts. Created 6 years, 8 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
OLDNEW
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 <string> 7 #include <string>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h" 10 #include "base/memory/ref_counted.h"
11 #include "base/sequenced_task_runner.h"
11 #include "base/strings/sys_string_conversions.h" 12 #include "base/strings/sys_string_conversions.h"
13 #include "base/threading/thread_restrictions.h"
12 #include "device/bluetooth/bluetooth_init_win.h" 14 #include "device/bluetooth/bluetooth_init_win.h"
13 #include "device/bluetooth/bluetooth_service_record_win.h" 15 #include "device/bluetooth/bluetooth_service_record_win.h"
16 #include "device/bluetooth/bluetooth_socket_thread_win.h"
14 #include "net/base/io_buffer.h" 17 #include "net/base/io_buffer.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/base/net_errors.h"
15 #include "net/base/winsock_init.h" 20 #include "net/base/winsock_init.h"
21 #include "net/socket/tcp_socket_win.h"
jar (doing other things) 2014/04/04 21:35:49 nit: better might be to include net/socket/tcp_soc
rpaquay 2014/04/04 22:27:58 Done.
16 22
17 namespace { 23 namespace {
18 24
25 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported";
26 const char kSocketAlreadyConnected[] = "Socket is already connected.";
27 const char kSocketNotConnected[] = "Socket is not connected.";
28
29 using device::BluetoothSocketWin;
30
19 std::string FormatErrorMessage(DWORD error_code) { 31 std::string FormatErrorMessage(DWORD error_code) {
20 TCHAR error_msg[1024]; 32 TCHAR error_msg[1024];
21 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 33 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
22 0, 34 0,
23 error_code, 35 error_code,
24 0, 36 0,
25 error_msg, 37 error_msg,
26 1024, 38 1024,
27 NULL); 39 NULL);
28 return base::SysWideToUTF8(error_msg); 40 return base::SysWideToUTF8(error_msg);
29 } 41 }
30 42
43 static void DeactivateSocket(
44 const scoped_refptr<device::BluetoothSocketThreadWin>& socket_thread) {
45 socket_thread->OnSocketDeactivate();
46 }
47
31 } // namespace 48 } // namespace
32 49
33 namespace device { 50 namespace device {
34 51
35 BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) { 52 // static
53 scoped_refptr<BluetoothSocketWin> BluetoothSocketWin::CreateBluetoothSocket(
54 const BluetoothServiceRecord& service_record,
55 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
56 scoped_refptr<BluetoothSocketThreadWin> socket_thread,
57 net::NetLog* net_log,
58 const net::NetLog::Source& source) {
59 DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
60 const BluetoothServiceRecordWin* service_record_win =
61 static_cast<const BluetoothServiceRecordWin*>(&service_record);
62
63 scoped_refptr<BluetoothSocketWin> result(
64 new BluetoothSocketWin(ui_task_runner, socket_thread, net_log, source));
65 result->device_address_ = service_record_win->address();
66 if (service_record.SupportsRfcomm()) {
67 result->supports_rfcomm_ = true;
68 result->rfcomm_channel_ = service_record_win->rfcomm_channel();
69 result->bth_addr_ = service_record_win->bth_addr();
70 }
71
72 return result;
73 }
74
75 BluetoothSocketWin::BluetoothSocketWin(
76 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
77 scoped_refptr<BluetoothSocketThreadWin> socket_thread,
78 net::NetLog* net_log,
79 const net::NetLog::Source& source)
80 : ui_task_runner_(ui_task_runner),
81 socket_thread_(socket_thread),
82 net_log_(net_log),
83 source_(source),
84 supports_rfcomm_(false),
85 rfcomm_channel_(-1),
86 bth_addr_(BTH_ADDR_NULL) {
87 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
88 socket_thread->OnSocketActivate();
36 } 89 }
37 90
38 BluetoothSocketWin::~BluetoothSocketWin() { 91 BluetoothSocketWin::~BluetoothSocketWin() {
39 closesocket(fd_); 92 ui_task_runner_->PostTask(FROM_HERE,
40 } 93 base::Bind(&DeactivateSocket, socket_thread_));
41 94 }
42 // static 95
43 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket( 96 void BluetoothSocketWin::Release() {
44 const BluetoothServiceRecord& service_record) { 97 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
45 BluetoothSocketWin* bluetooth_socket = NULL; 98 socket_thread_->task_runner()->PostTask(
46 if (service_record.SupportsRfcomm()) { 99 FROM_HERE, base::Bind(&BluetoothSocketWin::DoRelease, this));
47 net::EnsureWinsockInit(); 100 }
48 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); 101
49 SOCKADDR_BTH sa; 102 void BluetoothSocketWin::Connect(
50 ZeroMemory(&sa, sizeof(sa)); 103 const base::Closure& success_callback,
51 sa.addressFamily = AF_BTH; 104 const ErrorCompletionCallback& error_callback) {
52 sa.port = service_record.rfcomm_channel(); 105 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
53 const BluetoothServiceRecordWin* service_record_win = 106 socket_thread_->task_runner()->PostTask(
54 static_cast<const BluetoothServiceRecordWin*>(&service_record); 107 FROM_HERE,
55 sa.btAddr = service_record_win->bth_addr(); 108 base::Bind(
56 109 &BluetoothSocketWin::DoConnect,
57 int status = connect(socket_fd, 110 this,
58 reinterpret_cast<SOCKADDR *>(&sa), 111 base::Bind(&BluetoothSocketWin::PostSuccess, this, success_callback),
59 sizeof(sa)); 112 base::Bind(
60 DWORD error_code = WSAGetLastError(); 113 &BluetoothSocketWin::PostErrorCompletion, this, error_callback)));
61 if (status == 0 || error_code == WSAEINPROGRESS) { 114 }
62 bluetooth_socket = 115
63 new BluetoothSocketWin(socket_fd); 116 void BluetoothSocketWin::Disconnect(const base::Closure& success_callback) {
64 } else { 117 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
65 LOG(ERROR) << "Failed to connect bluetooth socket " 118 socket_thread_->task_runner()->PostTask(
66 << "(" << service_record.address() << "): " 119 FROM_HERE,
67 << "(" << error_code << ")" << FormatErrorMessage(error_code); 120 base::Bind(
68 closesocket(socket_fd); 121 &BluetoothSocketWin::DoDisconnect,
69 } 122 this,
70 } 123 base::Bind(
71 // TODO(youngki) add support for L2CAP sockets as well. 124 &BluetoothSocketWin::PostSuccess, this, success_callback)));
72 125 }
73 return scoped_refptr<BluetoothSocketWin>(bluetooth_socket); 126
74 } 127 void BluetoothSocketWin::Receive(
75 128 int count,
76 bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) { 129 const ReceiveCompletionCallback& success_callback,
77 buffer->SetCapacity(1024); 130 const ReceiveErrorCompletionCallback& error_callback) {
78 int bytes_read; 131 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
79 do { 132 socket_thread_->task_runner()->PostTask(
80 if (buffer->RemainingCapacity() == 0) 133 FROM_HERE,
81 buffer->SetCapacity(buffer->capacity() * 2); 134 base::Bind(&BluetoothSocketWin::DoReceive,
82 bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0); 135 this,
83 if (bytes_read > 0) 136 count,
84 buffer->set_offset(buffer->offset() + bytes_read); 137 base::Bind(&BluetoothSocketWin::PostReceiveCompletion,
85 } while (bytes_read > 0); 138 this,
86 139 success_callback),
140 base::Bind(&BluetoothSocketWin::PostReceiveErrorCompletion,
141 this,
142 error_callback)));
143 }
144
145 void BluetoothSocketWin::Send(scoped_refptr<net::IOBuffer> buffer,
146 int buffer_size,
147 const SendCompletionCallback& success_callback,
148 const ErrorCompletionCallback& error_callback) {
149 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
150 socket_thread_->task_runner()->PostTask(
151 FROM_HERE,
152 base::Bind(
153 &BluetoothSocketWin::DoSend,
154 this,
155 buffer,
156 buffer_size,
157 base::Bind(
158 &BluetoothSocketWin::PostSendCompletion, this, success_callback),
159 base::Bind(
160 &BluetoothSocketWin::PostErrorCompletion, this, error_callback)));
161 }
162
163 void BluetoothSocketWin::DoRelease() {
164 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
165 base::ThreadRestrictions::AssertIOAllowed();
166
167 if (socket_win_) {
168 socket_win_->Close();
169 socket_win_.reset(NULL);
170 }
171
172 // Note: Closing |socket_win_| above released all potential pending
173 // Send/Receive operations, so we can no safely release the state associated
174 // to those pending operations.
175 read_buffer_ = NULL;
176 std::queue<linked_ptr<WriteRequest> > empty;
177 write_queue_.swap(empty);
178 }
179
180 void BluetoothSocketWin::DoConnect(
181 const base::Closure& success_callback,
182 const ErrorCompletionCallback& error_callback) {
183 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
184 base::ThreadRestrictions::AssertIOAllowed();
185
186 if (socket_win_) {
187 error_callback.Run(kSocketAlreadyConnected);
188 return;
189 }
190
191 if (!supports_rfcomm_) {
192 // TODO(youngki) add support for L2CAP sockets as well.
193 error_callback.Run(kL2CAPNotSupported);
194 return;
195 }
196
197 socket_win_.reset(new net::TCPSocketWin(net_log_, source_));
jar (doing other things) 2014/04/04 21:35:49 nit: Better is probably to use generic name TCPSoc
rpaquay 2014/04/04 22:27:58 Done.
198 net::EnsureWinsockInit();
199 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
200 SOCKADDR_BTH sa;
201 ZeroMemory(&sa, sizeof(sa));
202 sa.addressFamily = AF_BTH;
203 sa.port = rfcomm_channel_;
204 sa.btAddr = bth_addr_;
205
206 // TODO(rpaquay): Condider making this call non-blocking.
207 int status = connect(socket_fd, reinterpret_cast<SOCKADDR*>(&sa), sizeof(sa));
87 DWORD error_code = WSAGetLastError(); 208 DWORD error_code = WSAGetLastError();
88 if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) { 209 if (!(status == 0 || error_code == WSAEINPROGRESS)) {
89 error_message_ = FormatErrorMessage(error_code); 210 LOG(ERROR) << "Failed to connect bluetooth socket "
90 return false; 211 << "(" << device_address_ << "): "
91 } 212 << "(" << error_code << ")" << FormatErrorMessage(error_code);
92 return true; 213 error_callback.Run("Error connecting to socket: " +
93 } 214 FormatErrorMessage(error_code));
94 215 closesocket(socket_fd);
95 bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) { 216 return;
96 int bytes_written; 217 }
97 do { 218
98 bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0); 219 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
99 if (bytes_written > 0) 220 // TCPSocketWin implementation does not actually require one.
100 buffer->DidConsume(bytes_written); 221 int net_result =
101 } while (buffer->BytesRemaining() > 0 && bytes_written > 0); 222 socket_win_->AdoptConnectedSocket(socket_fd, net::IPEndPoint());
102 223 if (net_result != net::OK) {
103 DWORD error_code = WSAGetLastError(); 224 error_callback.Run("Error connecting to socket: " +
104 if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) { 225 std::string(net::ErrorToString(net_result)));
105 error_message_ = FormatErrorMessage(error_code); 226 closesocket(socket_fd);
106 return false; 227 return;
107 } 228 }
108 return true; 229
109 } 230 success_callback.Run();
110 231 }
111 std::string BluetoothSocketWin::GetLastErrorMessage() const { 232
112 return error_message_; 233 void BluetoothSocketWin::DoDisconnect(const base::Closure& success_callback) {
234 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
235 base::ThreadRestrictions::AssertIOAllowed();
236
237 DoRelease();
238 success_callback.Run();
239 }
240
241 void BluetoothSocketWin::DoReceive(
242 int count,
243 const ReceiveCompletionCallback& success_callback,
244 const ReceiveErrorCompletionCallback& error_callback) {
245 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
246 base::ThreadRestrictions::AssertIOAllowed();
247
248 if (!socket_win_) {
249 error_callback.Run(BluetoothSocketWin::kDisconnected, kSocketNotConnected);
250 return;
251 }
252
253 // Only one pending read at a time
254 if (read_buffer_.get()) {
255 error_callback.Run(BluetoothSocketWin::kIOPending,
256 net::ErrorToString(net::ERR_IO_PENDING));
257 return;
258 }
259
260 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(count));
261 int read_result =
262 socket_win_->Read(buffer.get(),
263 buffer->size(),
264 base::Bind(&BluetoothSocketWin::OnSocketReadComplete,
265 this,
266 success_callback,
267 error_callback));
268
269 if (read_result > 0) {
270 success_callback.Run(read_result, buffer);
271 } else if (read_result == net::OK ||
272 read_result == net::ERR_CONNECTION_CLOSED) {
273 error_callback.Run(BluetoothSocketWin::kDisconnected,
274 net::ErrorToString(net::ERR_CONNECTION_CLOSED));
275 } else if (read_result == net::ERR_IO_PENDING) {
276 read_buffer_ = buffer;
277 } else {
278 error_callback.Run(BluetoothSocketWin::kSystemError,
279 net::ErrorToString(read_result));
280 }
281 }
282
283 void BluetoothSocketWin::OnSocketReadComplete(
284 const ReceiveCompletionCallback& success_callback,
285 const ReceiveErrorCompletionCallback& error_callback,
286 int read_result) {
287 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
288 base::ThreadRestrictions::AssertIOAllowed();
289
290 scoped_refptr<net::IOBufferWithSize> buffer;
291 buffer.swap(read_buffer_);
292 if (read_result > 0) {
293 success_callback.Run(read_result, buffer);
294 } else if (read_result == net::OK ||
295 read_result == net::ERR_CONNECTION_CLOSED) {
296 error_callback.Run(BluetoothSocketWin::kDisconnected,
297 net::ErrorToString(net::ERR_CONNECTION_CLOSED));
298 } else {
299 error_callback.Run(BluetoothSocketWin::kSystemError,
300 net::ErrorToString(read_result));
301 }
302 }
303
304 void BluetoothSocketWin::DoSend(scoped_refptr<net::IOBuffer> buffer,
305 int buffer_size,
306 const SendCompletionCallback& success_callback,
307 const ErrorCompletionCallback& error_callback) {
308 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
309 base::ThreadRestrictions::AssertIOAllowed();
310
311 if (!socket_win_) {
312 error_callback.Run(kSocketNotConnected);
313 return;
314 }
315
316 linked_ptr<WriteRequest> request(new WriteRequest());
317 request->buffer = buffer;
318 request->buffer_size = buffer_size;
319 request->success_callback = success_callback;
320 request->error_callback = error_callback;
321
322 write_queue_.push(request);
323 if (write_queue_.size() == 1) {
324 SendFrontWriteRequest();
325 }
326 }
327
328 void BluetoothSocketWin::SendFrontWriteRequest() {
329 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
330 base::ThreadRestrictions::AssertIOAllowed();
331
332 if (!socket_win_)
333 return;
334
335 if (write_queue_.size() == 0)
336 return;
337
338 linked_ptr<WriteRequest> request = write_queue_.front();
339 net::CompletionCallback callback =
340 base::Bind(&BluetoothSocketWin::OnSocketWriteComplete,
341 this,
342 request->success_callback,
343 request->error_callback);
344 int send_result =
345 socket_win_->Write(request->buffer, request->buffer_size, callback);
346 if (send_result != net::ERR_IO_PENDING) {
347 callback.Run(send_result);
348 }
349 }
350
351 void BluetoothSocketWin::OnSocketWriteComplete(
352 const SendCompletionCallback& success_callback,
353 const ErrorCompletionCallback& error_callback,
354 int send_result) {
355 DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
356 base::ThreadRestrictions::AssertIOAllowed();
357
358 write_queue_.pop();
359
360 if (send_result >= net::OK) {
361 success_callback.Run(send_result);
362 } else {
363 error_callback.Run(net::ErrorToString(send_result));
364 }
365
366 // Don't call directly to avoid potentail large recursion.
367 socket_thread_->task_runner()->PostNonNestableTask(
368 FROM_HERE, base::Bind(&BluetoothSocketWin::SendFrontWriteRequest, this));
369 }
370
371 void BluetoothSocketWin::PostSuccess(const base::Closure& callback) {
372 ui_task_runner_->PostTask(FROM_HERE, callback);
373 }
374
375 void BluetoothSocketWin::PostErrorCompletion(
376 const ErrorCompletionCallback& callback,
377 const std::string& error) {
378 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, error));
379 }
380
381 void BluetoothSocketWin::PostReceiveCompletion(
382 const ReceiveCompletionCallback& callback,
383 int io_buffer_size,
384 scoped_refptr<net::IOBuffer> io_buffer) {
385 ui_task_runner_->PostTask(FROM_HERE,
386 base::Bind(callback, io_buffer_size, io_buffer));
387 }
388
389 void BluetoothSocketWin::PostReceiveErrorCompletion(
390 const ReceiveErrorCompletionCallback& callback,
391 ErrorReason reason,
392 const std::string& error_message) {
393 ui_task_runner_->PostTask(FROM_HERE,
394 base::Bind(callback, reason, error_message));
395 }
396
397 void BluetoothSocketWin::PostSendCompletion(
398 const SendCompletionCallback& callback,
399 int bytes_written) {
400 ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written));
113 } 401 }
114 402
115 } // namespace device 403 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698