F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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 <FpConfig.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
47namespace Drv {
48
49IpSocket::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
53SocketIpStatus 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
80SocketIpStatus 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;
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
138SocketIpStatus 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
173SocketIpStatus 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
#define FW_ASSERT(...)
Definition Assert.hpp:7
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition BasicTypes.h:26
C++-compatible configuration header for fprime configuration.
@ SOCKET_MAX_HOSTNAME_SIZE
Definition IpCfg.hpp:23
@ SOCKET_MAX_ITERATIONS
Definition IpCfg.hpp:21
virtual I32 sendProtocol(const U8 *const data, const U32 size)=0
Protocol specific implementation of send. Called directly with retry from send.
void close()
closes the socket
Definition IpSocket.cpp:109
U16 m_port
IP address port used.
Definition IpSocket.hpp:180
virtual I32 recvProtocol(U8 *const data, const U32 size)=0
Protocol specific implementation of recv. Called directly with error handling from recv.
bool isOpened()
check if IP socket has previously been opened
Definition IpSocket.cpp:101
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition IpSocket.hpp:182
SocketIpStatus recv(U8 *const data, I32 &size)
receive data from the IP socket from the given buffer
Definition IpSocket.cpp:173
bool m_open
Have we successfully opened.
Definition IpSocket.hpp:181
SocketIpStatus send(const U8 *const data, const U32 size)
send data out the IP socket from the given buffer
Definition IpSocket.cpp:138
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
U32 m_timeoutMicroseconds
Definition IpSocket.hpp:179
Os::Mutex m_lock
Definition IpSocket.hpp:176
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
NATIVE_INT_TYPE m_fd
Definition IpSocket.hpp:177
SocketIpStatus setupTimeouts(NATIVE_INT_TYPE socketFd)
setup the socket timeout properties of the opened outgoing socket
Definition IpSocket.cpp:63
virtual SocketIpStatus openProtocol(NATIVE_INT_TYPE &fd)=0
Protocol specific open implementation, called from open.
SocketIpStatus open()
open the IP socket for communications
Definition IpSocket.cpp:120
void unLock()
unlock the mutex
Definition Mutex.cpp:13
void lock()
lock the mutex
Definition Mutex.cpp:12
SocketIpStatus
Status enumeration for socket return values.
Definition IpSocket.hpp:23
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition IpSocket.hpp:27
@ SOCK_SUCCESS
Socket operation successful.
Definition IpSocket.hpp:24
@ SOCK_DISCONNECTED
Failed to read socket with disconnect.
Definition IpSocket.hpp:32
@ SOCK_READ_ERROR
Failed to read socket.
Definition IpSocket.hpp:31
@ SOCK_FAILED_TO_SET_SOCKET_OPTIONS
Failed to configure socket.
Definition IpSocket.hpp:29
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition IpSocket.hpp:30
@ SOCK_SEND_ERROR
Failed to send after configured retries.
Definition IpSocket.hpp:36
char * string_copy(char *destination, const char *source, U32 num)
copy string with null-termination guaranteed