Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/vanetza/rpc/asio_stream.cpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

156 lines
4.7 KiB
C++

#include <vanetza/common/annotation.hpp>
#include <vanetza/rpc/asio_stream.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#include <kj/debug.h>
namespace vanetza
{
namespace rpc
{
namespace
{
class KjBufferSequence
{
public:
using value_type = boost::asio::const_buffer;
class const_iterator
{
public:
using value_type = boost::asio::const_buffer;
using difference_type = std::ptrdiff_t;
using pointer = const value_type*;
using reference = value_type;
using iterator_category = std::forward_iterator_tag;
const_iterator() = default;
explicit const_iterator(const kj::ArrayPtr<const kj::byte>* ptr) : ptr_(ptr) {}
value_type operator*() const { return boost::asio::const_buffer(ptr_->begin(), ptr_->size()); }
const_iterator& operator++()
{
++ptr_;
return *this;
}
const_iterator operator++(int)
{
auto tmp = *this;
++ptr_;
return tmp;
}
bool operator==(const const_iterator& other) const { return ptr_ == other.ptr_; }
bool operator!=(const const_iterator& other) const { return ptr_ != other.ptr_; }
private:
const kj::ArrayPtr<const kj::byte>* ptr_ = nullptr;
};
explicit KjBufferSequence(kj::ArrayPtr<const kj::ArrayPtr<const kj::byte>> pieces) : pieces_(pieces) {}
const_iterator begin() const { return const_iterator(pieces_.begin()); }
const_iterator end() const { return const_iterator(pieces_.end()); }
private:
kj::ArrayPtr<const kj::ArrayPtr<const kj::byte>> pieces_;
};
} // namespace
AsioStream::AsioStream(boost::asio::ip::tcp::socket socket) : socket_(std::move(socket))
{
}
void AsioStream::shutdownWrite()
{
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
}
kj::Promise<void> AsioStream::write(const void* buffer, size_t size)
{
auto paf = kj::newPromiseAndFulfiller<void>();
boost::asio::const_buffer buf(buffer, size);
boost::asio::async_write(socket_, buf,
[this, fulfiller = std::move(paf.fulfiller)](
const boost::system::error_code& ec, std::size_t bytes_transferred) mutable {
mark_unused(bytes_transferred);
if (ec) {
signalDisconnect(ec);
fulfiller->reject(KJ_EXCEPTION(FAILED, "write", ec.message()));
} else {
fulfiller->fulfill();
}
});
return kj::mv(paf.promise);
}
kj::Promise<void> AsioStream::write(kj::ArrayPtr<const kj::ArrayPtr<const kj::byte>> pieces)
{
auto paf = kj::newPromiseAndFulfiller<void>();
boost::asio::async_write(socket_, KjBufferSequence(pieces),
[this, fulfiller = std::move(paf.fulfiller)](
const boost::system::error_code& ec, std::size_t bytes_transferred) mutable {
mark_unused(bytes_transferred);
if (ec) {
signalDisconnect(ec);
fulfiller->reject(KJ_EXCEPTION(FAILED, "write", ec.message()));
} else {
fulfiller->fulfill();
}
});
return kj::mv(paf.promise);
}
kj::Promise<void> AsioStream::whenWriteDisconnected()
{
if (!socket_.is_open()) {
return kj::READY_NOW;
}
KJ_IF_MAYBE(p, disconnect_promise_) {
return p->addBranch();
} else {
auto paf = kj::newPromiseAndFulfiller<void>();
disconnect_fulfiller_ = kj::mv(paf.fulfiller);
auto fork = paf.promise.fork();
auto result = fork.addBranch();
disconnect_promise_ = kj::mv(fork);
return kj::mv(result);
}
}
void AsioStream::signalDisconnect(const boost::system::error_code& ec)
{
if (ec != boost::asio::error::operation_aborted) {
boost::system::error_code ignored;
socket_.close(ignored);
KJ_IF_MAYBE(f, disconnect_fulfiller_) {
(*f)->fulfill();
disconnect_fulfiller_ = nullptr;
}
}
}
kj::Promise<size_t> AsioStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes)
{
auto paf = kj::newPromiseAndFulfiller<size_t>();
boost::asio::async_read(socket_, boost::asio::buffer(buffer, maxBytes), boost::asio::transfer_at_least(minBytes),
[this, fulfiller = std::move(paf.fulfiller)](
const boost::system::error_code& ec, std::size_t bytes_transferred) mutable {
if (ec) {
signalDisconnect(ec);
fulfiller->reject(KJ_EXCEPTION(FAILED, "read", ec.message()));
} else {
fulfiller->fulfill(kj::mv(bytes_transferred));
}
});
return kj::mv(paf.promise);
}
} // namespace rpc
} // namespace vanetza