blob: e61badf070bba797a89810b55c2045532e7ad7fe [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "model/devices/link_layer_socket_device.h"
#include <packet_runtime.h>
#include <cerrno>
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>
#include <vector>
#include "log.h"
#include "model/devices/device.h"
#include "packets/link_layer_packets.h"
#include "phy.h"
using std::vector;
namespace rootcanal {
LinkLayerSocketDevice::LinkLayerSocketDevice(
std::shared_ptr<AsyncDataChannel> socket_fd, Phy::Type phy_type)
: socket_(socket_fd),
phy_type_(phy_type),
size_bytes_(std::make_shared<std::vector<uint8_t>>(kSizeBytes)) {}
void LinkLayerSocketDevice::Tick() {
if (receiving_size_) {
ssize_t bytes_received =
socket_->Recv(size_bytes_->data() + offset_, kSizeBytes);
if (bytes_received <= 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// Nothing available yet.
// DEBUG("Nothing available yet...");
return;
}
INFO("Closing socket, received: {}, {}", bytes_received, strerror(errno));
Close();
return;
}
if ((size_t)bytes_received < bytes_left_) {
bytes_left_ -= bytes_received;
offset_ += bytes_received;
return;
}
pdl::packet::slice size(std::move(size_bytes_));
bytes_left_ = size.read_le<uint32_t>();
received_ = std::make_shared<std::vector<uint8_t>>(bytes_left_);
offset_ = 0;
receiving_size_ = false;
}
ssize_t bytes_received =
socket_->Recv(received_->data() + offset_, bytes_left_);
if (bytes_received <= 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// Nothing available yet.
// DEBUG("Nothing available yet...");
return;
}
INFO("Closing socket, received: {}, {}", bytes_received, strerror(errno));
Close();
return;
}
if ((size_t)bytes_received < bytes_left_) {
bytes_left_ -= bytes_received;
offset_ += bytes_received;
return;
}
bytes_left_ = kSizeBytes;
offset_ = 0;
receiving_size_ = true;
SendLinkLayerPacket(*received_, phy_type_);
}
void LinkLayerSocketDevice::Close() {
if (socket_) {
socket_->Close();
}
Device::Close();
}
void LinkLayerSocketDevice::ReceiveLinkLayerPacket(
model::packets::LinkLayerPacketView packet, Phy::Type /*type*/,
int8_t /*rssi*/) {
std::vector<uint8_t> packet_bytes = packet.bytes().bytes();
std::vector<uint8_t> size_bytes;
pdl::packet::Builder::write_le<uint32_t>(size_bytes, packet_bytes.size());
if (socket_->Send(size_bytes.data(), size_bytes.size()) == kSizeBytes) {
socket_->Send(packet_bytes.data(), packet_bytes.size());
}
}
} // namespace rootcanal