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 FwTaskPriorityType priority,
26  const Os::Task::ParamType stack,
27  const Os::Task::ParamType cpuAffinity) {
29  Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
30  this->m_stop = false;
31  // Note: the first step is for the IP socket to open the port
32  Os::Task::Arguments arguments(name, SocketComponentHelper::readTask, this, priority, stack, cpuAffinity);
33  Os::Task::Status stat = m_task.start(arguments);
34  FW_ASSERT(Os::Task::OP_OK == stat, static_cast<FwAssertArgType>(stat));
35 }
36 
39  OpenState local_open = OpenState::OPEN;
40  // Scope to guard lock
41  {
42  Os::ScopeLock scopeLock(m_lock);
43  if (this->m_open == OpenState::NOT_OPEN) {
44  this->m_open = OpenState::OPENING;
45  local_open = this->m_open;
46  } else {
47  local_open = OpenState::SKIP;
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  FW_ASSERT_NO_OVERFLOW(buffer.getSize(), U32);
199  U32 size = static_cast<U32>(buffer.getSize());
200  // recv blocks, so it may have been a while since its done an isOpened check
201  status = this->recv(data, size);
202  if ((status != SOCK_SUCCESS) && (status != SOCK_INTERRUPTED_TRY_AGAIN) &&
203  (status != SOCK_NO_DATA_AVAILABLE)) {
204  Fw::Logger::log("[WARNING] Failed to recv from port with status %d and errno %d\n", status, 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:194
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
virtual 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:132
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
void setSize(FwSizeType size)
Definition: Buffer.cpp:75
State getState()
get the task&#39;s state
Definition: Task.cpp:76
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:56
void start(const Fw::StringBase &name, const FwTaskPriorityType priority=Os::Task::TASK_PRIORITY_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
void setAutomaticOpen(bool auto_open)
set socket to automatically open connections when true, or not when false
int fd
Used for all sockets to track the communication file descriptor.
Definition: IpSocket.hpp:22
Status start(const Arguments &arguments) override
start the task
Definition: Task.cpp:84
SocketIpStatus recv(const SocketDescriptor &fd, U8 *const data, U32 &size)
receive data from the IP socket from the given buffer
Definition: IpSocket.cpp:167
virtual Fw::Buffer getBuffer()=0
returns a buffer to fill with data
Another thread is opening.
Definition: IpSocket.hpp:46
void shutdown(const SocketDescriptor &socketDescriptor)
shutdown the socket
Definition: IpSocket.cpp:111
void unlock()
alias for unLock to meet BasicLockable requirements
Definition: Mutex.hpp:64
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:40
Status join() override
block until the task has ended
Definition: Task.cpp:136
void close()
close the socket communications
virtual void connected()=0
called when the IPv4 system has been connected
PlatformTaskPriorityType FwTaskPriorityType
The type of task priorities used.
virtual IpSocket & getSocketHandler()=0
returns a reference to the socket handler
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
FwSizeType ParamType
backwards-compatible parameter type
Definition: Task.hpp:222
FwSizeType getSize() const
Definition: Buffer.cpp:60
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.
void close(const SocketDescriptor &socketDescriptor)
closes the socket
Definition: IpSocket.cpp:107
locks a mutex within the current scope
Definition: Mutex.hpp:80
#define FW_ASSERT_NO_OVERFLOW(value, T)
Definition: Assert.hpp:49
static const Fw::TimeInterval SOCKET_RETRY_INTERVAL
Definition: IpCfg.hpp:24
virtual void readLoop()
receive off the TCP socket
SocketIpStatus open(SocketDescriptor &socketDescriptor)
open the IP socket for communications
Definition: IpSocket.cpp:120
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
bool running()
is the read loop running
void lock()
lock the mutex and assert success
Definition: Mutex.cpp:34