Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / services / device / serial / bluetooth_serial_port_impl.cc
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/device/serial/bluetooth_serial_port_impl.h"
6
7 #include <limits.h>
8 #include <algorithm>
9
10 #include "base/callback_helpers.h"
11 #include "base/command_line.h"
12 #include "base/containers/contains.h"
13 #include "net/base/io_buffer.h"
14 #include "services/device/public/cpp/bluetooth/bluetooth_utils.h"
15 #include "services/device/public/cpp/serial/serial_switches.h"
16
17 namespace device {
18
19 // static
20 void BluetoothSerialPortImpl::Open(
21     scoped_refptr<BluetoothAdapter> adapter,
22     const std::string& address,
23     const BluetoothUUID& service_class_id,
24     mojom::SerialConnectionOptionsPtr options,
25     mojo::PendingRemote<mojom::SerialPortClient> client,
26     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
27     OpenCallback callback) {
28   DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
29       switches::kEnableBluetoothSerialPortProfileInSerialApi));
30
31   // This BluetoothSerialPortImpl is owned by its |receiver_| and |watcher_| and
32   // will self-destruct on connection failure.
33   auto* port = new BluetoothSerialPortImpl(
34       std::move(adapter), address, std::move(options), std::move(client),
35       std::move(watcher));
36   port->OpenSocket(service_class_id, std::move(callback));
37 }
38
39 BluetoothSerialPortImpl::BluetoothSerialPortImpl(
40     scoped_refptr<BluetoothAdapter> adapter,
41     const std::string& address,
42     mojom::SerialConnectionOptionsPtr options,
43     mojo::PendingRemote<mojom::SerialPortClient> client,
44     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher)
45     : watcher_(std::move(watcher)),
46       client_(std::move(client)),
47       in_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
48       out_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
49       bluetooth_adapter_(std::move(adapter)),
50       address_(address),
51       options_(std::move(options)) {
52   if (watcher_.is_bound()) {
53     watcher_.set_disconnect_handler(
54         base::BindOnce([](BluetoothSerialPortImpl* self) { delete self; },
55                        base::Unretained(this)));
56   }
57 }
58
59 BluetoothSerialPortImpl::~BluetoothSerialPortImpl() {
60   if (bluetooth_socket_)
61     bluetooth_socket_->Disconnect(base::DoNothing());
62 }
63
64 void BluetoothSerialPortImpl::OpenSocket(const BluetoothUUID& service_class_id,
65                                          OpenCallback callback) {
66   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
67   BluetoothDevice* device = bluetooth_adapter_->GetDevice(address_);
68   if (!device) {
69     std::move(callback).Run(mojo::NullRemote());
70     delete this;
71     return;
72   }
73
74   auto split_callback = base::SplitOnceCallback(std::move(callback));
75   device->ConnectToService(
76       service_class_id,
77       base::BindOnce(&BluetoothSerialPortImpl::OnSocketConnected,
78                      weak_ptr_factory_.GetWeakPtr(),
79                      std::move(split_callback.first)),
80       base::BindOnce(&BluetoothSerialPortImpl::OnSocketConnectedError,
81                      weak_ptr_factory_.GetWeakPtr(),
82                      std::move(split_callback.second)));
83 }
84
85 void BluetoothSerialPortImpl::OnSocketConnected(
86     OpenCallback callback,
87     scoped_refptr<BluetoothSocket> socket) {
88   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
89   DCHECK(socket);
90   bluetooth_socket_ = std::move(socket);
91   mojo::PendingRemote<mojom::SerialPort> port =
92       receiver_.BindNewPipeAndPassRemote();
93   receiver_.set_disconnect_handler(
94       base::BindOnce([](BluetoothSerialPortImpl* self) { delete self; },
95                      base::Unretained(this)));
96   std::move(callback).Run(std::move(port));
97 }
98
99 void BluetoothSerialPortImpl::OnSocketConnectedError(
100     OpenCallback callback,
101     const std::string& message) {
102   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
103   std::move(callback).Run(mojo::NullRemote());
104   delete this;
105 }
106
107 void BluetoothSerialPortImpl::StartWriting(
108     mojo::ScopedDataPipeConsumerHandle consumer) {
109   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
110
111   if (in_stream_) {
112     receiver_.ReportBadMessage("Data pipe consumer still open.");
113     return;
114   }
115
116   if (!bluetooth_socket_) {
117     receiver_.ReportBadMessage("No Bluetooth socket.");
118     return;
119   }
120
121   in_stream_watcher_.Cancel();
122   in_stream_ = std::move(consumer);
123   in_stream_watcher_.Watch(
124       in_stream_.get(),
125       MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
126       MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
127       base::BindRepeating(&BluetoothSerialPortImpl::WriteToSocket,
128                           weak_ptr_factory_.GetWeakPtr()));
129   if (!write_pending_)
130     in_stream_watcher_.ArmOrNotify();
131 }
132
133 void BluetoothSerialPortImpl::StartReading(
134     mojo::ScopedDataPipeProducerHandle producer) {
135   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
136   if (out_stream_) {
137     mojo::ReportBadMessage("Data pipe producer still open.");
138     return;
139   }
140
141   if (!bluetooth_socket_) {
142     mojo::ReportBadMessage("No Bluetooth socket.");
143     return;
144   }
145
146   out_stream_watcher_.Cancel();
147   out_stream_ = std::move(producer);
148
149   out_stream_watcher_.Watch(
150       out_stream_.get(),
151       MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
152       MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
153       base::BindRepeating(&BluetoothSerialPortImpl::ReadFromSocketAndWriteOut,
154                           weak_ptr_factory_.GetWeakPtr()));
155   if (!read_pending_)
156     out_stream_watcher_.ArmOrNotify();
157 }
158
159 void BluetoothSerialPortImpl::ReadFromSocketAndWriteOut(
160     MojoResult result,
161     const mojo::HandleSignalsState& state) {
162   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
163   switch (result) {
164     case MOJO_RESULT_OK:
165       DCHECK(!read_pending_);
166       ReadMore();
167       break;
168     case MOJO_RESULT_SHOULD_WAIT:
169       // If there is no space to write, wait for more space.
170       out_stream_watcher_.ArmOrNotify();
171       break;
172     case MOJO_RESULT_FAILED_PRECONDITION:
173     case MOJO_RESULT_CANCELLED:
174       // The |out_stream_| has been closed.
175       out_stream_watcher_.Cancel();
176       out_stream_.reset();
177       break;
178     default:
179       NOTREACHED() << "Unexpected Mojo result: " << result;
180   }
181 }
182
183 void BluetoothSerialPortImpl::ResetPendingWriteBuffer() {
184   pending_write_buffer_ = base::span<char>();
185 }
186
187 void BluetoothSerialPortImpl::ResetReceiveBuffer() {
188   receive_buffer_size_ = 0;
189   receive_buffer_next_byte_pos_ = 0;
190   receive_buffer_.reset();
191 }
192
193 void BluetoothSerialPortImpl::ReadMore() {
194   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
195   DCHECK(out_stream_.is_valid());
196   DCHECK(!read_pending_);
197
198   void* buffer = nullptr;
199   uint32_t buffer_num_bytes = 0;
200   // The |buffer| is owned by |out_stream_|.
201   MojoResult result = out_stream_->BeginWriteData(&buffer, &buffer_num_bytes,
202                                                   MOJO_WRITE_DATA_FLAG_NONE);
203   if (result == MOJO_RESULT_SHOULD_WAIT) {
204     out_stream_watcher_.ArmOrNotify();
205     return;
206   }
207   if (result != MOJO_RESULT_OK) {
208     out_stream_watcher_.Cancel();
209     out_stream_.reset();
210     return;
211   }
212
213   if (!bluetooth_socket_) {
214     mojo::ReportBadMessage("No Bluetooth socket.");
215     return;
216   }
217
218   if (receive_buffer_) {
219     const size_t num_remaining_bytes =
220         receive_buffer_size_ - receive_buffer_next_byte_pos_;
221     const size_t bytes_to_copy =
222         std::min(num_remaining_bytes, size_t{buffer_num_bytes});
223     std::copy(
224         receive_buffer_->data() + receive_buffer_next_byte_pos_,
225         receive_buffer_->data() + receive_buffer_next_byte_pos_ + bytes_to_copy,
226         reinterpret_cast<char*>(buffer));
227     out_stream_->EndWriteData(bytes_to_copy);
228     if (bytes_to_copy == num_remaining_bytes) {  // If copied the last byte.
229       ResetReceiveBuffer();
230     } else {
231       receive_buffer_next_byte_pos_ += buffer_num_bytes;
232     }
233     out_stream_watcher_.ArmOrNotify();
234     return;
235   }
236   read_pending_ = true;
237   pending_write_buffer_ =
238       base::make_span(reinterpret_cast<char*>(buffer), buffer_num_bytes);
239   bluetooth_socket_->Receive(
240       buffer_num_bytes,
241       base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketReceive,
242                      weak_ptr_factory_.GetWeakPtr()),
243       base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketReceiveError,
244                      weak_ptr_factory_.GetWeakPtr()));
245 }
246
247 void BluetoothSerialPortImpl::OnBluetoothSocketReceive(
248     int num_bytes_received,
249     scoped_refptr<net::IOBuffer> receive_buffer) {
250   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
251   DCHECK_GT(num_bytes_received, 0);
252   DCHECK(receive_buffer->data());
253
254   const bool receive_completed_after_flush = pending_write_buffer_.empty();
255   read_pending_ = false;
256
257   if (receive_completed_after_flush) {
258     if (out_stream_) {
259       // The prior pipe was flushed while a read was in-flight. Now that
260       // StartReading() has been called, put this received data in the receive
261       // buffer which will prepend to the next read output and call ReadMore()
262       // to start consuming receive_buffer_.
263       receive_buffer_size_ = num_bytes_received;
264       receive_buffer_next_byte_pos_ = 0;
265       receive_buffer_ = std::move(receive_buffer);
266       ReadMore();
267     }
268     return;
269   }
270
271   // Note: Some platform implementations of BluetoothSocket::Receive ignore the
272   // buffer size parameter. This means that |num_bytes_received| could be
273   // larger than |pending_write_buffer_|. Check to avoid buffer overflow.
274   DCHECK(out_stream_);
275   size_t bytes_to_copy = std::min(pending_write_buffer_.size(),
276                                   static_cast<size_t>(num_bytes_received));
277   std::copy(receive_buffer->data(), receive_buffer->data() + bytes_to_copy,
278             pending_write_buffer_.data());
279   out_stream_->EndWriteData(bytes_to_copy);
280   if (pending_write_buffer_.size() < static_cast<size_t>(num_bytes_received)) {
281     receive_buffer_size_ = num_bytes_received;
282     receive_buffer_next_byte_pos_ = pending_write_buffer_.size();
283     receive_buffer_ = std::move(receive_buffer);
284   }
285   ResetPendingWriteBuffer();
286
287   ReadMore();
288 }
289
290 void BluetoothSerialPortImpl::OnBluetoothSocketReceiveError(
291     BluetoothSocket::ErrorReason error_reason,
292     const std::string& error_message) {
293   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
294
295   read_pending_ = false;
296   ResetPendingWriteBuffer();
297
298   if (out_stream_) {
299     if (client_) {
300       DCHECK(error_reason != BluetoothSocket::ErrorReason::kIOPending);
301       switch (error_reason) {
302         case BluetoothSocket::ErrorReason::kDisconnected:
303           client_->OnReadError(mojom::SerialReceiveError::DISCONNECTED);
304           break;
305         case BluetoothSocket::ErrorReason::kIOPending:
306           NOTREACHED();
307           break;
308         case BluetoothSocket::ErrorReason::kSystemError:
309           client_->OnReadError(mojom::SerialReceiveError::SYSTEM_ERROR);
310           break;
311       }
312     }
313
314     out_stream_->EndWriteData(0);
315     out_stream_watcher_.Cancel();
316     out_stream_.reset();
317     ResetReceiveBuffer();
318   }
319 }
320
321 void BluetoothSerialPortImpl::WriteToSocket(
322     MojoResult result,
323     const mojo::HandleSignalsState& state) {
324   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
325   switch (result) {
326     case MOJO_RESULT_OK:
327       DCHECK(!write_pending_);
328       WriteMore();
329       break;
330     case MOJO_RESULT_SHOULD_WAIT:
331       // If there is no space to write, wait for more space.
332       in_stream_watcher_.ArmOrNotify();
333       break;
334     case MOJO_RESULT_FAILED_PRECONDITION:
335     case MOJO_RESULT_CANCELLED:
336       // The |in_stream_| has been closed.
337       in_stream_watcher_.Cancel();
338       in_stream_.reset();
339
340       if (drain_callback_)
341         std::move(drain_callback_).Run();
342       break;
343     default:
344       NOTREACHED() << "Unexpected Mojo result: " << result;
345   }
346 }
347
348 void BluetoothSerialPortImpl::WriteMore() {
349   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
350   DCHECK(in_stream_.is_valid());
351   DCHECK(!write_pending_);
352
353   const void* buffer = nullptr;
354   uint32_t buffer_size = 0;
355   // |buffer| is owned by |in_stream_|.
356   MojoResult result = in_stream_->BeginReadData(&buffer, &buffer_size,
357                                                 MOJO_WRITE_DATA_FLAG_NONE);
358   if (result == MOJO_RESULT_SHOULD_WAIT) {
359     in_stream_watcher_.ArmOrNotify();
360     return;
361   }
362   if (result == MOJO_RESULT_FAILED_PRECONDITION) {
363     in_stream_watcher_.Cancel();
364     in_stream_.reset();
365     if (drain_callback_)
366       std::move(drain_callback_).Run();
367     return;
368   }
369   if (result != MOJO_RESULT_OK) {
370     in_stream_watcher_.Cancel();
371     in_stream_.reset();
372     return;
373   }
374
375   if (!bluetooth_socket_) {
376     mojo::ReportBadMessage("No Bluetooth socket.");
377     return;
378   }
379
380   write_pending_ = true;
381   // Copying the buffer because we might want to close in_stream_, thus
382   // invalidating |buffer|, which is passed to Send().
383   auto io_buffer = base::MakeRefCounted<net::IOBuffer>(buffer_size);
384   std::copy(static_cast<const char*>(buffer),
385             static_cast<const char*>(buffer) + buffer_size, io_buffer->data());
386
387   // The call to EndReadData() will be delayed until after Send() completes.
388   bluetooth_socket_->Send(
389       io_buffer, buffer_size,
390       base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketSend,
391                      weak_ptr_factory_.GetWeakPtr()),
392       base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketSendError,
393                      weak_ptr_factory_.GetWeakPtr()));
394 }
395
396 void BluetoothSerialPortImpl::OnBluetoothSocketSend(int num_bytes_sent) {
397   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
398   DCHECK_GE(num_bytes_sent, 0);
399
400   write_pending_ = false;
401
402   if (!flush_next_write_) {
403     DCHECK(in_stream_);
404     in_stream_->EndReadData(static_cast<uint32_t>(num_bytes_sent));
405   }
406   flush_next_write_ = false;
407
408   // If |in_stream_| is valid then StartWriting() has been called.
409   if (in_stream_) {
410     WriteMore();
411   }
412 }
413
414 void BluetoothSerialPortImpl::OnBluetoothSocketSendError(
415     const std::string& error_message) {
416   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
417
418   write_pending_ = false;
419   flush_next_write_ = false;
420
421   if (in_stream_) {
422     if (client_)
423       client_->OnSendError(mojom::SerialSendError::SYSTEM_ERROR);
424
425     in_stream_->EndReadData(0);
426     in_stream_watcher_.Cancel();
427     in_stream_.reset();
428   }
429 }
430
431 void BluetoothSerialPortImpl::OnSocketDisconnected(CloseCallback callback) {
432   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
433   std::move(callback).Run();
434   bluetooth_socket_.reset();  // Avoid calling Disconnect() twice.
435   delete this;
436 }
437
438 void BluetoothSerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
439                                     FlushCallback callback) {
440   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
441   switch (mode) {
442     case mojom::SerialPortFlushMode::kReceiveAndTransmit:
443       // Do nothing. This case exists to support the chrome.serial.flush()
444       // method and is not used by the Web Serial API.
445       break;
446     case mojom::SerialPortFlushMode::kReceive:
447       if (read_pending_)
448         out_stream_->EndWriteData(0);
449       out_stream_watcher_.Cancel();
450       out_stream_.reset();
451       ResetReceiveBuffer();
452       ResetPendingWriteBuffer();
453       break;
454     case mojom::SerialPortFlushMode::kTransmit:
455       if (write_pending_) {
456         flush_next_write_ = true;
457         in_stream_->EndReadData(0);
458       }
459       in_stream_watcher_.Cancel();
460       in_stream_.reset();
461       break;
462   }
463
464   std::move(callback).Run();
465 }
466
467 void BluetoothSerialPortImpl::Drain(DrainCallback callback) {
468   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
469   if (!in_stream_) {
470     std::move(callback).Run();
471     return;
472   }
473
474   drain_callback_ = std::move(callback);
475 }
476
477 void BluetoothSerialPortImpl::GetControlSignals(
478     GetControlSignalsCallback callback) {
479   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
480   auto signals = mojom::SerialPortControlSignals::New();
481   std::move(callback).Run(std::move(signals));
482 }
483
484 void BluetoothSerialPortImpl::SetControlSignals(
485     mojom::SerialHostControlSignalsPtr signals,
486     SetControlSignalsCallback callback) {
487   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
488   std::move(callback).Run(true);
489 }
490
491 void BluetoothSerialPortImpl::ConfigurePort(
492     mojom::SerialConnectionOptionsPtr options,
493     ConfigurePortCallback callback) {
494   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
495   options_ = std::move(options);
496   std::move(callback).Run(true);
497 }
498
499 void BluetoothSerialPortImpl::GetPortInfo(GetPortInfoCallback callback) {
500   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
501   auto info = mojom::SerialConnectionInfo::New(
502       /*bitrate=*/options_->bitrate, /*data_bits=*/options_->data_bits,
503       /*parity_bit=*/options_->parity_bit, /*stop_bits=*/options_->stop_bits,
504       /*cts_flow_control=*/options_->cts_flow_control);
505   std::move(callback).Run(std::move(info));
506 }
507
508 void BluetoothSerialPortImpl::Close(bool flush, CloseCallback callback) {
509   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
510   // It is safe to ignore |flush| because we get the semantics of a flush simply
511   // by disconnecting the socket. There are no hardware buffers to clear.
512   bluetooth_socket_->Disconnect(
513       base::BindOnce(&BluetoothSerialPortImpl::OnSocketDisconnected,
514                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
515 }
516
517 }  // namespace device