Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UDP does not bind on send only port. Fixes: #3127 #3143

Open
wants to merge 10 commits into
base: devel
Choose a base branch
from
3 changes: 2 additions & 1 deletion Drv/Ip/IpSocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
SOCK_NOT_STARTED = -14, //!< Socket has not been started
SOCK_FAILED_TO_READ_BACK_PORT = -15, //!< Failed to read back port from connection
SOCK_NO_DATA_AVAILABLE = -16, //!< No data available or read operation would block
SOCK_ANOTHER_THREAD_OPENING = -17 //!< Another thread is opening
SOCK_ANOTHER_THREAD_OPENING = -17, //!< Another thread is opening
SOCK_AUTOCONNECT_DISABLED = -18 //!< Automatic connections are disabled

Check warning on line 47 in Drv/Ip/IpSocket.hpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`AUTOCONNECT` is not a recognized word. (unrecognized-spelling)
};

/**
Expand Down
37 changes: 28 additions & 9 deletions Drv/Ip/SocketComponentHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
const Os::Task::ParamType cpuAffinity) {
FW_ASSERT(m_task.getState() == Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
this->m_stop = false;
m_reconnect = reconnect;
this->setAutoconnect(reconnect);

Check warning on line 31 in Drv/Ip/SocketComponentHelper.cpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`Autoconnect` is not a recognized word. (unrecognized-spelling)
// Note: the first step is for the IP socket to open the port
Os::Task::Arguments arguments(name, SocketComponentHelper::readTask, this, priority, stack, cpuAffinity);
Os::Task::Status stat = m_task.start(arguments);
Expand Down Expand Up @@ -77,13 +77,28 @@
return is_open;
}

void SocketComponentHelper::setAutoConnect(bool auto_connect) {
Fixed Show fixed Hide fixed
Os::ScopeLock scopedLock(this->m_lock);
this->m_reconnect = auto_connect;
Fixed Show fixed Hide fixed
}

SocketIpStatus SocketComponentHelper::reconnect() {
LeStarch marked this conversation as resolved.
Show resolved Hide resolved
SocketIpStatus status = SOCK_SUCCESS;
// Open a network connection if it has not already been open
if (not this->isOpened()) {
status = this->open();
if (status == SocketIpStatus::SOCK_ANOTHER_THREAD_OPENING) {
status = SocketIpStatus::SOCK_SUCCESS;
// Check for autoconnect before attempting to reconnect

Check warning on line 88 in Drv/Ip/SocketComponentHelper.cpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`autoconnect` is not a recognized word. (unrecognized-spelling)
bool reconnect = false;
Fixed Show fixed Hide fixed
{
Os::ScopeLock scopedLock(this->m_lock);
reconnect = this->m_reconnect;
}
// Open a network connection if it has not already been open
if (not reconnect) {
status = SOCK_AUTOCONNECT_DISABLED;

Check warning on line 96 in Drv/Ip/SocketComponentHelper.cpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`AUTOCONNECT` is not a recognized word. (unrecognized-spelling)
} else {
status = this->open();
if (status == SocketIpStatus::SOCK_ANOTHER_THREAD_OPENING) {
status = SocketIpStatus::SOCK_SUCCESS;
}
}
}
return status;
Expand Down Expand Up @@ -166,7 +181,12 @@
// Prevent transmission before connection, or after a disconnect
if ((not this->isOpened()) and this->running()) {
status = this->reconnect();
if (status != SOCK_SUCCESS) {
// When reconnect is disabled, just break as this is a exit condition for the loop
LeStarch marked this conversation as resolved.
Show resolved Hide resolved
if (status == SOCK_AUTOCONNECT_DISABLED) {

Check warning on line 185 in Drv/Ip/SocketComponentHelper.cpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`AUTOCONNECT` is not a recognized word. (unrecognized-spelling)
break;
}
// If the reconnection failed in any other way, warn, wait, and retry
else if (status != SOCK_SUCCESS) {
Fw::Logger::log("[WARNING] Failed to open port with status %d and errno %d\n", status, errno);
(void)Os::Task::delay(SOCKET_RETRY_INTERVAL);
continue;
Expand All @@ -193,9 +213,8 @@
this->sendBuffer(buffer, status);
}
}
// As long as not told to stop, and we are successful interrupted or ordered to retry, keep receiving
while (this->running() &&
(status == SOCK_SUCCESS || (status == SOCK_NO_DATA_AVAILABLE) || status == SOCK_INTERRUPTED_TRY_AGAIN || this->m_reconnect));
LeStarch marked this conversation as resolved.
Show resolved Hide resolved
// This will loop until stopped. If autoconnect is disabled, this will break at the moment of reconnect

Check warning on line 216 in Drv/Ip/SocketComponentHelper.cpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`autoconnect` is not a recognized word. (unrecognized-spelling)
while (this->running());
Dismissed Show dismissed Hide dismissed
// Close the socket
this->close(); // Close the port entirely
}
Expand Down
14 changes: 12 additions & 2 deletions Drv/Ip/SocketComponentHelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
* to the Os::Task::start call.
*
* \param name: name of the task
* \param reconnect: automatically reconnect socket when closed. Default: true.
* \param reconnect: automatically (re)connect socket when closed. Default: true.
* \param priority: priority of the started task. See: Os::Task::start. Default: TASK_DEFAULT, not prioritized
* \param stack: stack size provided to the task. See: Os::Task::start. Default: TASK_DEFAULT, posix threads default
* \param cpuAffinity: cpu affinity provided to task. See: Os::Task::start. Default: TASK_DEFAULT, don't care
Expand Down Expand Up @@ -85,6 +85,16 @@
*/
bool isOpened();

/**
* \brief set the socket to automatically connect or reconnect
*
* Set the autoconnect flag to automatically connect or reconnect the socket when it is closed. This is useful for

Check warning on line 91 in Drv/Ip/SocketComponentHelper.hpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`autoconnect` is not a recognized word. (unrecognized-spelling)
* allowing the socket to reconnect when a disconnection event happens
*
* \param auto_connect: true to automatically connect, false otherwise
*/
void setAutoConnect(bool auto_connect);

/**
* \brief Re-open port if it has been disconnected
*
Expand Down Expand Up @@ -212,7 +222,7 @@
Os::Task m_task;
Os::Mutex m_lock;
SocketDescriptor m_descriptor;
bool m_reconnect = false; //!< Force reconnection
bool m_reconnect = true; //!< Force reconnection
Fixed Show fixed Hide fixed
bool m_stop = true; //!< Stops the task when set to true
OpenState m_open = OpenState::NOT_OPEN; //!< Have we successfully opened
};
Expand Down
28 changes: 20 additions & 8 deletions Drv/Ip/UdpSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,35 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
memcpy(&this->m_state->m_addr_send, &address, sizeof(this->m_state->m_addr_send));
}

// When we are setting up for receiving as well, then we must bind to a port
if ((status = this->bind(socketFd)) != SOCK_SUCCESS) {
::close(socketFd);
return status; // Not closing FD as it is still a valid send FD
}
// Receive port set up only done when configure receive was called
U16 recv_port = this->m_recv_port;
if (recv_port != 0) {
status = this->bind(socketFd);
// When we are setting up for receiving as well, then we must bind to a port
if (status != SOCK_SUCCESS) {
(void) ::close(socketFd); // Closing FD as a retry will reopen send side
return status;
}
}

// Log message for UDP
if (port == 0) {
Fw::Logger::log("Setup to receive udp at %s:%hu\n", m_recv_hostname,
if ((port == 0) && (recv_port > 0)) {
Fw::Logger::log("Setup to only receive udp at %s:%hu\n", m_recv_hostname,
recv_port);
} else {
} else if ((port > 0) && (recv_port == 0)) {
Fw::Logger::log("Setup to only send udp at %s:%hu\n", m_hostname,
port);
} else if ((port > 0) && (recv_port > 0)) {
Fw::Logger::log("Setup to receive udp at %s:%hu and send to %s:%hu\n",
m_recv_hostname,
recv_port,
m_hostname,
port);
}
// Neither configuration method was called
else {
FW_ASSERT(port > 0 || recv_port > 0, port, recv_port);
LeStarch marked this conversation as resolved.
Show resolved Hide resolved
}
FW_ASSERT(status == SOCK_SUCCESS, status);
socketDescriptor.fd = socketFd;
return status;
Expand Down
Loading