Skip to content

Commit 65cb4c8

Browse files
Add non-blocking socket support and error handling in NUClearNetwork
This commit introduces a new function to set sockets to non-blocking mode and enhances error handling for network operations. Specifically, it throws exceptions for network errors during packet reception and sending, ensuring robust error management. The changes improve the reliability of the NUClearNetwork by preventing blocking behavior and handling potential errors gracefully.
1 parent d7b302a commit 65cb4c8

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

src/extension/network/NUClearNetwork.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,44 @@ namespace extension {
7777

7878
// Now read the data for real
7979
const ssize_t received = recvmsg(fd, &mh, 0);
80+
if (received < 0) {
81+
throw std::system_error(network_errno,
82+
std::system_category(),
83+
"Network error when receiving the packet");
84+
}
8085
payload.resize(received);
8186

8287
return {from, std::move(payload)};
8388
}
8489

90+
91+
/**
92+
* Sets a socket to non-blocking mode.
93+
*
94+
* @param fd The file descriptor of the socket to set to non-blocking.
95+
*/
96+
void set_non_blocking(const fd_t& fd) {
97+
#ifdef _WIN32
98+
u_long mode = 1;
99+
if (ioctlsocket(fd, FIONBIO, &mode) != 0) {
100+
throw std::system_error(network_errno,
101+
std::system_category(),
102+
"Unable to set the socket to non-blocking");
103+
}
104+
#else
105+
int flags = fcntl(fd, F_GETFL, 0);
106+
if (flags < 0) {
107+
throw std::system_error(network_errno, std::system_category(), "Unable to get socket flags");
108+
}
109+
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
110+
throw std::system_error(network_errno,
111+
std::system_category(),
112+
"Unable to set the socket to non-blocking");
113+
}
114+
#endif
115+
}
116+
117+
85118
} // namespace
86119

87120
NUClearNetwork::PacketQueue::PacketTarget::PacketTarget(std::weak_ptr<NetworkTarget> target,
@@ -189,6 +222,9 @@ namespace extension {
189222
throw std::system_error(network_errno, std::system_category(), "Unable to set broadcast on the socket");
190223
}
191224

225+
// Make the data socket non blocking
226+
set_non_blocking(data_fd);
227+
192228
// Bind to the address, and if we fail throw an error
193229
if (::bind(data_fd, &address.sock, address.size()) != 0) {
194230
throw std::system_error(network_errno,
@@ -1050,9 +1086,14 @@ namespace extension {
10501086
message.msg_name = const_cast<sockaddr*>(&target.sock); // NOLINT(cppcoreguidelines-pro-type-const-cast)
10511087
message.msg_namelen = target.size();
10521088

1053-
// TODO(trent): if reliable, run select first to see if this socket is writeable
1054-
// If it is not reliable just don't send the message instead of blocking
1055-
sendmsg(data_fd, &message, 0);
1089+
// send a message, if it would block then we don't care because it will be resent
1090+
if (sendmsg(data_fd, &message, 0) < 0) {
1091+
if (errno != EWOULDBLOCK && errno != EAGAIN) {
1092+
throw std::system_error(network_errno,
1093+
std::system_category(),
1094+
"Network error when sending the packet");
1095+
}
1096+
}
10561097
}
10571098

10581099

0 commit comments

Comments
 (0)