F´ Flight Software - C/C++ Documentation  NASA-v1.6.0
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 <Fw/Types/BasicTypes.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) {
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_open = false;
103  m_lock.lock();
104  is_open = m_open;
105  m_lock.unLock();
106  return is_open;
107 }
108 
110  m_lock.lock();
111  if (this->m_fd != -1) {
112  (void)::shutdown(this->m_fd, SHUT_RDWR);
113  (void)::close(this->m_fd);
114  this->m_fd = -1;
115  }
116  m_open = false;
117  m_lock.unLock();
118 }
119 
121  NATIVE_INT_TYPE fd = -1;
122  SocketIpStatus status = SOCK_SUCCESS;
123  FW_ASSERT(m_fd == -1 and not m_open); // Ensure we are not opening an opened socket
124  // Open a TCP socket for incoming commands, and outgoing data if not using UDP
125  status = this->openProtocol(fd);
126  if (status != SOCK_SUCCESS) {
127  FW_ASSERT(m_fd == -1); // Ensure we properly kept closed on error
128  return status;
129  }
130  // Lock to update values and "officially open"
131  m_lock.lock();
132  m_fd = fd;
133  m_open = true;
134  m_lock.unLock();
135  return status;
136 }
137 
138 SocketIpStatus IpSocket::send(const U8* const data, const U32 size) {
139  U32 total = 0;
140  I32 sent = 0;
141  // Prevent transmission before connection, or after a disconnect
142  if (this->m_fd == -1) {
143  return SOCK_DISCONNECTED;
144  }
145  // Attempt to send out data and retry as necessary
146  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
147  // Send using my specific protocol
148  sent = this->sendProtocol(data + total, size - total);
149  // Error is EINTR or timeout just try again
150  if (((sent == -1) && (errno == EINTR)) || (sent == 0)) {
151  continue;
152  }
153  // Error bad file descriptor is a close along with reset
154  else if ((sent == -1) && ((errno == EBADF) || (errno == ECONNRESET))) {
155  this->close();
156  return SOCK_DISCONNECTED;
157  }
158  // Error returned, and it wasn't an interrupt nor a disconnect
159  else if (sent == -1) {
160  return SOCK_SEND_ERROR;
161  }
162  FW_ASSERT(sent > 0, sent);
163  total += sent;
164  }
165  // Failed to retry enough to send all data
166  if (total < size) {
168  }
169  FW_ASSERT(total == size, total, size); // Ensure we sent everything
170  return SOCK_SUCCESS;
171 }
172 
173 SocketIpStatus IpSocket::recv(U8* data, I32& req_read) {
174  I32 size = 0;
175  // Check for previously disconnected socket
176  if (m_fd == -1) {
177  return SOCK_DISCONNECTED;
178  }
179 
180  // Try to read until we fail to receive data
181  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (size <= 0); i++) {
182  // Attempt to recv out data
183  size = this->recvProtocol(data, req_read);
184  // Error is EINTR, just try again
185  if (size == -1 && ((errno == EINTR) || errno == EAGAIN)) {
186  continue;
187  }
188  // Zero bytes read reset or bad ef means we've disconnected
189  else if (size == 0 || ((size == -1) && ((errno == ECONNRESET) || (errno == EBADF)))) {
190  this->close();
191  req_read = size;
192  return SOCK_DISCONNECTED;
193  }
194  // Error returned, and it wasn't an interrupt, nor a disconnect
195  else if (size == -1) {
196  req_read = size;
197  return SOCK_READ_ERROR; // Stop recv task on error
198  }
199  }
200  req_read = size;
201  // Prevent interrupted socket being viewed as success
202  if (size == -1) {
204  }
205  return SOCK_SUCCESS;
206 }
207 
208 } // namespace Drv
Drv::IpSocket::m_timeoutSeconds
U32 m_timeoutSeconds
Definition: IpSocket.hpp:178
Drv::SOCK_INTERRUPTED_TRY_AGAIN
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition: IpSocket.hpp:30
Drv::IpSocket::close
void close()
closes the socket
Definition: IpSocket.cpp:109
Drv::SOCK_FAILED_TO_SET_SOCKET_OPTIONS
@ SOCK_FAILED_TO_SET_SOCKET_OPTIONS
Failed to configure socket.
Definition: IpSocket.hpp:29
Drv::IpSocket::configure
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
Drv::IpSocket::openProtocol
virtual SocketIpStatus openProtocol(NATIVE_INT_TYPE &fd)=0
Protocol specific open implementation, called from open.
SOCKET_MAX_ITERATIONS
@ SOCKET_MAX_ITERATIONS
Definition: IpCfg.hpp:21
Drv::IpSocket::setupTimeouts
SocketIpStatus setupTimeouts(NATIVE_INT_TYPE socketFd)
setup the socket timeout properties of the opened outgoing socket
Definition: IpSocket.cpp:63
U8
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.hpp:73
Drv::IpSocket::sendProtocol
virtual I32 sendProtocol(const U8 *const data, const U32 size)=0
Protocol specific implementation of send. Called directly with retry from send.
Drv
Definition: BlockDriver.hpp:11
Drv::IpSocket::m_hostname
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition: IpSocket.hpp:182
StringUtils.hpp
Drv::IpSocket::m_lock
Os::Mutex m_lock
Definition: IpSocket.hpp:176
Drv::IpSocket::isOpened
bool isOpened()
check if IP socket has previously been opened
Definition: IpSocket.cpp:101
Drv::IpSocket::IpSocket
IpSocket()
Definition: IpSocket.cpp:49
Drv::IpSocket::m_timeoutMicroseconds
U32 m_timeoutMicroseconds
Definition: IpSocket.hpp:179
Drv::IpSocket::recvProtocol
virtual I32 recvProtocol(U8 *const data, const U32 size)=0
Protocol specific implementation of recv. Called directly with error handling from recv.
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:27
Drv::SOCK_INVALID_IP_ADDRESS
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition: IpSocket.hpp:27
Os::Mutex::lock
void lock()
lock the mutex
Definition: Mutex.cpp:12
Fw::StringUtils::string_copy
char * string_copy(char *destination, const char *source, U32 num)
copy string with null-termination guaranteed
Definition: StringUtils.cpp:5
Drv::IpSocket::m_open
bool m_open
Have we successfully opened.
Definition: IpSocket.hpp:181
Drv::IpSocket::send
SocketIpStatus send(const U8 *const data, const U32 size)
send data out the IP socket from the given buffer
Definition: IpSocket.cpp:138
Drv::SOCK_SUCCESS
@ SOCK_SUCCESS
Socket operation successful.
Definition: IpSocket.hpp:24
Drv::SOCK_READ_ERROR
@ SOCK_READ_ERROR
Failed to read socket.
Definition: IpSocket.hpp:31
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Drv::SocketIpStatus
SocketIpStatus
Status enumeration for socket return values.
Definition: IpSocket.hpp:23
Os::Mutex::unLock
void unLock()
unlock the mutex
Definition: Mutex.cpp:13
IpSocket.hpp
Drv::IpSocket::addressToIp4
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
Drv::IpSocket::recv
SocketIpStatus recv(U8 *const data, I32 &size)
receive data from the IP socket from the given buffer
Definition: IpSocket.cpp:173
Drv::SOCK_DISCONNECTED
@ SOCK_DISCONNECTED
Failed to read socket with disconnect.
Definition: IpSocket.hpp:32
SOCKET_MAX_HOSTNAME_SIZE
@ SOCKET_MAX_HOSTNAME_SIZE
Definition: IpCfg.hpp:23
Drv::SOCK_SEND_ERROR
@ SOCK_SEND_ERROR
Failed to send after configured retries.
Definition: IpSocket.hpp:36
Drv::IpSocket::m_fd
NATIVE_INT_TYPE m_fd
Definition: IpSocket.hpp:177
Drv::IpSocket::m_port
U16 m_port
IP address port used.
Definition: IpSocket.hpp:180
Drv::IpSocket::open
SocketIpStatus open()
open the IP socket for communications
Definition: IpSocket.cpp:120
ERROR
@ ERROR
Definition: StandardTypes.hpp:16