F´ Flight Software - C/C++ Documentation
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, crsmith
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_timeoutSeconds(0), m_timeoutMicroseconds(0), m_port(0) {
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, static_cast<FwAssertArgType>(timeout_microseconds));
55 FW_ASSERT(this->isValidPort(port), static_cast<FwAssertArgType>(port));
56 FW_ASSERT(hostname != nullptr);
57 this->m_timeoutSeconds = timeout_seconds;
58 this->m_timeoutMicroseconds = timeout_microseconds;
59 this->m_port = port;
61 return SOCK_SUCCESS;
62}
63
64bool IpSocket::isValidPort(U16 port) {
65 return true;
66}
67
69// Get the IP address from host
70#ifdef TGT_OS_TYPE_VXWORKS
71 // No timeouts set on Vxworks
72#else
73 // Set timeout socket option
74 struct timeval timeout;
75 timeout.tv_sec = static_cast<time_t>(this->m_timeoutSeconds);
76 timeout.tv_usec = static_cast<suseconds_t>(this->m_timeoutMicroseconds);
77 // set socket write to timeout after 1 sec
78 if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout)) < 0) {
80 }
81#endif
82 return SOCK_SUCCESS;
83}
84
85SocketIpStatus IpSocket::addressToIp4(const char* address, void* ip4) {
86 FW_ASSERT(address != nullptr);
87 FW_ASSERT(ip4 != nullptr);
88 // Get the IP address from host
89#ifdef TGT_OS_TYPE_VXWORKS
90 NATIVE_INT_TYPE ip = inet_addr(address);
91 if (ip == ERROR) {
93 }
94 // from sin_addr, which has one struct
95 // member s_addr, which is unsigned int
96 *reinterpret_cast<unsigned long*>(ip4) = ip;
97#else
98 // First IP address to socket sin_addr
99 if (not ::inet_pton(AF_INET, address, ip4)) {
101 };
102#endif
103 return SOCK_SUCCESS;
104}
105
106void IpSocket::close(const SocketDescriptor& socketDescriptor) {
107 (void)::close(socketDescriptor.fd);
108}
109
110void IpSocket::shutdown(const SocketDescriptor& socketDescriptor) {
111 errno = 0;
112 PlatformIntType status = ::shutdown(socketDescriptor.fd, SHUT_RDWR);
113 // If shutdown fails, go straight to the hard-shutdown
114 if (status != 0) {
115 this->close(socketDescriptor);
116 }
117}
118
121 errno = 0;
122 // Open a TCP socket for incoming commands, and outgoing data if not using UDP
123 status = this->openProtocol(socketDescriptor);
124 if (status != SOCK_SUCCESS) {
125 socketDescriptor.fd = -1;
126 return status;
127 }
128 return status;
129}
130
131SocketIpStatus IpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
132 U32 total = 0;
133 I32 sent = 0;
134 // Attempt to send out data and retry as necessary
135 for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
136 errno = 0;
137 // Send using my specific protocol
138 sent = this->sendProtocol(socketDescriptor, data + total, size - total);
139 // Error is EINTR or timeout just try again
140 if (((sent == -1) && (errno == EINTR)) || (sent == 0)) {
141 continue;
142 }
143 // Error bad file descriptor is a close along with reset
144 else if ((sent == -1) && ((errno == EBADF) || (errno == ECONNRESET))) {
145 return SOCK_DISCONNECTED;
146 }
147 // Error returned, and it wasn't an interrupt nor a disconnect
148 else if (sent == -1) {
149 return SOCK_SEND_ERROR;
150 }
151 FW_ASSERT(sent > 0, sent);
152 total += static_cast<U32>(sent);
153 }
154 // Failed to retry enough to send all data
155 if (total < size) {
157 }
158 // Ensure we sent everything
159 FW_ASSERT(total == size, static_cast<FwAssertArgType>(total), static_cast<FwAssertArgType>(size));
160 return SOCK_SUCCESS;
161}
162
163SocketIpStatus IpSocket::recv(const SocketDescriptor& socketDescriptor, U8* data, U32& req_read) {
164 I32 size = 0;
165 // Try to read until we fail to receive data
166 for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (size <= 0); i++) {
167 errno = 0;
168 // Attempt to recv out data
169 size = this->recvProtocol(socketDescriptor, data, req_read);
170
171 // Nothing to be received
172 if ((size == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
173 req_read = 0;
175 }
176
177 // Error is EINTR, just try again
178 if ((size == -1) && (errno == EINTR)) {
179 continue;
180 }
181 // Zero bytes read reset or bad ef means we've disconnected
182 else if (size == 0 || ((size == -1) && ((errno == ECONNRESET) || (errno == EBADF)))) {
183 req_read = static_cast<U32>(size);
184 return SOCK_DISCONNECTED;
185 }
186 // Error returned, and it wasn't an interrupt, nor a disconnect
187 else if (size == -1) {
188 req_read = static_cast<U32>(size);
189 return SOCK_READ_ERROR; // Stop recv task on error
190 }
191 }
192 req_read = static_cast<U32>(size);
193 // Prevent interrupted socket being viewed as success
194 if (size == -1) {
196 }
197 return SOCK_SUCCESS;
198}
199
200} // namespace Drv
#define FW_ASSERT(...)
Definition Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:55
uint8_t U8
8-bit unsigned integer
Definition BasicTypes.h:30
int PlatformIntType
DefaultTypes.hpp provides fallback defaults for the platform types.
PlatformAssertArgType FwAssertArgType
Definition FpConfig.h:39
PlatformSizeType FwSizeType
Definition FpConfig.h:35
C++-compatible configuration header for fprime configuration.
@ SOCKET_MAX_HOSTNAME_SIZE
Definition IpCfg.hpp:22
@ SOCKET_MAX_ITERATIONS
Definition IpCfg.hpp:21
U16 m_port
IP address port used.
Definition IpSocket.hpp:210
virtual SocketIpStatus openProtocol(SocketDescriptor &fd)=0
Protocol specific open implementation, called from open.
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition IpSocket.hpp:211
SocketIpStatus setupTimeouts(PlatformIntType socketFd)
setup the socket timeout properties of the opened outgoing socket
Definition IpSocket.cpp:68
SocketIpStatus open(SocketDescriptor &socketDescriptor)
open the IP socket for communications
Definition IpSocket.cpp:119
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
virtual I32 sendProtocol(const SocketDescriptor &socketDescriptor, const U8 *const data, const U32 size)=0
Protocol specific implementation of send. Called directly with retry from send.
U32 m_timeoutMicroseconds
Definition IpSocket.hpp:209
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:85
virtual bool isValidPort(U16 port)
Check if the given port is valid for the socket.
Definition IpSocket.cpp:64
virtual I32 recvProtocol(const SocketDescriptor &socketDescriptor, U8 *const data, const U32 size)=0
Protocol specific implementation of recv. Called directly with error handling from recv.
SocketIpStatus send(const SocketDescriptor &socketDescriptor, const U8 *const data, const U32 size)
send data out the IP socket from the given buffer
Definition IpSocket.cpp:131
void shutdown(const SocketDescriptor &socketDescriptor)
shutdown the socket
Definition IpSocket.cpp:110
SocketIpStatus recv(const SocketDescriptor &fd, U8 *const data, U32 &size)
receive data from the IP socket from the given buffer
Definition IpSocket.cpp:163
void close(const SocketDescriptor &socketDescriptor)
closes the socket
Definition IpSocket.cpp:106
SocketIpStatus
Status enumeration for socket return values.
Definition IpSocket.hpp:29
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition IpSocket.hpp:33
@ SOCK_SUCCESS
Socket operation successful.
Definition IpSocket.hpp:30
@ SOCK_DISCONNECTED
Failed to read socket with disconnect.
Definition IpSocket.hpp:38
@ SOCK_READ_ERROR
Failed to read socket.
Definition IpSocket.hpp:37
@ SOCK_FAILED_TO_SET_SOCKET_OPTIONS
Failed to configure socket.
Definition IpSocket.hpp:35
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition IpSocket.hpp:36
@ SOCK_SEND_ERROR
Failed to send after configured retries.
Definition IpSocket.hpp:42
@ SOCK_NO_DATA_AVAILABLE
No data available or read operation would block.
Definition IpSocket.hpp:45
char * string_copy(char *destination, const char *source, FwSizeType num)
copy string with null-termination guaranteed
PlatformIntType fd
Used for all sockets to track the communication file descriptor.
Definition IpSocket.hpp:22