F´ Flight Software - C/C++ Documentation devel
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
IpSocket.cpp
Go to the documentation of this file.
1// ======================================================================
2// \title IpSocket.cpp
3// \author mstarch
4// \brief cpp 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#include <cstring>
13#include <Drv/Ip/IpSocket.hpp>
14#include <Fw/Types/Assert.hpp>
15#include <FpConfig.hpp>
17#include <sys/time.h>
18
19// This implementation has primarily implemented to isolate
20// the socket interface from the F' Fw::Buffer class.
21// There is a macro in VxWorks (m_data) that collides with
22// the m_data member in Fw::Buffer.
23
24#ifdef TGT_OS_TYPE_VXWORKS
25#include <socket.h>
26 #include <inetLib.h>
27 #include <fioLib.h>
28 #include <hostLib.h>
29 #include <ioLib.h>
30 #include <vxWorks.h>
31 #include <sockLib.h>
32 #include <fioLib.h>
33 #include <taskLib.h>
34 #include <sysLib.h>
35 #include <errnoLib.h>
36 #include <cstring>
37#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
38#include <sys/socket.h>
39#include <unistd.h>
40#include <cerrno>
41#include <arpa/inet.h>
42#else
43#error OS not supported for IP Socket Communications
44#endif
45
46
47namespace Drv {
48
49IpSocket::IpSocket() : m_fd(-1), m_timeoutSeconds(0), m_timeoutMicroseconds(0), m_port(0), m_open(false), m_started(false) {
50 ::memset(m_hostname, 0, sizeof(m_hostname));
51}
52
53SocketIpStatus IpSocket::configure(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) {
54 FW_ASSERT(timeout_microseconds < 1000000, timeout_microseconds);
55 FW_ASSERT(port != 0, port);
56 this->m_timeoutSeconds = timeout_seconds;
57 this->m_timeoutMicroseconds = timeout_microseconds;
58 this->m_port = port;
60 return SOCK_SUCCESS;
61}
62
64// Get the IP address from host
65#ifdef TGT_OS_TYPE_VXWORKS
66 // No timeouts set on Vxworks
67#else
68 // Set timeout socket option
69 struct timeval timeout;
70 timeout.tv_sec = this->m_timeoutSeconds;
71 timeout.tv_usec = this->m_timeoutMicroseconds;
72 // set socket write to timeout after 1 sec
73 if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout)) < 0) {
75 }
76#endif
77 return SOCK_SUCCESS;
78}
79
80SocketIpStatus IpSocket::addressToIp4(const char* address, void* ip4) {
81 FW_ASSERT(address != nullptr);
82 FW_ASSERT(ip4 != nullptr);
83 // Get the IP address from host
84#ifdef TGT_OS_TYPE_VXWORKS
85 NATIVE_INT_TYPE ip = inet_addr(address);
86 if (ip == ERROR) {
88 }
89 // from sin_addr, which has one struct
90 // member s_addr, which is unsigned int
91 *reinterpret_cast<unsigned long*>(ip4) = ip;
92#else
93 // First IP address to socket sin_addr
94 if (not ::inet_pton(AF_INET, address, ip4)) {
96 };
97#endif
98 return SOCK_SUCCESS;
99}
100
102 bool is_started = false;
103 this->m_lock.lock();
104 is_started = this->m_started;
105 this->m_lock.unLock();
106 return is_started;
107}
108
110 bool is_open = false;
111 this->m_lock.lock();
112 is_open = this->m_open;
113 this->m_lock.unLock();
114 return is_open;
115}
116
118 this->m_lock.lock();
119 if (this->m_fd != -1) {
120 (void)::shutdown(this->m_fd, SHUT_RDWR);
121 (void)::close(this->m_fd);
122 this->m_fd = -1;
123 }
124 this->m_open = false;
125 this->m_lock.unLock();
126}
127
129 this->close();
130 this->m_lock.lock();
131 this->m_started = false;
132 this->m_lock.unLock();
133}
134
136 this->m_lock.lock();
137 this->m_started = true;
138 this->m_lock.unLock();
139 return SOCK_SUCCESS;
140}
141
143 NATIVE_INT_TYPE fd = -1;
145 FW_ASSERT(m_fd == -1 and not m_open); // Ensure we are not opening an opened socket
146 // Open a TCP socket for incoming commands, and outgoing data if not using UDP
147 status = this->openProtocol(fd);
148 if (status != SOCK_SUCCESS) {
149 FW_ASSERT(m_fd == -1); // Ensure we properly kept closed on error
150 return status;
151 }
152 // Lock to update values and "officially open"
153 this->m_lock.lock();
154 this->m_fd = fd;
155 this->m_open = true;
156 this->m_lock.unLock();
157 return status;
158}
159
160SocketIpStatus IpSocket::send(const U8* const data, const U32 size) {
161 U32 total = 0;
162 I32 sent = 0;
163 // Prevent transmission before connection, or after a disconnect
164 if (this->m_fd == -1) {
165 return SOCK_DISCONNECTED;
166 }
167 // Attempt to send out data and retry as necessary
168 for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
169 // Send using my specific protocol
170 sent = this->sendProtocol(data + total, size - total);
171 // Error is EINTR or timeout just try again
172 if (((sent == -1) && (errno == EINTR)) || (sent == 0)) {
173 continue;
174 }
175 // Error bad file descriptor is a close along with reset
176 else if ((sent == -1) && ((errno == EBADF) || (errno == ECONNRESET))) {
177 this->close();
178 return SOCK_DISCONNECTED;
179 }
180 // Error returned, and it wasn't an interrupt nor a disconnect
181 else if (sent == -1) {
182 return SOCK_SEND_ERROR;
183 }
184 FW_ASSERT(sent > 0, sent);
185 total += sent;
186 }
187 // Failed to retry enough to send all data
188 if (total < size) {
190 }
191 FW_ASSERT(total == size, total, size); // Ensure we sent everything
192 return SOCK_SUCCESS;
193}
194
195SocketIpStatus IpSocket::recv(U8* data, I32& req_read) {
196 I32 size = 0;
197 // Check for previously disconnected socket
198 if (m_fd == -1) {
199 return SOCK_DISCONNECTED;
200 }
201
202 // Try to read until we fail to receive data
203 for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (size <= 0); i++) {
204 // Attempt to recv out data
205 size = this->recvProtocol(data, req_read);
206 // Error is EINTR, just try again
207 if (size == -1 && ((errno == EINTR) || errno == EAGAIN)) {
208 continue;
209 }
210 // Zero bytes read reset or bad ef means we've disconnected
211 else if (size == 0 || ((size == -1) && ((errno == ECONNRESET) || (errno == EBADF)))) {
212 this->close();
213 req_read = size;
214 return SOCK_DISCONNECTED;
215 }
216 // Error returned, and it wasn't an interrupt, nor a disconnect
217 else if (size == -1) {
218 req_read = size;
219 return SOCK_READ_ERROR; // Stop recv task on error
220 }
221 }
222 req_read = size;
223 // Prevent interrupted socket being viewed as success
224 if (size == -1) {
226 }
227 return SOCK_SUCCESS;
228}
229
230} // namespace Drv
#define FW_ASSERT(...)
Definition Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition BasicTypes.h:26
C++-compatible configuration header for fprime configuration.
@ SOCKET_MAX_HOSTNAME_SIZE
Definition IpCfg.hpp:23
@ SOCKET_MAX_ITERATIONS
Definition IpCfg.hpp:21
virtual I32 sendProtocol(const U8 *const data, const U32 size)=0
Protocol specific implementation of send. Called directly with retry from send.
void close()
closes the socket
Definition IpSocket.cpp:117
U16 m_port
IP address port used.
Definition IpSocket.hpp:207
bool isStarted()
Returns true when the socket is started.
Definition IpSocket.cpp:101
virtual I32 recvProtocol(U8 *const data, const U32 size)=0
Protocol specific implementation of recv. Called directly with error handling from recv.
bool isOpened()
check if IP socket has previously been opened
Definition IpSocket.cpp:109
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition IpSocket.hpp:210
SocketIpStatus recv(U8 *const data, I32 &size)
receive data from the IP socket from the given buffer
Definition IpSocket.cpp:195
bool m_started
Have we successfully started the socket.
Definition IpSocket.hpp:209
bool m_open
Have we successfully opened.
Definition IpSocket.hpp:208
SocketIpStatus send(const U8 *const data, const U32 size)
send data out the IP socket from the given buffer
Definition IpSocket.cpp:160
SocketIpStatus configure(const char *hostname, const U16 port, const U32 send_timeout_seconds, const U32 send_timeout_microseconds)
configure the ip socket with host and transmission timeouts
Definition IpSocket.cpp:53
U32 m_timeoutMicroseconds
Definition IpSocket.hpp:206
Os::Mutex m_lock
Definition IpSocket.hpp:203
static SocketIpStatus addressToIp4(const char *address, void *ip4)
converts a given address in dot form x.x.x.x to an ip address. ONLY works for IPv4.
Definition IpSocket.cpp:80
NATIVE_INT_TYPE m_fd
Definition IpSocket.hpp:204
SocketIpStatus setupTimeouts(NATIVE_INT_TYPE socketFd)
setup the socket timeout properties of the opened outgoing socket
Definition IpSocket.cpp:63
virtual void shutdown()
shutdown the socket
Definition IpSocket.cpp:128
virtual SocketIpStatus openProtocol(NATIVE_INT_TYPE &fd)=0
Protocol specific open implementation, called from open.
SocketIpStatus open()
open the IP socket for communications
Definition IpSocket.cpp:142
virtual SocketIpStatus startup()
startup the socket, a no-op on unless this is server
Definition IpSocket.cpp:135
void unLock()
unlock the mutex
Definition Mutex.cpp:13
void lock()
lock the mutex
Definition Mutex.cpp:12
SocketIpStatus
Status enumeration for socket return values.
Definition IpSocket.hpp:23
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition IpSocket.hpp:27
@ SOCK_SUCCESS
Socket operation successful.
Definition IpSocket.hpp:24
@ SOCK_DISCONNECTED
Failed to read socket with disconnect.
Definition IpSocket.hpp:32
@ SOCK_READ_ERROR
Failed to read socket.
Definition IpSocket.hpp:31
@ SOCK_FAILED_TO_SET_SOCKET_OPTIONS
Failed to configure socket.
Definition IpSocket.hpp:29
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition IpSocket.hpp:30
@ SOCK_SEND_ERROR
Failed to send after configured retries.
Definition IpSocket.hpp:36
char * string_copy(char *destination, const char *source, U32 num)
copy string with null-termination guaranteed