#ifndef TCPS_CLIENT_H_ #define TCPS_CLIENT_H_ /** * @file TCPSClient.h * @brief Auto-reconnecting TCP receiver for the UDPS wire format. * * TCPSClient is the consumer-side counterpart of TCPSServer. It connects to a * TCPSServer, reads UDPS frames (17-byte header + payload) from the byte stream * and delivers CONFIG / DATA payloads through UDPSClientListener, so any * listener written for UDPSClient works unchanged. * * It runs its own thread (SingleThreadService); every wait inside Execute() is * bounded by 50 ms so Stop() is prompt. A partial frame survives across * iterations. Bad magic, an oversize length, or a fragmented frame means the * stream cannot be trusted any more: the connection is dropped and re-opened. * * There is no CONNECT / ACK / keepalive traffic: the TCP connection is the * session and the server sends CONFIG on accept. */ #include "EmbeddedServiceMethodBinderI.h" #include "FastPollingMutexSem.h" #include "ExecutionInfo.h" #include "SingleThreadService.h" #include "StreamString.h" #include "StructuredDataI.h" #include "UDPSClient.h" #include "UDPSProtocol.h" #include "UDPSTransportI.h" namespace MARTe { class TCPSClient; /** * One stream of a (possibly multiplexed) TCPSClient connection, seen as an * independent UDPSClientI. Obtained from TCPSClient::GetStream(). Start()/Stop() * are reference counted so the shared connection runs while any stream wants it. */ class TCPSClientStream : public UDPSClientI { public: TCPSClientStream(TCPSClient &owner, uint32 index); virtual ~TCPSClientStream(); /** The connection is configured through its TCPSClient; always succeeds. */ virtual bool Initialise(StructuredDataI &data); virtual void SetListener(UDPSClientListener *newListener); virtual bool Start(); virtual bool Stop(); virtual uint32 GetLastDataGap() const; private: TCPSClient &owner; uint32 index; bool started; }; class TCPSClient : public UDPSClientI, public EmbeddedServiceMethodBinderI { public: /** Most streams one connection can multiplex. */ static const uint32 TCPS_CLIENT_MAX_STREAMS = UDPS_TCP_MAX_STREAMS; /** Default delay between reconnect attempts (seconds). */ static const uint32 TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S = 2u; TCPSClient(); virtual ~TCPSClient(); /** * Keys: * - ServerAddr (char*) IPv4 address or host name. Default 127.0.0.1. * - Port (uint32) Server TCP port. Required. * - StreamName (char*) Optional. When set, a SUBSCRIBE frame carrying * this name is sent right after every connect, to * select one stream of a TCPStreamService. A plain * TCPSServer ignores (discards) it. A comma * separated list ("a,b,c") multiplexes several * streams over this one connection; stream i of * the list is reached through GetStream(i). * - SilenceTimeout (float32) Seconds without any received byte before the * connection is considered dead. Default 0 * (disabled: TCP reports a dead peer itself). * - ReconnectDelay (float32) Seconds between connection attempts. Default 2. * - CPUMask (uint32) Receive thread affinity. Default 0xFFFFFFFF. * - StackSize (uint32) Receive thread stack. Default 65536. */ virtual bool Initialise(StructuredDataI &data); virtual void SetListener(UDPSClientListener *newListener); /** Listener of stream @p index (0 = SetListener()). Call before Start(). */ void SetStreamListener(uint32 index, UDPSClientListener *newListener); /** @return number of streams subscribed to (1 unless StreamName is a list). */ uint32 GetNumStreams() const; /** * @return a UDPSClientI for stream @p index, owned by this client (NULL if out of * range). Valid after Initialise(). */ UDPSClientI *GetStream(uint32 index); /** Counter gap of the DATA frame of stream @p index being delivered. */ uint32 GetStreamDataGap(uint32 index) const; /** Reference-counted Start()/Stop() used by the TCPSClientStream facades. */ bool AcquireStart(); bool ReleaseStop(); virtual bool Start(); virtual bool Stop(); /** Thread entry point; do not call directly. */ virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info); /** Packets the server dropped for this client just before the DATA frame being delivered. */ virtual uint32 GetLastDataGap() const; /** @return true while a connection is established. */ bool IsConnected() const; /** @return connections established since Start(). */ uint32 GetConnectionCount() const; /** @return connections dropped because of a protocol violation. */ uint32 GetProtocolErrors() const; private: bool Connect(); void Disconnect(); /** One bounded receive step. @return false when the connection is lost. */ bool ReceiveStep(); /** Deliver the complete frame sitting in rxBuf. @return false on a protocol error. */ bool Dispatch(); /** Validate StreamName as one name or a comma separated list; sets numStreams. */ bool ParseStreamList(); StreamString serverAddr; StreamString streamName; uint32 serverPort; uint64 silenceTimeoutTicks; uint64 reconnectDelayTicks; uint32 cpuMask; uint32 stackSize; uint32 numStreams; UDPSClientListener *listeners[UDPS_TCP_MAX_STREAMS]; TCPSClientStream *facades[UDPS_TCP_MAX_STREAMS]; FastPollingMutexSem refMutex; uint32 startRefs; SingleThreadService threadService; int fd; volatile bool connected; volatile bool stopping; uint64 lastDataTicks; uint64 disconnectTick; volatile uint32 connectionCount; volatile uint32 protocolErrors; uint8 *rxBuf; ///< header + payload of the frame being received uint32 rxHave; ///< bytes of the current frame received so far uint32 rxWant; ///< total bytes the current frame needs (header first) bool rxHeaderOk; ///< header validated; rxWant covers the payload uint32 lastDataCounter[UDPS_TCP_MAX_STREAMS]; ///< counter of the last delivered DATA frame bool lastDataCounterValid[UDPS_TCP_MAX_STREAMS]; ///< false until the first DATA frame of a connection uint32 lastDataGap[UDPS_TCP_MAX_STREAMS]; ///< frames missing before the one being delivered }; } // namespace MARTe #endif // TCPS_CLIENT_H_