F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
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 <string.h>
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 
18 // This implementation has primarily implemented to isolate
19 // the socket interface from the F' Fw::Buffer class.
20 // There is a macro in VxWorks (m_data) that collides with
21 // the m_data member in Fw::Buffer.
22 
23 #ifdef TGT_OS_TYPE_VXWORKS
24 #include <socket.h>
25  #include <inetLib.h>
26  #include <fioLib.h>
27  #include <hostLib.h>
28  #include <ioLib.h>
29  #include <vxWorks.h>
30  #include <sockLib.h>
31  #include <fioLib.h>
32  #include <taskLib.h>
33  #include <sysLib.h>
34  #include <errnoLib.h>
35  #include <string.h>
36 #elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
37 #include <sys/socket.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <arpa/inet.h>
41 #else
42 #error OS not supported for IP Socket Communications
43 #endif
44 
45 
46 namespace Drv {
47 
48 IpSocket::IpSocket() : m_fd(-1), m_timeoutSeconds(0), m_timeoutMicroseconds(0), m_port(0), m_open(false) {
49  ::memset(m_hostname, 0, sizeof(m_hostname));
50 }
51 
52 SocketIpStatus IpSocket::configure(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) {
53  FW_ASSERT(timeout_microseconds < 1000000, timeout_microseconds);
54  FW_ASSERT(port != 0, port);
55  this->m_timeoutSeconds = timeout_seconds;
56  this->m_timeoutMicroseconds = timeout_microseconds;
57  this->m_port = port;
59  return SOCK_SUCCESS;
60 }
61 
63 // Get the IP address from host
64 #ifdef TGT_OS_TYPE_VXWORKS
65  // No timeouts set on Vxworks
66 #else
67  // Set timeout socket option
68  struct timeval timeout;
69  timeout.tv_sec = this->m_timeoutSeconds;
70  timeout.tv_usec = this->m_timeoutMicroseconds;
71  // set socket write to timeout after 1 sec
72  if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) < 0) {
74  }
75  return SOCK_SUCCESS;
76 #endif
77 }
78 
79 SocketIpStatus IpSocket::addressToIp4(const char* address, void* ip4) {
80  FW_ASSERT(address != NULL);
81  FW_ASSERT(ip4 != NULL);
82  // Get the IP address from host
83 #ifdef TGT_OS_TYPE_VXWORKS
84  U32 ip = inet_addr(address);
85  if (ip == ERROR) {
87  }
88  *ip4 = ip;
89 #else
90  // First IP address to socket sin_addr
91  if (not ::inet_pton(AF_INET, address, ip4)) {
93  };
94 #endif
95  return SOCK_SUCCESS;
96 }
97 
98 bool IpSocket::isOpened(void) {
99  bool is_open = false;
100  m_lock.lock();
101  is_open = m_open;
102  m_lock.unLock();
103  return is_open;
104 }
105 
106 void IpSocket::close(void) {
107  m_lock.lock();
108  if (this->m_fd != -1) {
109  (void)::shutdown(this->m_fd, SHUT_RDWR);
110  (void)::close(this->m_fd);
111  this->m_fd = -1;
112  }
113  m_open = false;
114  m_lock.unLock();
115 }
116 
118  NATIVE_INT_TYPE fd = -1;
119  SocketIpStatus status = SOCK_SUCCESS;
120  FW_ASSERT(m_fd == -1 and not m_open); // Ensure we are not opening an opened socket
121  // Open a TCP socket for incoming commands, and outgoing data if not using UDP
122  status = this->openProtocol(fd);
123  if (status != SOCK_SUCCESS) {
124  FW_ASSERT(m_fd == -1); // Ensure we properly kept closed on error
125  return status;
126  }
127  // Lock to update values and "officially open"
128  m_lock.lock();
129  m_fd = fd;
130  m_open = true;
131  m_lock.unLock();
132  return status;
133 }
134 
135 SocketIpStatus IpSocket::send(const U8* const data, const U32 size) {
136  U32 total = 0;
137  I32 sent = 0;
138  // Prevent transmission before connection, or after a disconnect
139  if (this->m_fd == -1) {
140  return SOCK_DISCONNECTED;
141  }
142  // Attempt to send out data and retry as necessary
143  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
144  // Send using my specific protocol
145  sent = this->sendProtocol(data + total, size - total);
146  // Error is EINTR or timeout just try again
147  if (((sent == -1) && (errno == EINTR)) || (sent == 0)) {
148  continue;
149  }
150  // Error bad file descriptor is a close along with reset
151  else if ((sent == -1) && ((errno == EBADF) || (errno == ECONNRESET))) {
152  this->close();
153  return SOCK_DISCONNECTED;
154  }
155  // Error returned, and it wasn't an interrupt nor a disconnect
156  else if (sent == -1) {
157  return SOCK_SEND_ERROR;
158  }
159  FW_ASSERT(sent > 0, sent);
160  total += sent;
161  }
162  // Failed to retry enough to send all data
163  if (total < size) {
165  }
166  FW_ASSERT(total == size, total, size); // Ensure we sent everything
167  return SOCK_SUCCESS;
168 }
169 
170 SocketIpStatus IpSocket::recv(U8* data, I32& req_read) {
171  I32 size = 0;
172  // Check for previously disconnected socket
173  if (m_fd == -1) {
174  return SOCK_DISCONNECTED;
175  }
176 
177  // Try to read until we fail to receive data
178  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (size <= 0); i++) {
179  // Attempt to recv out data
180  size = this->recvProtocol(data, req_read);
181  // Error is EINTR, just try again
182  if (size == -1 && ((errno == EINTR) || errno == EAGAIN)) {
183  continue;
184  }
185  // Zero bytes read reset or bad ef means we've disconnected
186  else if (size == 0 || ((size == -1) && ((errno == ECONNRESET) || (errno == EBADF)))) {
187  this->close();
188  req_read = size;
189  return SOCK_DISCONNECTED;
190  }
191  // Error returned, and it wasn't an interrupt, nor a disconnect
192  else if (size == -1) {
193  req_read = size;
194  return SOCK_READ_ERROR; // Stop recv task on error
195  }
196  }
197  req_read = size;
198  // Prevent interrupted socket being viewed as success
199  if (size == -1) {
201  }
202  return SOCK_SUCCESS;
203 }
204 
205 } // namespace Drv
Drv::IpSocket::open
SocketIpStatus open(void)
open the IP socket for communications
Definition: IpSocket.cpp:117
Drv::SOCK_SUCCESS
@ SOCK_SUCCESS
Socket operation successful.
Definition: IpSocket.hpp:24
Drv::IpSocket::m_timeoutSeconds
U32 m_timeoutSeconds
Definition: IpSocket.hpp:177
Drv::SOCK_INTERRUPTED_TRY_AGAIN
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition: IpSocket.hpp:30
Os::Mutex::lock
void lock(void)
lock the mutex
Definition: Mutex.cpp:12
Os::Mutex::unLock
void unLock(void)
unlock the mutex
Definition: Mutex.cpp:13
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:52
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:62
U8
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.hpp:76
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: BlockDriverImpl.cpp:5
Drv::SOCK_INVALID_IP_ADDRESS
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition: IpSocket.hpp:27
Drv::IpSocket::m_hostname
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition: IpSocket.hpp:181
StringUtils.hpp
Drv::IpSocket::m_lock
Os::Mutex m_lock
Definition: IpSocket.hpp:175
Assert.hpp
Drv::IpSocket::IpSocket
IpSocket()
Definition: IpSocket.cpp:48
Drv::IpSocket::m_timeoutMicroseconds
U32 m_timeoutMicroseconds
Definition: IpSocket.hpp:178
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.
Fw::StringUtils::string_copy
char * string_copy(char *destination, const char *source, U32 num)
copy string with null-termination guaranteed
Definition: StringUtils.cpp:4
Drv::IpSocket::m_open
bool m_open
Have we successfully opened.
Definition: IpSocket.hpp:180
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:135
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Drv::SocketIpStatus
SocketIpStatus
Status enumeration for socket return values.
Definition: IpSocket.hpp:23
IpSocket.hpp
BasicTypes.hpp
Declares ISF basic types.
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:79
Drv::SOCK_READ_ERROR
@ SOCK_READ_ERROR
Failed to read socket.
Definition: IpSocket.hpp:31
Drv::IpSocket::recv
SocketIpStatus recv(U8 *const data, I32 &size)
receive data from the IP socket from the given buffer
Definition: IpSocket.cpp:170
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:176
Drv::IpSocket::m_port
U16 m_port
IP address port used.
Definition: IpSocket.hpp:179
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:29
NULL
#define NULL
NULL.
Definition: BasicTypes.hpp:100
Drv::IpSocket::close
void close(void)
closes the socket
Definition: IpSocket.cpp:106
Drv::IpSocket::isOpened
bool isOpened(void)
check if IP socket has previously been opened
Definition: IpSocket.cpp:98