TCP: Implemented ACK return stream, as a feedback channel (to be read properly!)

This commit is contained in:
2026-03-04 12:24:05 +01:00
parent 939bb02ce2
commit a3a986830b
13 changed files with 611 additions and 80 deletions

View File

@@ -51,6 +51,77 @@ TCPImagePuller::TCPImagePuller(const std::string &tcp_addr,
cbor_thread = std::thread(&TCPImagePuller::CBORThread, this);
}
bool TCPImagePuller::SendAll(const void *buf, size_t len) {
const auto *p = static_cast<const uint8_t *>(buf);
size_t sent = 0;
while (sent < len) {
if (disconnect)
return false;
int local_fd = -1;
{
std::unique_lock ul(fd_mutex);
local_fd = fd;
}
if (local_fd < 0)
return false;
ssize_t rc = ::send(local_fd, p + sent, len - sent, MSG_NOSIGNAL);
if (rc < 0) {
if (errno == EINTR)
continue;
return false;
}
sent += static_cast<size_t>(rc);
}
return true;
}
bool TCPImagePuller::SendAck(const PullerAckMessage &ack) {
TcpFrameHeader h{};
h.type = static_cast<uint16_t>(TCPFrameType::ACK);
h.run_number = ack.run_number;
h.socket_number = ack.socket_number;
h.image_number = ack.image_number;
h.flags = 0;
if (ack.ok)
h.flags |= TCP_ACK_FLAG_OK;
if (ack.fatal)
h.flags |= TCP_ACK_FLAG_FATAL;
if (!ack.error_text.empty())
h.flags |= TCP_ACK_FLAG_HAS_ERROR_TEXT;
h.ack_for = static_cast<uint16_t>(ack.ack_for);
h.ack_processed_images = ack.processed_images;
h.ack_code = static_cast<uint32_t>(ack.error_code);
h.payload_size = ack.error_text.size();
if (!SendAll(&h, sizeof(h)))
return false;
if (!ack.error_text.empty())
return SendAll(ack.error_text.data(), ack.error_text.size());
return true;
}
void TCPImagePuller::CBORThread() {
auto ret = cbor_fifo.GetBlocking();
while (ret.tcp_msg) {
try {
const auto type = static_cast<TCPFrameType>(ret.tcp_msg->header.type);
if (type == TCPFrameType::CANCEL) {
outside_fifo.PutBlocking(ret);
} else {
ret.cbor = CBORStream2Deserialize(ret.tcp_msg->payload.data(), ret.tcp_msg->payload.size());
outside_fifo.PutBlocking(ret);
}
} catch (const JFJochException &e) {
logger.ErrorException(e);
}
ret = cbor_fifo.GetBlocking();
}
outside_fifo.PutBlocking(ret);
}
TCPImagePuller::~TCPImagePuller() {
TCPImagePuller::Disconnect();
}
@@ -179,6 +250,17 @@ void TCPImagePuller::ReceiverThread() {
continue;
}
// Ignore ACK on puller side
if (static_cast<TCPFrameType>(frame.header.type) == TCPFrameType::ACK) {
if (frame.header.payload_size > 0) {
std::vector<uint8_t> discard(frame.header.payload_size);
if (!ReadExact(discard.data(), discard.size())) {
CloseSocket();
}
}
continue;
}
ImagePullerOutput out;
out.tcp_msg = std::make_shared<RawFrame>();
out.tcp_msg->header = frame.header;
@@ -206,19 +288,6 @@ void TCPImagePuller::ReceiverThread() {
cbor_fifo.PutBlocking(ImagePullerOutput{});
}
void TCPImagePuller::CBORThread() {
auto ret = cbor_fifo.GetBlocking();
while (ret.tcp_msg) {
try {
ret.cbor = CBORStream2Deserialize(ret.tcp_msg->payload.data(), ret.tcp_msg->payload.size());
outside_fifo.PutBlocking(ret);
} catch (const JFJochException &e) {
logger.ErrorException(e);
}
ret = cbor_fifo.GetBlocking();
}
outside_fifo.PutBlocking(ret);
}
void TCPImagePuller::Disconnect() {
if (disconnect.exchange(true))
return;