F´ Flight Software - C/C++ Documentation
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 Os::Task::ParamType priority,
26  const Os::Task::ParamType stack,
27  const Os::Task::ParamType cpuAffinity) {
28  FW_ASSERT(m_task.getState() == Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
29  this->m_stop = false;
30  // Note: the first step is for the IP socket to open the port
31  Os::Task::Arguments arguments(name, SocketComponentHelper::readTask, this, priority, stack, cpuAffinity);
32  Os::Task::Status stat = m_task.start(arguments);
33  FW_ASSERT(Os::Task::OP_OK == stat, static_cast<FwAssertArgType>(stat));
34 }
35 
38  OpenState local_open = OpenState::OPEN;
39  // Scope to guard lock
40  {
41  Os::ScopeLock scopeLock(m_lock);
42  if (this->m_open == OpenState::NOT_OPEN) {
43  this->m_open = OpenState::OPENING;
44  local_open = this->m_open;
45  } else {
46  local_open = OpenState::SKIP;
47  }
48 
49  }
50  if (local_open == OpenState::OPENING) {
51  FW_ASSERT(this->m_descriptor.fd == -1); // Ensure we are not opening an opened socket
52  status = this->getSocketHandler().open(this->m_descriptor);
53  // Lock scope
54  {
55  Os::ScopeLock scopeLock(m_lock);
56  if (Drv::SOCK_SUCCESS == status) {
57  this->m_open = OpenState::OPEN;
58  } else {
59  this->m_open = OpenState::NOT_OPEN;
60  this->m_descriptor.fd = -1;
61  }
62  }
63  // Notify connection on success outside locked scope
64  if (Drv::SOCK_SUCCESS == status) {
65  this->connected();
66  }
67  }
68 
69  return status;
70 }
71 
73  Os::ScopeLock scopedLock(this->m_lock);
74  bool is_open = this->m_open == OpenState::OPEN;
75  return is_open;
76 }
77 
79  Os::ScopeLock scopedLock(this->m_lock);
80  this->m_reopen = auto_open;
81 }
82 
83 SocketIpStatus SocketComponentHelper::reopen() {
85  if (not this->isOpened()) {
86  // Check for auto-open before attempting to reopen
87  bool reopen = false;
88  {
89  Os::ScopeLock scopedLock(this->m_lock);
90  reopen = this->m_reopen;
91  }
92  // Open a network connection if it has not already been open
93  if (not reopen) {
95  } else {
96  status = this->open();
99  }
100  }
101  }
102  return status;
103 }
104 
105 SocketIpStatus SocketComponentHelper::send(const U8* const data, const U32 size) {
106  SocketIpStatus status = SOCK_SUCCESS;
107  this->m_lock.lock();
108  SocketDescriptor descriptor = this->m_descriptor;
109  this->m_lock.unlock();
110  // Prevent transmission before connection, or after a disconnect
111  if (descriptor.fd == -1) {
112  status = this->reopen();
113  // if reopen wasn't successful, pass the that up to the caller
114  if(status != SOCK_SUCCESS) {
115  return status;
116  }
117  // Refresh local copy after reopen
118  this->m_lock.lock();
119  descriptor = this->m_descriptor;
120  this->m_lock.unlock();
121  }
122  status = this->getSocketHandler().send(descriptor, data, size);
123  if (status == SOCK_DISCONNECTED) {
124  this->close();
125  }
126  return status;
127 }
128 
130  Os::ScopeLock scopedLock(this->m_lock);
131  this->getSocketHandler().shutdown(this->m_descriptor);
132 }
133 
135  Os::ScopeLock scopedLock(this->m_lock);
136  this->getSocketHandler().close(this->m_descriptor);
137  this->m_descriptor.fd = -1;
138  this->m_open = OpenState::NOT_OPEN;
139 }
140 
142  return m_task.join();
143 }
144 
146  // Scope to protect lock
147  {
148  Os::ScopeLock scopeLock(m_lock);
149  this->m_stop = true;
150  }
151  this->shutdown(); // Break out of any receives and fully shutdown
152 }
153 
155  Os::ScopeLock scopedLock(this->m_lock);
156  bool running = not this->m_stop;
157  return running;
158 }
159 
161  SocketIpStatus status = SOCK_SUCCESS;
162  // Check for previously disconnected socket
163  this->m_lock.lock();
164  SocketDescriptor descriptor = this->m_descriptor;
165  this->m_lock.unlock();
166  if (descriptor.fd == -1) {
167  return SOCK_DISCONNECTED;
168  }
169  status = this->getSocketHandler().recv(descriptor, data, size);
170  if (status == SOCK_DISCONNECTED) {
171  this->close();
172  }
173  return status;
174 }
175 
177  SocketIpStatus status = SOCK_SUCCESS;
178  do {
179  // Prevent transmission before connection, or after a disconnect
180  if ((not this->isOpened()) and this->running()) {
181  status = this->reopen();
182  // When reopen is disabled, just break as this is a exit condition for the loop
183  if (status == SOCK_AUTO_CONNECT_DISABLED) {
184  break;
185  }
186  // If the reconnection failed in any other way, warn, wait, and retry
187  else if (status != SOCK_SUCCESS) {
188  Fw::Logger::log("[WARNING] Failed to open port with status %d and errno %d\n", status, errno);
190  continue;
191  }
192  }
193  // If the network connection is open, read from it
194  if (this->isOpened() and this->running()) {
195  Fw::Buffer buffer = this->getBuffer();
196  U8* data = buffer.getData();
197  FW_ASSERT(data);
198  U32 size = buffer.getSize();
199  // recv blocks, so it may have been a while since its done an isOpened check
200  status = this->recv(data, size);
201  if ((status != SOCK_SUCCESS) && (status != SOCK_INTERRUPTED_TRY_AGAIN) && (status != SOCK_NO_DATA_AVAILABLE)) {
202  Fw::Logger::log("[WARNING] Failed to recv from port with status %d and errno %d\n",
203  status,
204  errno);
205  this->close();
206  buffer.setSize(0);
207  } else {
208  // Send out received data
209  buffer.setSize(size);
210  }
211  this->sendBuffer(buffer, status);
212  }
213  }
214  // This will loop until stopped. If auto-open is disabled, this will break when reopen returns disabled status
215  while (this->running());
216  // Close the socket
217  this->close(); // Close the port entirely
218 }
219 
220 void SocketComponentHelper::readTask(void* pointer) {
221  FW_ASSERT(pointer);
222  SocketComponentHelper* self = reinterpret_cast<SocketComponentHelper*>(pointer);
223  self->readLoop();
224 }
225 } // namespace Drv
SocketComponentHelper()
constructs the socket read task
static Status delay(Fw::TimeInterval interval)
delay the current task
Definition: Task.cpp:191
bool m_reopen
Force reopen on disconnect.
bool m_stop
Stops the task when set to true.
Failed to read socket with disconnect.
Definition: IpSocket.hpp:38
void shutdown()
shutdown the socket communications
Interrupted status for retries.
Definition: IpSocket.hpp:36
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
SocketIpStatus send(const U8 *const data, const U32 size)
send data to the IP socket from the given buffer
bool isOpened()
check if IP socket has previously been opened
State getState()
get the task&#39;s state
Definition: Task.cpp:74
static void log(const char *format,...)
log a formated string with supplied arguments
Definition: Logger.cpp:21
Automatic connections are disabled.
Definition: IpSocket.hpp:47
U8 * getData() const
Definition: Buffer.cpp:68
void setAutomaticOpen(bool auto_open)
set socket to automatically open connections when true, or not when false
Status start(const Arguments &arguments) override
start the task
Definition: Task.cpp:82
SocketIpStatus recv(const SocketDescriptor &fd, U8 *const data, U32 &size)
receive data from the IP socket from the given buffer
Definition: IpSocket.cpp:163
virtual Fw::Buffer getBuffer()=0
returns a buffer to fill with data
U32 getSize() const
Definition: Buffer.cpp:72
Another thread is opening.
Definition: IpSocket.hpp:46
void shutdown(const SocketDescriptor &socketDescriptor)
shutdown the socket
Definition: IpSocket.cpp:110
void unlock()
alias for unLock to meet BasicLockable requirements
Definition: Mutex.hpp:63
supports a task to read a given socket adaptation
OpenState m_open
Have we successfully opened.
Socket operation successful.
Definition: IpSocket.hpp:30
message sent/received okay
Definition: Task.hpp:30
void setSize(U32 size)
Definition: Buffer.cpp:87
Status join() override
block until the task has ended
Definition: Task.cpp:134
void close()
close the socket communications
virtual void connected()=0
called when the IPv4 system has been connected
virtual IpSocket & getSocketHandler()=0
returns a reference to the socket handler
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
FwSizeType ParamType
backwards-compatible parameter type
Definition: Task.hpp:219
SocketIpStatus recv(U8 *data, U32 &size)
receive data from the IP socket from the given buffer
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
void stop()
stop the socket read task and close the associated socket.
PlatformIntType fd
Used for all sockets to track the communication file descriptor.
Definition: IpSocket.hpp:22
void close(const SocketDescriptor &socketDescriptor)
closes the socket
Definition: IpSocket.cpp:106
locks a mutex within the current scope
Definition: Mutex.hpp:79
virtual void readLoop()
receive off the TCP socket
SocketIpStatus open(SocketDescriptor &socketDescriptor)
open the IP socket for communications
Definition: IpSocket.cpp:119
Os::Task::Status join()
joins to the stopping read task to wait for it to close
SocketIpStatus
Status enumeration for socket return values.
Definition: IpSocket.hpp:29
SocketIpStatus open()
open the socket for communications
No data available or read operation would block.
Definition: IpSocket.hpp:45
virtual void sendBuffer(Fw::Buffer buffer, SocketIpStatus status)=0
sends a buffer to be filled with data
#define FW_ASSERT(...)
Definition: Assert.hpp:14
void start(const Fw::StringBase &name, 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 running()
is the read loop running
void lock()
lock the mutex and assert success
Definition: Mutex.cpp:34
static const Fw::TimeInterval SOCKET_RETRY_INTERVAL
Definition: IpCfg.hpp:24