F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
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>
16 #include <Fw/Types/StringUtils.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 
47 namespace Drv {
48 
49 IpSocket::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 
53 SocketIpStatus 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 
80 SocketIpStatus 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;
144  SocketIpStatus status = SOCK_SUCCESS;
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 
160 SocketIpStatus 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 
195 SocketIpStatus 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
U32 m_timeoutSeconds
Definition: IpSocket.hpp:205
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
Definition: StringUtils.cpp:5