GCC Code Coverage Report


Directory: ./
File: Drv/Ip/IpSocket.hpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 1 1 100.0%
Functions: 1 1 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 // ======================================================================
2 // \title IpSocket.hpp
3 // \author mstarch
4 // \brief hpp file for IpSocket core implementation classes
5 //
6 // \copyright
7 // Copyright 2009-2020, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 #ifndef DRV_IP_IPHELPER_HPP_
13 #define DRV_IP_IPHELPER_HPP_
14
15 #include <Fw/FPrimeBasicTypes.hpp>
16 #include <Os/Mutex.hpp>
17 #include <config/IpCfg.hpp>
18
19 namespace Drv {
20
21 struct SocketDescriptor final {
22 int fd = -1; //!< Used for all sockets to track the communication file descriptor
23 int serverFd = -1; //!< Used for server sockets to track the listening file descriptor
24 };
25
26 /**
27 * \brief Status enumeration for socket return values
28 */
29 enum SocketIpStatus {
30 SOCK_SUCCESS = 0, //!< Socket operation successful
31 SOCK_FAILED_TO_GET_SOCKET = -1, //!< Socket open failed
32 SOCK_FAILED_TO_GET_HOST_IP = -2, //!< Host IP lookup failed
33 SOCK_INVALID_IP_ADDRESS = -3, //!< Bad IP address supplied
34 SOCK_FAILED_TO_CONNECT = -4, //!< Failed to connect socket
35 SOCK_FAILED_TO_SET_SOCKET_OPTIONS = -5, //!< Failed to configure socket
36 SOCK_INTERRUPTED_TRY_AGAIN = -6, //!< Interrupted status for retries
37 SOCK_READ_ERROR = -7, //!< Failed to read socket
38 SOCK_DISCONNECTED = -8, //!< Failed to read socket with disconnect
39 SOCK_FAILED_TO_BIND = -9, //!< Failed to bind to socket
40 SOCK_FAILED_TO_LISTEN = -10, //!< Failed to listen on socket
41 SOCK_FAILED_TO_ACCEPT = -11, //!< Failed to accept connection
42 SOCK_SEND_ERROR = -13, //!< Failed to send after configured retries
43 SOCK_NOT_STARTED = -14, //!< Socket has not been started
44 SOCK_FAILED_TO_READ_BACK_PORT = -15, //!< Failed to read back port from connection
45 SOCK_NO_DATA_AVAILABLE = -16, //!< No data available or read operation would block
46 SOCK_ANOTHER_THREAD_OPENING = -17, //!< Another thread is opening
47 SOCK_AUTO_CONNECT_DISABLED = -18, //!< Automatic connections are disabled
48 SOCK_INVALID_CALL = -19 //!< Operation is invalid
49 };
50
51 /**
52 * \brief Helper base-class for setting up Berkeley sockets
53 *
54 * Certain IP headers have conflicting definitions with the m_data member of various types in fprime. TcpHelper
55 * separates the ip setup from the incoming Fw::Buffer in the primary component class preventing this collision.
56 */
57 class IpSocket {
58 public:
59 IpSocket();
60 2138 virtual ~IpSocket() {};
61 /**
62 * \brief configure the ip socket with an IPv4 address and transmission timeouts
63 *
64 * Configures the IP handler (Tcp, Tcp server, and Udp) to use the given IPv4 address and port.
65 * When multiple ports are used for send/receive these settings affect the send direction (as is
66 * the case for udp).
67 *
68 * \warning DNS resolution is NOT performed by this driver. The \a ipv4_address argument MUST be
69 * a NUL-terminated IPv4 address in dotted-quad notation of the form "x.x.x.x" (for example,
70 * "127.0.0.1"). Passing a textual hostname (e.g. "localhost") will be rejected at open() time
71 * with SOCK_INVALID_IP_ADDRESS. Callers that need DNS lookup must perform it themselves and
72 * pass the resolved IPv4 string to this function.
73 *
74 * Port cannot be set to 0 as dynamic port assignment is not supported.
75 *
76 * Note: for UDP sockets this is equivalent to `configureSend` and only sets up the
77 * transmission direction of the socket. A separate call to `configureRecv` is required to
78 * receive on the socket and should be made before the `open` call has been made.
79 *
80 * \param ipv4_address: IPv4 address (dotted-quad "x.x.x.x") used for outgoing transmissions
81 * (and incoming when tcp).
82 * \param port: port socket uses for outgoing transmissions (and incoming when tcp). Must NOT be 0.
83 * \param send_timeout_seconds: send timeout seconds portion
84 * \param send_timeout_microseconds: send timeout microseconds portion. Must be less than 1000000
85 * \return status of configure
86 */
87 virtual SocketIpStatus configure(const char* const ipv4_address,
88 const U16 port,
89 const U32 send_timeout_seconds,
90 const U32 send_timeout_microseconds);
91
92 /**
93 * \brief open the IP socket for communications
94 *
95 * This will open the IP socket for communication. This method error checks and validates properties set using the
96 * `configure` method. Tcp sockets will open bidirectional communication assuming the `configure` function was
97 * previously called. Udp sockets allow `configureRecv` and `configure`/`configureSend` calls to configure for
98 * each direction separately and may be operated in a single-direction or bidirectional mode. This call returns a
99 * status of SOCK_SEND means the port is ready for transmissions and any other status should be treated as an error
100 * with the socket not capable of sending nor receiving. This method will properly close resources on any
101 * unsuccessful status.
102 *
103 * In the case of server components (TcpServer) this function will block until a client has connected.
104 *
105 * Note: delegates to openProtocol for protocol specific implementation
106 *
107 * \param socketDescriptor: socket descriptor to update with opened port
108 * \return status of open
109 */
110 SocketIpStatus open(SocketDescriptor& socketDescriptor);
111 /**
112 * \brief send data out the IP socket from the given buffer
113 *
114 * Sends data out of the IpSocket. This outgoing transmission will be retried several times if the transmission
115 * fails to send all the data. Retries are globally configured in the `IpCfg.hpp` header. Should the
116 * socket be unavailable, SOCK_DISCONNECTED is returned and the socket should be reopened using the `open` call.
117 * This can happen even when the socket has already been opened should a transmission error/closure be detected.
118 * Unless an error is received, all data will have been transmitted. A zero-size send is a no-op returning
119 * SOCK_SUCCESS.
120 *
121 * Note: delegates to `sendProtocol` to send the data
122 *
123 * \param fd: file descriptor to send to
124 * \param data: pointer to data to send
125 * \param size: size of data to send
126 * \return status of the send, SOCK_DISCONNECTED to reopen, SOCK_SUCCESS on success, something else on error
127 */
128 virtual SocketIpStatus send(const SocketDescriptor& socketDescriptor, const U8* const data, const FwSizeType size);
129 /**
130 * \brief receive data from the IP socket from the given buffer
131 *
132 * Receives data from the IpSocket. Should the socket be unavailable, SOCK_DISCONNECTED will be returned and
133 * the socket should be reopened using the `open` call. This can happen even when the socket has already been opened
134 * should a transmission error/closure be detected. Since this blocks until data is available, it will retry as long
135 * as EINTR is set and less than a max number of iterations has passed. This function will block to receive data and
136 * will retry (up to a configured set of retries) as long as EINTR is returned.
137 *
138 * Note: delegates to `recvProtocol` to send the data
139 *
140 * \param socketDescriptor: socket descriptor to recv from
141 * \param data: pointer to data to fill with received data
142 * \param size: maximum size of data buffer to fill
143 * \return status of the send, SOCK_DISCONNECTED to reopen, SOCK_SUCCESS on success, something else on error
144 */
145 SocketIpStatus recv(const SocketDescriptor& fd, U8* const data, FwSizeType& size);
146
147 /**
148 * \brief closes the socket
149 *
150 * Closes the socket opened by the open call. In the case of the TcpServer, this does NOT close server's listening
151 * port but will close the active client connection.
152 *
153 * \param socketDescriptor: socket descriptor to close
154 */
155 void close(const SocketDescriptor& socketDescriptor);
156
157 /**
158 * \brief shutdown the socket
159 *
160 * Shuts down the socket opened by the open call. In the case of the TcpServer, this does not shut down server's
161 * listening port, but rather shuts down the active client.
162 *
163 * A shut down begins the termination of communication. The underlying socket will coordinate a clean shutdown, and
164 * it is safe to close the socket once a recv with 0 size has returned or an appropriate timeout has been reached.
165 *
166 * \param socketDescriptor: socket descriptor to shutdown
167 */
168 void shutdown(const SocketDescriptor& socketDescriptor);
169
170 protected:
171 /**
172 * \brief Check if the given port is valid for the socket
173 *
174 * Some ports should be allowed for sockets and disabled on others (e.g. port 0 is a valid tcp server port but not a
175 * client. This will check the port and return "true" if the port is valid, or "false" otherwise. In the default
176 * implementation, all ports are considered valid.
177 *
178 * \param port: port to check
179 * \return true if valid, false otherwise
180 */
181 virtual bool isValidPort(U16 port) const;
182
183 /**
184 * \brief setup the socket timeout properties of the opened outgoing socket
185 * \param socketDescriptor: socket descriptor to setup
186 * \return status of timeout setup
187 */
188 SocketIpStatus setupTimeouts(int socketFd);
189
190 /**
191 * \brief converts a given IPv4 address in dotted-quad form "x.x.x.x" to a network-order
192 * in_addr structure. ONLY works for IPv4; does NOT perform DNS resolution.
193 *
194 * On failure the destination buffer is zero-initialized so callers cannot accidentally
195 * consume uninitialized stack memory after a failed conversion.
196 *
197 * \param ipv4_address: NUL-terminated dotted-quad IPv4 address to convert (must not be null)
198 * \param out: pointer to a struct in_addr (or equivalently sized buffer) to fill
199 * (must not be null)
200 * \return: SOCK_SUCCESS on success, SOCK_INVALID_IP_ADDRESS on any malformed input
201 */
202 static SocketIpStatus addressToIp4(const char* const ipv4_address, void* const out);
203 /**
204 * \brief Protocol specific open implementation, called from open.
205 * \param socketDescriptor: (output) socket descriptor opened. Only valid on SOCK_SUCCESS. Otherwise will be invalid
206 * \return status of open
207 */
208 virtual SocketIpStatus openProtocol(SocketDescriptor& fd) = 0;
209 /**
210 * \brief Protocol specific implementation of send. Called directly with retry from send.
211 * \param socketDescriptor: socket descriptor to send to
212 * \param data: data to send
213 * \param size: size of data to send
214 * \return: size of data sent, or -1 on error.
215 */
216 virtual FwSignedSizeType sendProtocol(const SocketDescriptor& socketDescriptor,
217 const U8* const data,
218 const FwSizeType size) = 0;
219
220 /**
221 * \brief Protocol specific implementation of recv. Called directly with error handling from recv.
222 * \param socketDescriptor: socket descriptor to recv from
223 * \param data: data pointer to fill
224 * \param size: size of data buffer
225 * \return: size of data received, or -1 on error.
226 */
227 virtual FwSignedSizeType recvProtocol(const SocketDescriptor& socketDescriptor,
228 U8* const data,
229 const FwSizeType size) = 0;
230
231 /**
232 * \brief Handle zero return from recvProtocol
233 *
234 * This method is called when recvProtocol returns 0. The default implementation
235 * treats this as a disconnection (appropriate for TCP). Subclasses can override
236 * this to provide different behavior.
237 *
238 * @return SocketIpStatus Status to return from recv
239 */
240 virtual SocketIpStatus handleZeroReturn();
241
242 /**
243 * \brief setup the socket options of the input socket as defined in IpCfg.hpp
244 * \param socketFd: socket file descriptor
245 * \return status of setup options
246 */
247 SocketIpStatus setupSocketOptions(int socketFd);
248
249 U32 m_timeoutSeconds;
250 U32 m_timeoutMicroseconds;
251 U16 m_port; //!< IP address port used
252 char m_ipv4_address[SOCKET_MAX_IPV4_ADDRESS_SIZE]; //!< IPv4 address (dotted-quad "x.x.x.x")
253 };
254 } // namespace Drv
255
256 #endif /* DRV_SOCKETIPDRIVER_SOCKETHELPER_HPP_ */
257