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, crsmith
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_timeoutSeconds(0), m_timeoutMicroseconds(0), m_port(0) {
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, static_cast<FwAssertArgType>(timeout_microseconds));
55  FW_ASSERT(this->isValidPort(port), static_cast<FwAssertArgType>(port));
56  FW_ASSERT(hostname != nullptr);
57  this->m_timeoutSeconds = timeout_seconds;
58  this->m_timeoutMicroseconds = timeout_microseconds;
59  this->m_port = port;
60  (void) Fw::StringUtils::string_copy(this->m_hostname, hostname, static_cast<FwSizeType>(SOCKET_MAX_HOSTNAME_SIZE));
61  return SOCK_SUCCESS;
62 }
63 
64 bool IpSocket::isValidPort(U16 port) {
65  return true;
66 }
67 
69 // Get the IP address from host
70 #ifdef TGT_OS_TYPE_VXWORKS
71  // No timeouts set on Vxworks
72 #else
73  // Set timeout socket option
74  struct timeval timeout;
75  timeout.tv_sec = static_cast<time_t>(this->m_timeoutSeconds);
76  timeout.tv_usec = static_cast<suseconds_t>(this->m_timeoutMicroseconds);
77  // set socket write to timeout after 1 sec
78  if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout)) < 0) {
80  }
81 #endif
82  return SOCK_SUCCESS;
83 }
84 
85 SocketIpStatus IpSocket::addressToIp4(const char* address, void* ip4) {
86  FW_ASSERT(address != nullptr);
87  FW_ASSERT(ip4 != nullptr);
88  // Get the IP address from host
89 #ifdef TGT_OS_TYPE_VXWORKS
90  NATIVE_INT_TYPE ip = inet_addr(address);
91  if (ip == ERROR) {
93  }
94  // from sin_addr, which has one struct
95  // member s_addr, which is unsigned int
96  *reinterpret_cast<unsigned long*>(ip4) = ip;
97 #else
98  // First IP address to socket sin_addr
99  if (not ::inet_pton(AF_INET, address, ip4)) {
101  };
102 #endif
103  return SOCK_SUCCESS;
104 }
105 
106 void IpSocket::close(const SocketDescriptor& socketDescriptor) {
107  (void)::close(socketDescriptor.fd);
108 }
109 
110 void IpSocket::shutdown(const SocketDescriptor& socketDescriptor) {
111  errno = 0;
112  PlatformIntType status = ::shutdown(socketDescriptor.fd, SHUT_RDWR);
113  // If shutdown fails, go straight to the hard-shutdown
114  if (status != 0) {
115  this->close(socketDescriptor);
116  }
117 }
118 
120  SocketIpStatus status = SOCK_SUCCESS;
121  errno = 0;
122  // Open a TCP socket for incoming commands, and outgoing data if not using UDP
123  status = this->openProtocol(socketDescriptor);
124  if (status != SOCK_SUCCESS) {
125  socketDescriptor.fd = -1;
126  return status;
127  }
128  return status;
129 }
130 
131 SocketIpStatus IpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
132  U32 total = 0;
133  I32 sent = 0;
134  // Attempt to send out data and retry as necessary
135  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
136  errno = 0;
137  // Send using my specific protocol
138  sent = this->sendProtocol(socketDescriptor, data + total, size - total);
139  // Error is EINTR or timeout just try again
140  if (((sent == -1) && (errno == EINTR)) || (sent == 0)) {
141  continue;
142  }
143  // Error bad file descriptor is a close along with reset
144  else if ((sent == -1) && ((errno == EBADF) || (errno == ECONNRESET))) {
145  return SOCK_DISCONNECTED;
146  }
147  // Error returned, and it wasn't an interrupt nor a disconnect
148  else if (sent == -1) {
149  return SOCK_SEND_ERROR;
150  }
151  FW_ASSERT(sent > 0, sent);
152  total += static_cast<U32>(sent);
153  }
154  // Failed to retry enough to send all data
155  if (total < size) {
157  }
158  // Ensure we sent everything
159  FW_ASSERT(total == size, static_cast<FwAssertArgType>(total), static_cast<FwAssertArgType>(size));
160  return SOCK_SUCCESS;
161 }
162 
163 SocketIpStatus IpSocket::recv(const SocketDescriptor& socketDescriptor, U8* data, U32& req_read) {
164  I32 size = 0;
165  // Try to read until we fail to receive data
166  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (size <= 0); i++) {
167  errno = 0;
168  // Attempt to recv out data
169  size = this->recvProtocol(socketDescriptor, data, req_read);
170 
171  // Nothing to be received
172  if ((size == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
173  req_read = 0;
174  return SOCK_NO_DATA_AVAILABLE;
175  }
176 
177  // Error is EINTR, just try again
178  if ((size == -1) && (errno == EINTR)) {
179  continue;
180  }
181  // Zero bytes read reset or bad ef means we've disconnected
182  else if (size == 0 || ((size == -1) && ((errno == ECONNRESET) || (errno == EBADF)))) {
183  req_read = static_cast<U32>(size);
184  return SOCK_DISCONNECTED;
185  }
186  // Error returned, and it wasn't an interrupt, nor a disconnect
187  else if (size == -1) {
188  req_read = static_cast<U32>(size);
189  return SOCK_READ_ERROR; // Stop recv task on error
190  }
191  }
192  req_read = static_cast<U32>(size);
193  // Prevent interrupted socket being viewed as success
194  if (size == -1) {
196  }
197  return SOCK_SUCCESS;
198 }
199 
200 } // namespace Drv
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:55
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
int PlatformIntType
DefaultTypes.hpp provides fallback defaults for the platform types.
PlatformAssertArgType FwAssertArgType
Definition: FpConfig.h:39
PlatformSizeType FwSizeType
Definition: FpConfig.h:35
C++-compatible configuration header for fprime configuration.
@ SOCKET_MAX_HOSTNAME_SIZE
Definition: IpCfg.hpp:22
@ SOCKET_MAX_ITERATIONS
Definition: IpCfg.hpp:21
U16 m_port
IP address port used.
Definition: IpSocket.hpp:210
virtual SocketIpStatus openProtocol(SocketDescriptor &fd)=0
Protocol specific open implementation, called from open.
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition: IpSocket.hpp:211
SocketIpStatus setupTimeouts(PlatformIntType socketFd)
setup the socket timeout properties of the opened outgoing socket
Definition: IpSocket.cpp:68
SocketIpStatus open(SocketDescriptor &socketDescriptor)
open the IP socket for communications
Definition: IpSocket.cpp:119
U32 m_timeoutSeconds
Definition: IpSocket.hpp:208
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
virtual I32 sendProtocol(const SocketDescriptor &socketDescriptor, const U8 *const data, const U32 size)=0
Protocol specific implementation of send. Called directly with retry from send.
U32 m_timeoutMicroseconds
Definition: IpSocket.hpp:209
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:85
virtual bool isValidPort(U16 port)
Check if the given port is valid for the socket.
Definition: IpSocket.cpp:64
virtual I32 recvProtocol(const SocketDescriptor &socketDescriptor, U8 *const data, const U32 size)=0
Protocol specific implementation of recv. Called directly with error handling from recv.
SocketIpStatus send(const SocketDescriptor &socketDescriptor, const U8 *const data, const U32 size)
send data out the IP socket from the given buffer
Definition: IpSocket.cpp:131
void shutdown(const SocketDescriptor &socketDescriptor)
shutdown the socket
Definition: IpSocket.cpp:110
SocketIpStatus recv(const SocketDescriptor &fd, U8 *const data, U32 &size)
receive data from the IP socket from the given buffer
Definition: IpSocket.cpp:163
void close(const SocketDescriptor &socketDescriptor)
closes the socket
Definition: IpSocket.cpp:106
SocketIpStatus
Status enumeration for socket return values.
Definition: IpSocket.hpp:29
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition: IpSocket.hpp:33
@ SOCK_SUCCESS
Socket operation successful.
Definition: IpSocket.hpp:30
@ SOCK_DISCONNECTED
Failed to read socket with disconnect.
Definition: IpSocket.hpp:38
@ SOCK_READ_ERROR
Failed to read socket.
Definition: IpSocket.hpp:37
@ SOCK_FAILED_TO_SET_SOCKET_OPTIONS
Failed to configure socket.
Definition: IpSocket.hpp:35
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition: IpSocket.hpp:36
@ SOCK_SEND_ERROR
Failed to send after configured retries.
Definition: IpSocket.hpp:42
@ SOCK_NO_DATA_AVAILABLE
No data available or read operation would block.
Definition: IpSocket.hpp:45
char * string_copy(char *destination, const char *source, FwSizeType num)
copy string with null-termination guaranteed
Definition: StringUtils.cpp:6
@ ERROR
Operation failed.
Definition: Os.hpp:27
PlatformIntType fd
Used for all sockets to track the communication file descriptor.
Definition: IpSocket.hpp:22