// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include constexpr uint32_t JFJOCH_TCP_MAGIC = 0x4A464A54; // JFJT constexpr uint32_t JFJOCH_TCP_VERSION = 3; // Upper bound on a single frame's payload. A receiver rejects any header claiming more // before allocating for it: an uncapped payload_size would otherwise drive a huge // resize() and take down the receiving thread. 1 GiB is far above any real image frame. constexpr uint64_t JFJOCH_TCP_MAX_PAYLOAD_SIZE = static_cast(1) << 30; enum class TCPFrameType : uint16_t { START = 1, DATA = 2, CALIBRATION = 3, END = 4, ACK = 5, CANCEL = 6, KEEPALIVE = 7, // Writer -> pusher liveness/backpressure heartbeat. Tells the pusher the writer // is alive but busy (e.g. stalled on a slow filesystem) and that it should keep // waiting for a proper ACK rather than declaring the connection dead. Carries the // writer's current FIFO occupancy in the ack_fifo_* fields. BUSY = 8, }; enum class TCPAckCode : uint16_t { None = 0, StartFailed = 1, DataWriteFailed = 2, EndFailed = 3, DiskQuotaExceeded = 4, NoSpaceLeft = 5, PermissionDenied = 6, IoError = 7, ProtocolError = 8 }; constexpr uint32_t TCP_ACK_FLAG_OK = 1u << 0; constexpr uint32_t TCP_ACK_FLAG_FATAL = 1u << 1; constexpr uint32_t TCP_ACK_FLAG_HAS_ERROR_TEXT = 1u << 2; struct alignas(64) TcpFrameHeader { uint32_t magic = JFJOCH_TCP_MAGIC; uint16_t version = JFJOCH_TCP_VERSION ; uint16_t type = 0; uint64_t image_number = 0; uint64_t payload_size = 0; uint32_t socket_number = 0; uint32_t flags = 0; uint64_t run_number = 0; uint32_t ack_processed_images = 0; uint16_t ack_code = 0; uint16_t ack_for = 0; uint64_t ack_fifo_occupancy = 0; uint64_t ack_fifo_max_occupancy = 0; };