F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
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 <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