blob: 8e76f505d4e7a9008757671e8f175a19c699f8a1 [file] [log] [blame]
// 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