F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
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 
18 namespace 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) {
45  this->m_open = OpenState::OPENING;
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 {
61  this->m_open = OpenState::NOT_OPEN;
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 
92 SocketIpStatus 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);
118  this->getSocketHandler().shutdown(this->m_descriptor);
119 }
120 
122  Os::ScopeLock scopedLock(this->m_lock);
123  this->getSocketHandler().close(this->m_descriptor);
124  this->m_descriptor.fd = -1;
125  this->m_open = OpenState::NOT_OPEN;
126 }
127 
129  return m_task.join();
130 }
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 
148  SocketIpStatus status = SOCK_SUCCESS;
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 
164  SocketIpStatus status = SOCK_SUCCESS;
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 
203 void SocketComponentHelper::readTask(void* pointer) {
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 IpSocket & getSocketHandler()=0
returns a reference to the socket handler
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
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