F´ Flight Software - C/C++ Documentation  NASA-v2.1.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 <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 #endif
76  return SOCK_SUCCESS;
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  NATIVE_INT_TYPE ip = inet_addr(address);
85  if (ip == ERROR) {
87  }
88  // from sin_addr, which has one struct
89  // member s_addr, which is unsigned int
90  *reinterpret_cast<unsigned long*>(ip4) = ip;
91 #else
92  // First IP address to socket sin_addr
93  if (not ::inet_pton(AF_INET, address, ip4)) {
95  };
96 #endif
97  return SOCK_SUCCESS;
98 }
99 
100 bool IpSocket::isOpened(void) {
101  bool is_open = false;
102  m_lock.lock();
103  is_open = m_open;
104  m_lock.unLock();
105  return is_open;
106 }
107 
108 void IpSocket::close(void) {
109  m_lock.lock();
110  if (this->m_fd != -1) {
111  (void)::shutdown(this->m_fd, SHUT_RDWR);
112  (void)::close(this->m_fd);
113  this->m_fd = -1;
114  }
115  m_open = false;
116  m_lock.unLock();
117 }
118 
120  NATIVE_INT_TYPE fd = -1;
121  SocketIpStatus status = SOCK_SUCCESS;
122  FW_ASSERT(m_fd == -1 and not m_open); // Ensure we are not opening an opened socket
123  // Open a TCP socket for incoming commands, and outgoing data if not using UDP
124  status = this->openProtocol(fd);
125  if (status != SOCK_SUCCESS) {
126  FW_ASSERT(m_fd == -1); // Ensure we properly kept closed on error
127  return status;
128  }
129  // Lock to update values and "officially open"
130  m_lock.lock();
131  m_fd = fd;
132  m_open = true;
133  m_lock.unLock();
134  return status;
135 }
136 
137 SocketIpStatus IpSocket::send(const U8* const data, const U32 size) {
138  U32 total = 0;
139  I32 sent = 0;
140  // Prevent transmission before connection, or after a disconnect
141  if (this->m_fd == -1) {
142  return SOCK_DISCONNECTED;
143  }
144  // Attempt to send out data and retry as necessary
145  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
146  // Send using my specific protocol
147  sent = this->sendProtocol(data + total, size - total);
148  // Error is EINTR or timeout just try again
149  if (((sent == -1) && (errno == EINTR)) || (sent == 0)) {
150  continue;
151  }
152  // Error bad file descriptor is a close along with reset
153  else if ((sent == -1) && ((errno == EBADF) || (errno == ECONNRESET))) {
154  this->close();
155  return SOCK_DISCONNECTED;
156  }
157  // Error returned, and it wasn't an interrupt nor a disconnect
158  else if (sent == -1) {
159  return SOCK_SEND_ERROR;
160  }
161  FW_ASSERT(sent > 0, sent);
162  total += sent;
163  }
164  // Failed to retry enough to send all data
165  if (total < size) {
167  }
168  FW_ASSERT(total == size, total, size); // Ensure we sent everything
169  return SOCK_SUCCESS;
170 }
171 
172 SocketIpStatus IpSocket::recv(U8* data, I32& req_read) {
173  I32 size = 0;
174  // Check for previously disconnected socket
175  if (m_fd == -1) {
176  return SOCK_DISCONNECTED;
177  }
178 
179  // Try to read until we fail to receive data
180  for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (size <= 0); i++) {
181  // Attempt to recv out data
182  size = this->recvProtocol(data, req_read);
183  // Error is EINTR, just try again
184  if (size == -1 && ((errno == EINTR) || errno == EAGAIN)) {
185  continue;
186  }
187  // Zero bytes read reset or bad ef means we've disconnected
188  else if (size == 0 || ((size == -1) && ((errno == ECONNRESET) || (errno == EBADF)))) {
189  this->close();
190  req_read = size;
191  return SOCK_DISCONNECTED;
192  }
193  // Error returned, and it wasn't an interrupt, nor a disconnect
194  else if (size == -1) {
195  req_read = size;
196  return SOCK_READ_ERROR; // Stop recv task on error
197  }
198  }
199  req_read = size;
200  // Prevent interrupted socket being viewed as success
201  if (size == -1) {
203  }
204  return SOCK_SUCCESS;
205 }
206 
207 } // namespace Drv
Drv::IpSocket::open
SocketIpStatus open(void)
open the IP socket for communications
Definition: IpSocket.cpp:119
Drv::SOCK_SUCCESS
@ SOCK_SUCCESS
Socket operation successful.
Definition: IpSocket.hpp:24
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
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:182
StringUtils.hpp
Drv::IpSocket::m_lock
Os::Mutex m_lock
Definition: IpSocket.hpp:176
Assert.hpp
Drv::IpSocket::IpSocket
IpSocket()
Definition: IpSocket.cpp:48
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.
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:137
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:172
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
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:108
Drv::IpSocket::isOpened
bool isOpened(void)
check if IP socket has previously been opened
Definition: IpSocket.cpp:100