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

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 threading ownership related to ApiResourceManager<BluetoothApiSocket> and BluetoothSocketEventD… Created 6 years, 9 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/strings/sys_string_conversions.h" 11 #include "base/strings/sys_string_conversions.h"
12 #include "base/threading/thread_restrictions.h"
12 #include "device/bluetooth/bluetooth_init_win.h" 13 #include "device/bluetooth/bluetooth_init_win.h"
13 #include "device/bluetooth/bluetooth_service_record_win.h" 14 #include "device/bluetooth/bluetooth_service_record_win.h"
14 #include "net/base/io_buffer.h" 15 #include "net/base/io_buffer.h"
16 #include "net/base/ip_endpoint.h"
17 #include "net/base/net_errors.h"
15 #include "net/base/winsock_init.h" 18 #include "net/base/winsock_init.h"
19 #include "net/socket/tcp_socket_win.h"
16 20
17 namespace { 21 namespace {
18 22
23 const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported";
24 const char kSocketAlreadyConnected[] = "Socket is already connected.";
25 const char kSocketNotConnected[] = "Socket is not connected.";
26
19 std::string FormatErrorMessage(DWORD error_code) { 27 std::string FormatErrorMessage(DWORD error_code) {
20 TCHAR error_msg[1024]; 28 TCHAR error_msg[1024];
21 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 29 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
22 0, 30 0,
23 error_code, 31 error_code,
24 0, 32 0,
25 error_msg, 33 error_msg,
26 1024, 34 1024,
27 NULL); 35 NULL);
28 return base::SysWideToUTF8(error_msg); 36 return base::SysWideToUTF8(error_msg);
29 } 37 }
30 38
31 } // namespace 39 } // namespace
32 40
33 namespace device { 41 namespace device {
34 42
35 BluetoothSocketWin::BluetoothSocketWin(SOCKET fd) : fd_(fd) { 43 BluetoothSocketWin::BluetoothSocketWin(
36 } 44 scoped_refptr<base::SequencedTaskRunner> task_runner,
45 net::NetLog* net_log,
46 const net::NetLog::Source& source)
47 : task_runner_(task_runner),
48 net_log_(net_log),
49 source_(source),
50 supports_rfcomm_(false),
51 rfcomm_channel_(-1),
52 bth_addr_(BTH_ADDR_NULL) {}
37 53
38 BluetoothSocketWin::~BluetoothSocketWin() { 54 BluetoothSocketWin::~BluetoothSocketWin() {
39 closesocket(fd_); 55 DCHECK(thread_checker_.CalledOnValidThread());
40 } 56 }
41 57
42 // static 58 // static
43 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket( 59 scoped_refptr<BluetoothSocket> BluetoothSocketWin::CreateBluetoothSocket(
44 const BluetoothServiceRecord& service_record) { 60 const BluetoothServiceRecord& service_record,
45 BluetoothSocketWin* bluetooth_socket = NULL; 61 scoped_refptr<base::SequencedTaskRunner> task_runner,
62 net::NetLog* net_log,
63 const net::NetLog::Source& source) {
64 const BluetoothServiceRecordWin* service_record_win =
65 static_cast<const BluetoothServiceRecordWin*>(&service_record);
66
67 scoped_refptr<BluetoothSocketWin> result(
68 new BluetoothSocketWin(task_runner, net_log, source));
69 result->device_address_ = service_record_win->address();
46 if (service_record.SupportsRfcomm()) { 70 if (service_record.SupportsRfcomm()) {
47 net::EnsureWinsockInit(); 71 result->supports_rfcomm_ = true;
48 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); 72 result->rfcomm_channel_ = service_record_win->rfcomm_channel();
49 SOCKADDR_BTH sa; 73 result->bth_addr_ = service_record_win->bth_addr();
50 ZeroMemory(&sa, sizeof(sa)); 74 }
51 sa.addressFamily = AF_BTH; 75
52 sa.port = service_record.rfcomm_channel(); 76 // Underlying socket is used on a different thread.
53 const BluetoothServiceRecordWin* service_record_win = 77 result->thread_checker_.DetachFromThread();
54 static_cast<const BluetoothServiceRecordWin*>(&service_record); 78 return result;
55 sa.btAddr = service_record_win->bth_addr(); 79 }
56 80
57 int status = connect(socket_fd, 81 void BluetoothSocketWin::Connect(
58 reinterpret_cast<SOCKADDR *>(&sa), 82 const base::Closure& success_callback,
59 sizeof(sa)); 83 const ErrorCompletionCallback& error_callback) {
60 DWORD error_code = WSAGetLastError(); 84 DCHECK(thread_checker_.CalledOnValidThread());
61 if (status == 0 || error_code == WSAEINPROGRESS) { 85 base::ThreadRestrictions::AssertIOAllowed();
62 bluetooth_socket = 86
63 new BluetoothSocketWin(socket_fd); 87 if (socket_win_) {
64 } else { 88 error_callback.Run(kSocketAlreadyConnected);
65 LOG(ERROR) << "Failed to connect bluetooth socket " 89 return;
66 << "(" << service_record.address() << "): " 90 }
67 << "(" << error_code << ")" << FormatErrorMessage(error_code); 91
68 closesocket(socket_fd); 92 if (!supports_rfcomm_) {
69 } 93 // TODO(youngki) add support for L2CAP sockets as well.
70 } 94 error_callback.Run(kL2CAPNotSupported);
71 // TODO(youngki) add support for L2CAP sockets as well. 95 return;
72 96 }
73 return scoped_refptr<BluetoothSocketWin>(bluetooth_socket); 97
74 } 98 socket_win_.reset(new net::TCPSocketWin(net_log_, source_));
75 99 net::EnsureWinsockInit();
76 bool BluetoothSocketWin::Receive(net::GrowableIOBuffer* buffer) { 100 SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
77 buffer->SetCapacity(1024); 101 SOCKADDR_BTH sa;
78 int bytes_read; 102 ZeroMemory(&sa, sizeof(sa));
79 do { 103 sa.addressFamily = AF_BTH;
80 if (buffer->RemainingCapacity() == 0) 104 sa.port = rfcomm_channel_;
81 buffer->SetCapacity(buffer->capacity() * 2); 105 sa.btAddr = bth_addr_;
82 bytes_read = recv(fd_, buffer->data(), buffer->RemainingCapacity(), 0); 106
83 if (bytes_read > 0) 107 // TODO(rpaquay): Condider making this call non-blocking.
84 buffer->set_offset(buffer->offset() + bytes_read); 108 int status = connect(socket_fd, reinterpret_cast<SOCKADDR*>(&sa), sizeof(sa));
85 } while (bytes_read > 0);
86
87 DWORD error_code = WSAGetLastError(); 109 DWORD error_code = WSAGetLastError();
88 if (bytes_read < 0 && error_code != WSAEWOULDBLOCK) { 110 if (!(status == 0 || error_code == WSAEINPROGRESS)) {
89 error_message_ = FormatErrorMessage(error_code); 111 LOG(ERROR) << "Failed to connect bluetooth socket "
90 return false; 112 << "(" << device_address_ << "): "
91 } 113 << "(" << error_code << ")" << FormatErrorMessage(error_code);
92 return true; 114 error_callback.Run("Error connecting to socket: " +
93 } 115 FormatErrorMessage(error_code));
94 116 closesocket(socket_fd);
95 bool BluetoothSocketWin::Send(net::DrainableIOBuffer* buffer) { 117 return;
96 int bytes_written; 118 }
97 do { 119
98 bytes_written = send(fd_, buffer->data(), buffer->BytesRemaining(), 0); 120 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
99 if (bytes_written > 0) 121 // TCPSocketWin implementation does not actually require one.
100 buffer->DidConsume(bytes_written); 122 int net_result =
101 } while (buffer->BytesRemaining() > 0 && bytes_written > 0); 123 socket_win_->AdoptConnectedSocket(socket_fd, net::IPEndPoint());
102 124 if (net_result != net::OK) {
103 DWORD error_code = WSAGetLastError(); 125 error_callback.Run("Error connecting to socket: " +
104 if (bytes_written < 0 && error_code != WSAEWOULDBLOCK) { 126 std::string(net::ErrorToString(net_result)));
105 error_message_ = FormatErrorMessage(error_code); 127 closesocket(socket_fd);
106 return false; 128 return;
107 } 129 }
108 return true; 130
109 } 131 success_callback.Run();
110 132 }
111 std::string BluetoothSocketWin::GetLastErrorMessage() const { 133
112 return error_message_; 134 void BluetoothSocketWin::Disconnect(const base::Closure& success_callback) {
135 DCHECK(thread_checker_.CalledOnValidThread());
136 base::ThreadRestrictions::AssertIOAllowed();
137
138 if (socket_win_) {
139 socket_win_->Close();
140 socket_win_.reset(NULL);
141 }
142
143 // Note: Closing |socket_win_| above released all potential pending
144 // Send/Receive operations, so we can no safely release the state associated
145 // to those pending operations.
146 read_buffer_ = NULL;
147 std::queue<linked_ptr<WriteRequest> > empty;
148 write_queue_.swap(empty);
149
150 success_callback.Run();
151 }
152
153 void BluetoothSocketWin::Receive(
154 int count,
155 const ReceiveCompletionCallback& success_callback,
156 const ReceiveErrorCompletionCallback& error_callback) {
157 DCHECK(thread_checker_.CalledOnValidThread());
158 base::ThreadRestrictions::AssertIOAllowed();
159
160 if (!socket_win_) {
161 error_callback.Run(BluetoothSocketWin::kDisconnected, kSocketNotConnected);
162 return;
163 }
164
165 // Only one pending read at a time
166 if (read_buffer_.get()) {
167 error_callback.Run(BluetoothSocketWin::kIOPending,
168 net::ErrorToString(net::ERR_IO_PENDING));
169 return;
170 }
171
172 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(count));
173 int read_result =
174 socket_win_->Read(buffer.get(),
175 buffer->size(),
176 base::Bind(&BluetoothSocketWin::OnSocketReadComplete,
177 this,
178 success_callback,
179 error_callback));
180
181 if (read_result > 0) {
182 success_callback.Run(read_result, buffer);
183 } else if (read_result == net::OK ||
184 read_result == net::ERR_CONNECTION_CLOSED) {
185 error_callback.Run(BluetoothSocketWin::kDisconnected,
186 net::ErrorToString(net::ERR_CONNECTION_CLOSED));
187 } else if (read_result == net::ERR_IO_PENDING) {
188 read_buffer_ = buffer;
189 } else {
190 error_callback.Run(BluetoothSocketWin::kSystemError,
191 net::ErrorToString(read_result));
192 }
193 }
194
195 void BluetoothSocketWin::OnSocketReadComplete(
196 const ReceiveCompletionCallback& success_callback,
197 const ReceiveErrorCompletionCallback& error_callback,
198 int read_result) {
199 DCHECK(thread_checker_.CalledOnValidThread());
200 base::ThreadRestrictions::AssertIOAllowed();
201
202 scoped_refptr<net::IOBufferWithSize> buffer;
203 buffer.swap(read_buffer_);
204 if (read_result > 0) {
205 success_callback.Run(read_result, buffer);
206 } else if (read_result == net::OK ||
207 read_result == net::ERR_CONNECTION_CLOSED) {
208 error_callback.Run(BluetoothSocketWin::kDisconnected,
209 net::ErrorToString(net::ERR_CONNECTION_CLOSED));
210 } else {
211 error_callback.Run(BluetoothSocketWin::kSystemError,
212 net::ErrorToString(read_result));
213 }
214 }
215
216 void BluetoothSocketWin::Send(scoped_refptr<net::DrainableIOBuffer> buffer,
217 const SendCompletionCallback& success_callback,
218 const ErrorCompletionCallback& error_callback) {
219 DCHECK(thread_checker_.CalledOnValidThread());
220 base::ThreadRestrictions::AssertIOAllowed();
221
222 if (!socket_win_) {
223 error_callback.Run(kSocketNotConnected);
224 return;
225 }
226
227 linked_ptr<WriteRequest> request(new WriteRequest());
228 request->buffer = buffer;
229 request->success_callback = success_callback;
230 request->error_callback = error_callback;
231
232 write_queue_.push(request);
233 if (write_queue_.size() == 1) {
234 SendFrontWriteRequest();
235 }
236 }
237
238 void BluetoothSocketWin::SendFrontWriteRequest() {
239 DCHECK(thread_checker_.CalledOnValidThread());
240 base::ThreadRestrictions::AssertIOAllowed();
241
242 if (!socket_win_)
243 return;
244
245 if (write_queue_.size() == 0)
246 return;
247
248 linked_ptr<WriteRequest> request = write_queue_.front();
249 net::CompletionCallback callback =
250 base::Bind(&BluetoothSocketWin::OnSocketWriteComplete,
251 this,
252 request->success_callback,
253 request->error_callback);
254 int send_result =
255 socket_win_->Write(request->buffer, request->buffer->size(), callback);
256 if (send_result != net::ERR_IO_PENDING) {
257 callback.Run(send_result);
258 }
259 }
260
261 void BluetoothSocketWin::OnSocketWriteComplete(
262 const SendCompletionCallback& success_callback,
263 const ErrorCompletionCallback& error_callback,
264 int send_result) {
265 DCHECK(thread_checker_.CalledOnValidThread());
266 base::ThreadRestrictions::AssertIOAllowed();
267
268 write_queue_.pop();
269
270 if (send_result >= net::OK) {
271 success_callback.Run(send_result);
272 } else {
273 error_callback.Run(net::ErrorToString(send_result));
274 }
275
276 // Don't call directly to avoid potentail large recursion.
277 task_runner_->PostNonNestableTask(
278 FROM_HERE, base::Bind(&BluetoothSocketWin::SendFrontWriteRequest, this));
113 } 279 }
114 280
115 } // namespace device 281 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698