| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| |
| #include <base/bind.h> |
| |
| #include "hermes/socket_qrtr.h" |
| |
| #include <libqrtr.h> |
| |
| namespace { |
| |
| constexpr uint8_t kQrtrPort = 0; |
| |
| } // namespace |
| |
| namespace hermes { |
| |
| SocketQrtr::SocketQrtr() = default; |
| |
| void SocketQrtr::SetDataAvailableCallback(DataAvailableCallback cb) { |
| cb_ = cb; |
| } |
| |
| bool SocketQrtr::Open() { |
| if (IsValid()) { |
| return true; |
| } |
| |
| socket_.reset(qrtr_open(kQrtrPort)); |
| if (!socket_.is_valid()) { |
| LOG(ERROR) << "Failed to open QRTR socket with port " << kQrtrPort; |
| return false; |
| } |
| |
| watcher_ = base::FileDescriptorWatcher::WatchReadable( |
| socket_.get(), |
| base::BindRepeating(&SocketQrtr::OnFileCanReadWithoutBlocking, |
| base::Unretained(this))); |
| |
| if (!watcher_) { |
| LOG(ERROR) << "Failed to set up WatchFileDescriptor"; |
| socket_.reset(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void SocketQrtr::Close() { |
| if (IsValid()) { |
| watcher_ = nullptr; |
| // Since socket_ is a ScopedFD, socket_.reset() calls close() on the socket. |
| socket_.reset(); |
| } |
| } |
| |
| bool SocketQrtr::StartService(uint32_t service, |
| uint16_t version_major, |
| uint16_t version_minor) { |
| return qrtr_new_lookup(socket_.get(), service, version_major, |
| version_minor) >= 0; |
| } |
| |
| bool SocketQrtr::StopService(uint32_t service, |
| uint16_t version_major, |
| uint16_t version_minor) { |
| return qrtr_remove_lookup(socket_.get(), service, version_major, |
| version_minor) >= 0; |
| } |
| |
| int SocketQrtr::Recv(void* buf, size_t size, void* metadata) { |
| uint32_t node, port; |
| int ret = qrtr_recvfrom(socket_.get(), buf, size, &node, &port); |
| VLOG(2) << "Receiving packet from node: " << node << " port: " << port; |
| if (metadata) { |
| PacketMetadata* data = reinterpret_cast<PacketMetadata*>(metadata); |
| data->node = node; |
| data->port = port; |
| } |
| return ret; |
| } |
| |
| int SocketQrtr::Send(const void* data, size_t size, const void* metadata) { |
| uint32_t node = 0, port = 0; |
| if (metadata) { |
| const PacketMetadata* data = |
| reinterpret_cast<const PacketMetadata*>(metadata); |
| node = data->node; |
| port = data->port; |
| } |
| VLOG(2) << "Sending packet to node: " << node << " port: " << port; |
| return qrtr_sendto(socket_.get(), node, port, data, size); |
| } |
| |
| void SocketQrtr::OnFileCanReadWithoutBlocking() { |
| if (cb_) { |
| cb_.Run(this); |
| } |
| } |
| |
| bool SocketQrtr::PacketMetadata::operator==( |
| const SocketQrtr::PacketMetadata& rhs) const { |
| return this->port == rhs.port && this->node == rhs.node; |
| } |
| |
| } // namespace hermes |