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

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

Powered by Google App Engine
This is Rietveld 408576698