F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
SocketComponentHelper.cpp
Go to the documentation of this file.
1// ======================================================================
2// \title SocketComponentHelper.cpp
3// \author mstarch, crsmith
4// \brief cpp file for SocketComponentHelper implementation class
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
14#include <Fw/Logger/Logger.hpp>
15#include <Fw/Types/Assert.hpp>
16#include <cerrno>
17
18namespace Drv {
19
21
23
25 const bool reconnect,
26 const Os::Task::ParamType priority,
27 const Os::Task::ParamType stack,
28 const Os::Task::ParamType cpuAffinity) {
29 FW_ASSERT(m_task.getState() == Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
30 this->m_stop = false;
32 // Note: the first step is for the IP socket to open the port
33 Os::Task::Arguments arguments(name, SocketComponentHelper::readTask, this, priority, stack, cpuAffinity);
34 Os::Task::Status stat = m_task.start(arguments);
35 FW_ASSERT(Os::Task::OP_OK == stat, static_cast<FwAssertArgType>(stat));
36}
37
40 OpenState local_open = OpenState::OPEN;
41 // Scope to guard lock
42 {
43 Os::ScopeLock scopeLock(m_lock);
44 if (this->m_open == OpenState::NOT_OPEN) {
46 local_open = this->m_open;
47 } else {
48 local_open = OpenState::SKIP;
49 }
50
51 }
52 if (local_open == OpenState::OPENING) {
53 FW_ASSERT(this->m_descriptor.fd == -1); // Ensure we are not opening an opened socket
54 status = this->getSocketHandler().open(this->m_descriptor);
55 // Lock scope
56 {
57 Os::ScopeLock scopeLock(m_lock);
58 if (Drv::SOCK_SUCCESS == status) {
59 this->m_open = OpenState::OPEN;
60 } else {
62 this->m_descriptor.fd = -1;
63 }
64 }
65 // Notify connection on success outside locked scope
66 if (Drv::SOCK_SUCCESS == status) {
67 this->connected();
68 }
69 }
70
71 return status;
72}
73
75 Os::ScopeLock scopedLock(this->m_lock);
76 bool is_open = this->m_open == OpenState::OPEN;
77 return is_open;
78}
79
82 // Open a network connection if it has not already been open
83 if (not this->isOpened()) {
84 status = this->open();
87 }
88 }
89 return status;
90}
91
92SocketIpStatus SocketComponentHelper::send(const U8* const data, const U32 size) {
94 this->m_lock.lock();
95 SocketDescriptor descriptor = this->m_descriptor;
96 this->m_lock.unlock();
97 // Prevent transmission before connection, or after a disconnect
98 if (descriptor.fd == -1) {
99 status = this->reconnect();
100 // if reconnect wasn't successful, pass the that up to the caller
101 if(status != SOCK_SUCCESS) {
102 return status;
103 }
104 // Refresh local copy after reconnect
105 this->m_lock.lock();
106 descriptor = this->m_descriptor;
107 this->m_lock.unlock();
108 }
109 status = this->getSocketHandler().send(descriptor, data, size);
110 if (status == SOCK_DISCONNECTED) {
111 this->close();
112 }
113 return status;
114}
115
117 Os::ScopeLock scopedLock(this->m_lock);
119}
120
122 Os::ScopeLock scopedLock(this->m_lock);
123 this->getSocketHandler().close(this->m_descriptor);
124 this->m_descriptor.fd = -1;
126}
127
131
133 // Scope to protect lock
134 {
135 Os::ScopeLock scopeLock(m_lock);
136 this->m_stop = true;
137 }
138 this->shutdown(); // Break out of any receives and fully shutdown
139}
140
142 Os::ScopeLock scopedLock(this->m_lock);
143 bool running = not this->m_stop;
144 return running;
145}
146
149 // Check for previously disconnected socket
150 this->m_lock.lock();
151 SocketDescriptor descriptor = this->m_descriptor;
152 this->m_lock.unlock();
153 if (descriptor.fd == -1) {
154 return SOCK_DISCONNECTED;
155 }
156 status = this->getSocketHandler().recv(descriptor, data, size);
157 if (status == SOCK_DISCONNECTED) {
158 this->close();
159 }
160 return status;
161}
162
165 do {
166 // Prevent transmission before connection, or after a disconnect
167 if ((not this->isOpened()) and this->running()) {
168 status = this->reconnect();
169 if (status != SOCK_SUCCESS) {
170 Fw::Logger::log("[WARNING] Failed to open port with status %d and errno %d\n", status, errno);
172 continue;
173 }
174 }
175 // If the network connection is open, read from it
176 if (this->isOpened() and this->running()) {
177 Fw::Buffer buffer = this->getBuffer();
178 U8* data = buffer.getData();
179 FW_ASSERT(data);
180 U32 size = buffer.getSize();
181 // recv blocks, so it may have been a while since its done an isOpened check
182 status = this->recv(data, size);
183 if ((status != SOCK_SUCCESS) && (status != SOCK_INTERRUPTED_TRY_AGAIN) && (status != SOCK_NO_DATA_AVAILABLE)) {
184 Fw::Logger::log("[WARNING] Failed to recv from port with status %d and errno %d\n",
185 status,
186 errno);
187 this->close();
188 buffer.setSize(0);
189 } else {
190 // Send out received data
191 buffer.setSize(size);
192 }
193 this->sendBuffer(buffer, status);
194 }
195 }
196 // As long as not told to stop, and we are successful interrupted or ordered to retry, keep receiving
197 while (this->running() &&
198 (status == SOCK_SUCCESS || (status == SOCK_NO_DATA_AVAILABLE) || status == SOCK_INTERRUPTED_TRY_AGAIN || this->m_reconnect));
199 // Close the socket
200 this->close(); // Close the port entirely
201}
202
204 FW_ASSERT(pointer);
205 SocketComponentHelper* self = reinterpret_cast<SocketComponentHelper*>(pointer);
206 self->readLoop();
207}
208} // namespace Drv
#define FW_ASSERT(...)
Definition Assert.hpp:14
uint8_t U8
8-bit unsigned integer
Definition BasicTypes.h:30
PlatformAssertArgType FwAssertArgType
Definition FpConfig.h:39
static const Fw::TimeInterval SOCKET_RETRY_INTERVAL
Definition IpCfg.hpp:24
SocketIpStatus open(SocketDescriptor &socketDescriptor)
open the IP socket for communications
Definition IpSocket.cpp:119
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
supports a task to read a given socket adaptation
virtual void sendBuffer(Fw::Buffer buffer, SocketIpStatus status)=0
sends a buffer to be filled with data
bool isOpened()
check if IP socket has previously been opened
SocketComponentHelper()
constructs the socket read task
void start(const Fw::StringBase &name, const bool reconnect=true, const Os::Task::ParamType priority=Os::Task::TASK_DEFAULT, const Os::Task::ParamType stack=Os::Task::TASK_DEFAULT, const Os::Task::ParamType cpuAffinity=Os::Task::TASK_DEFAULT)
start the socket read task to start producing data
bool m_reconnect
Force reconnection.
OpenState m_open
Have we successfully opened.
virtual Fw::Buffer getBuffer()=0
returns a buffer to fill with data
virtual void readLoop()
receive off the TCP socket
bool m_stop
Stops the task when set to true.
virtual void connected()=0
called when the IPv4 system has been connected
void close()
close the socket communications
void shutdown()
shutdown the socket communications
Os::Task::Status join()
joins to the stopping read task to wait for it to close
SocketIpStatus open()
open the socket for communications
SocketIpStatus recv(U8 *data, U32 &size)
receive data from the IP socket from the given buffer
SocketIpStatus send(const U8 *const data, const U32 size)
send data to the IP socket from the given buffer
SocketIpStatus reconnect()
Re-open port if it has been disconnected.
bool running()
is the read loop running
void stop()
stop the socket read task and close the associated socket.
virtual ~SocketComponentHelper()
destructor of the socket read task
static void readTask(void *pointer)
a task designed to read from the socket and output incoming data
virtual IpSocket & getSocketHandler()=0
returns a reference to the socket handler
U8 * getData() const
Definition Buffer.cpp:68
U32 getSize() const
Definition Buffer.cpp:72
void setSize(U32 size)
Definition Buffer.cpp:87
static void log(const char *format,...)
log a formated string with supplied arguments
Definition Logger.cpp:21
void unlock()
alias for unLock to meet BasicLockable requirements
Definition Mutex.hpp:63
void lock()
lock the mutex and assert success
Definition Mutex.cpp:34
locks a mutex within the current scope
Definition Mutex.hpp:79
static Status delay(Fw::TimeInterval interval)
delay the current task
Definition Task.cpp:191
State getState()
get the task's state
Definition Task.cpp:74
FwSizeType ParamType
backwards-compatible parameter type
Definition Task.hpp:219
Status start(const Arguments &arguments) override
start the task
Definition Task.cpp:82
Status join() override
block until the task has ended
Definition Task.cpp:134
@ OP_OK
message sent/received okay
Definition Task.hpp:30
SocketIpStatus
Status enumeration for socket return values.
Definition IpSocket.hpp:29
@ SOCK_SUCCESS
Socket operation successful.
Definition IpSocket.hpp:30
@ SOCK_ANOTHER_THREAD_OPENING
Another thread is opening.
Definition IpSocket.hpp:46
@ SOCK_DISCONNECTED
Failed to read socket with disconnect.
Definition IpSocket.hpp:38
@ SOCK_INTERRUPTED_TRY_AGAIN
Interrupted status for retries.
Definition IpSocket.hpp:36
@ SOCK_NO_DATA_AVAILABLE
No data available or read operation would block.
Definition IpSocket.hpp:45
PlatformIntType fd
Used for all sockets to track the communication file descriptor.
Definition IpSocket.hpp:22