F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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