35#ifndef _OPENLCB_IFTCPIMPL_HXX_
36#define _OPENLCB_IFTCPIMPL_HXX_
40#include "utils/HubDeviceSelect.hxx"
57 NodeID gateway_node_id,
long long sequence,
string *tgt)
61 string &target = *tgt;
102 const uint8_t *src =
static_cast<const uint8_t *
>(data);
122 LOG(
WARNING,
"Incomplete or incorrectly formatted TCP message.");
142 const char *msg = &src[
HDR_LEN];
151 int payload_bytes = expected_size -
HDR_LEN;
162 payload_bytes -= payload_ofs;
163 if (payload_bytes < 0)
168 tgt->
payload.assign(msg + payload_ofs, payload_bytes);
326 b->data()->dstNode = n;
328 return release_and_exit();
351 return release_and_exit();
363 return static_cast<If *
>(service());
405 if (e->is_selected(&helper_))
472 if (needed > available)
532 b->data()->assign(std::move(
msg_));
BufferPtr< T > get_buffer_deleter(Buffer< T > *b)
Helper function to create a BufferPtr of an appropriate type without having to explicitly specify the...
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
void notify() override
Implementation of the barrier semantics.
BarrierNotifiable * new_child()
Creates a new child notifiable of the current done notifiable.
Base class for all QMember types that hold data in an expandable format.
Base class of everything with a virtual destructor.
void unselect(Selectable *job)
Removes a job from the select loop.
Shared base class for thread-based and select-based hub devices.
virtual void report_read_error()=0
Callback from the readflow when it encounters an error.
BarrierNotifiable barrier_
This notifiable will be called (if not NULL) upon read or write error.
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
MessageType * alloc()
Synchronously allocates a message buffer from the pool of this flow.
HubPort that connects a select-aware device to a strongly typed Hub.
@ MAX_PRIO
Largest priority we accept (otherwise we clip).
ExecutorBase * executor()
Return type for a state flow callback.
Base class for state machines.
Action read_single(StateFlowSelectHelper *helper, int fd, void *buf, size_t size, Callback c, unsigned priority=Selectable::MAX_PRIO)
Attempts to read at most size_t bytes, and blocks the caller until at least one byte is read.
Service * service()
Return a pointer to the service I am bound to.
Action allocate_and_call(FlowInterface< Buffer< T > > *target_flow, Callback c, Pool *pool=nullptr)
Allocates a buffer from a pool and proceed to the next state when allocation is successful.
Action exit()
Terminate current StateFlow activity.
void start_flow(Callback c)
Resets the flow to the specified state and starts it.
Buffer< T > * get_allocation_result(FlowInterface< Buffer< T > > *target_flow)
Takes the result of the asynchronous allocation.
Action call_immediately(Callback c)
Imediately call the next state upon return.
Action set_terminated()
Sets the flow to terminated state.
Base::Action Action
Allows using Action without having StateFlowBase:: prefix in front of it.
void send(MessageType *msg, unsigned priority=UINT_MAX) OVERRIDE
Sends a message to the state flow for processing.
MessageType * transfer_message()
Releases ownership of the current message.
Implementation of sequence number generator that uses the real clock.
long long sequence_
Sequence number of last sent message.
long long get_sequence_number() override
This flow is listening to data from a TCP connection, segments the incoming data into TcpMessages bas...
Action start_msg()
In this state the internal buffer (bufOfs_) points at the beginning of a message.
uint16_t bufOfs_
First active byte (offset of the beginning) in the read buffer.
HubPortInterface * skipMember_
Parsed messages will be initialized to this skipMember_.
static constexpr unsigned READ_BUFFER_SIZE
We attempt to read this many bytes in one go from the FD.
static constexpr unsigned READ_PRIO
What priority to use for reads from fds.
int expectedLen_
How many bytes we think the current message will be.
Action read_more_bytes()
Helper state to call the stateflow kernel to read bytes from the fd into the internal buffer.
FdToTcpParser(FdHubPortService *s, HubPortInterface *dst, HubPortInterface *skipMember)
Constructor.
HubPortInterface * dst_
Where to send parsed messages to.
uint8_t buffer_[READ_BUFFER_SIZE]
Temporary buffer to read into from the FD.
void notify_barrier()
Calls into the parent flow's barrier notify, but makes sure to only do this once in the lifetime of *...
Action parse_bytes()
Intermediate state where we are.
void shutdown()
Stops listening and terminates the flow.
string msg_
Assembly buffer. Holds the captured message so far.
Action have_alloc_msg()
Sends an assembled message (2) to the destination flow.
Action read_done()
Callback state when the kernel read is completed.
uint16_t bufEnd_
Offset of the end in the read buffer.
FdHubPortService * device()
static constexpr unsigned DEFAULT_PACKET_SIZE
If we have to guess at the size of the packet, we start by allocating this many bytes.
Action send_entry()
Sends an assembled message (1) to the destination flow.
uint8_t barrierOwned_
true iff pending parent->barrier_.notify()
Abstract class representing an OpenLCB Interface.
MessageDispatchFlow * dispatcher()
Node * lookup_local_node(NodeID id)
Looks up a node ID in the local nodes' registry.
virtual long long get_sequence_number()=0
Returns the next strictly monotonic sequence number.
Static class for constants and utilities related to the TCP transport protocol.
static unsigned guess_priority(const string &tcp_payload)
static void render_tcp_message(const GenMessage &msg, NodeID gateway_node_id, long long sequence, string *tgt)
Renders a TCP message into a single buffer, ready to transmit.
TcpDefs()
No usable constructor; this is a static-only class.
@ HDR_SIZE_OFS
Offset in the header of the size field.
@ MSG_DST_OFS
Offset in the message (=after the header) of the dst node ID field (for addressed MTI only).
@ HDR_TIMESTAMP_OFS
Offset in the header of the timestamp (seq no) field.
@ HDR_SIZE_END
Offset in the header of the end of the size field.
@ MSG_SRC_OFS
Offset in the message (=after the header) of the src node ID field.
@ MSG_MTI_OFS
Offset in the message (=after the header) of the MTI field.
@ HDR_FLAG_OFS
Offset in the header of the flags field.
@ HDR_GATEWAY_OFS
Offset in the header of the source gateway field.
@ MSG_ADR_PAYLOAD_OFS
Offset in the message (=after the header) of the message payload (for addressed MTI only).
@ FLAGS_FRAGMENT_NOT_LAST
"not last" fragmenting bit in the flags field.
@ MSG_GLOBAL_PAYLOAD_OFS
Offset in the message (=after the header) of the message payload (for global MTI only).
@ FLAGS_FRAGMENT_NOT_FIRST
"not first" fragmenting bit in the flags field.
@ HDR_LEN
Total length of the fixed header.
@ FLAGS_RESVD1_ZERO_CHECK
Reserved bits in the flags field. Check as zero.
@ FLAGS_CHAINING
Chaining bit in the uint16 flags field.
@ FLAGS_OPENLCB_MSG
Bit in the uint16 flags field in the header that signals frames that carry an OpenLCB message.
@ MIN_ADR_MESSAGE_SIZE
Minimum length of a valid message that has an addressed MTI.
@ FLAGS_RESVD2_IGNORED
Reserved bits in the flags field. Ignore (by the standard).
@ ABS_MTI_OFS
Offset from the header of the MTI field in the message.
@ MIN_MESSAGE_SIZE
Minimum length of a valid message.
static bool parse_tcp_message(const string &src, GenMessage *tgt)
Parses a TCP message format (from binary payload) into a general OpenLCB message.
static int get_tcp_message_len(const void *data, size_t len)
Guesses the length of a tcp message from looking at the prefix of the payload.
Simple stateless translator for incoming TCP messages from binary format into the structured format.
void send(Buffer< HubData > *data, unsigned prio) override
Entry point for the incoming (binary) data.
MessageHandler * target_
Flow(interface) where to pass on the parsed GenMessage.
TcpRecvFlow(MessageHandler *target)
This flow renders outgoing OpenLCB messages to their TCP stream representation.
NodeID get_gateway_node_id()
Action entry() override
Handler where dequeueing of messages to be sent starts.
NodeID gatewayId_
Populated into the source gateway field of the outgoing messages.
HubPortInterface * skipMember_
This value will be populated to the skipMember_ field.
Action render_src_message()
Callback state after allocation succeeded.
HubPortInterface * sendTarget_
Where to send the rendered messages to.
SequenceNumberGenerator * sequenceNumberGenerator_
Responsible for generating the sequence numbers of the outgoing messages.
TcpSendFlow(If *service, NodeID gateway_node_id, HubPortInterface *send_target, HubPortInterface *skip_member, SequenceNumberGenerator *sequence)
Constructor.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int WARNING
Loglevel that is always printed, reporting a warning or a retryable error.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define DASSERT(x)
Debug assertion facility.
void node_id_to_data(NodeID id, void *data)
Convenience function to render a 48-bit NMRAnet node ID into an existing buffer.
NodeID data_to_node_id(const void *d)
Converts 6 bytes of big-endian data to a node ID.
uint64_t NodeID
48-bit NMRAnet Node ID type
uint16_t data_to_error(const void *data)
Parses an error code from a payload object at a given pointer.
void error_to_data(uint16_t error_code, void *data)
Writes an error code into a payload object at a given pointer.
long long os_get_time_monotonic(void)
Get the monotonic time since the system started.
Use this class to read from an fd using select() in a state flow.
unsigned remaining_
Number of bytes still outstanding to read.
unsigned hasError_
1 if there was an error reading of writing.
static unsigned int mti_priority(MTI mti)
Get the MTI priority (value 0 through 3).
MTI
Known Message type indicators.
static bool get_mti_address(MTI mti)
Get the MTI address present value field.
This class is used in the dispatching of incoming or outgoing NMRAnet messages to the message handler...
@ DSTFLAG_NOT_FIRST_MESSAGE
Signals to the stack that we need to set the continuation bits in the outgoing message to indicate th...
@ DSTFLAG_NOT_LAST_MESSAGE
Signals to the stack that we need to set the continuation bits in the outgoing message to indicate th...
NodeHandle dst
Destination node.
NodeHandle src
Source node.
Defs::MTI mti
OpenLCB MTI of the incoming message.
string payload
Data content in the message body.
NodeID id
48-bit NMRAnet Node ID
void clear()
Resets node handle to global (broadcast) handle.