From d30d77e890d2c6c7eaa2c31dc7c9517ce0fcb7c9 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 10 Jul 2026 09:11:40 +0200 Subject: [PATCH 1/5] Use tcp_nodelay on socket server The sockets we use in this library should be optimized for real-time communication, not for throughput. Therefore, they should use tcp_nodelay by default. --- src/comm/tcp_server.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/comm/tcp_server.cpp b/src/comm/tcp_server.cpp index 3bb5559d5..3fe2c3c57 100644 --- a/src/comm/tcp_server.cpp +++ b/src/comm/tcp_server.cpp @@ -26,6 +26,7 @@ */ //---------------------------------------------------------------------- +#include #include #include @@ -73,6 +74,8 @@ void TCPServer::init() #endif ur_setsockopt(listen_fd_, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(int)); + ur_setsockopt(listen_fd_, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); + URCL_LOG_DEBUG("Created socket with FD %d", (int)listen_fd_); FD_ZERO(&masterfds_); From dbe5e74030cf509bac8d70371929ed2ad5d3434c Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 10 Jul 2026 09:12:54 +0200 Subject: [PATCH 2/5] Use win32 include guards --- src/comm/tcp_server.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/comm/tcp_server.cpp b/src/comm/tcp_server.cpp index 3fe2c3c57..e16ea0bf0 100644 --- a/src/comm/tcp_server.cpp +++ b/src/comm/tcp_server.cpp @@ -26,7 +26,9 @@ */ //---------------------------------------------------------------------- -#include +#ifndef _WIN32 +# include +#endif #include #include From 95c24acf9bf6a4058c3a0b83b7aa80b23cf183e9 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 10 Jul 2026 09:16:08 +0200 Subject: [PATCH 3/5] Set TCP_NODELAY on the accepted socket, not on the listen socket --- src/comm/tcp_server.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/comm/tcp_server.cpp b/src/comm/tcp_server.cpp index e16ea0bf0..e5cd84e0a 100644 --- a/src/comm/tcp_server.cpp +++ b/src/comm/tcp_server.cpp @@ -76,8 +76,6 @@ void TCPServer::init() #endif ur_setsockopt(listen_fd_, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(int)); - ur_setsockopt(listen_fd_, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); - URCL_LOG_DEBUG("Created socket with FD %d", (int)listen_fd_); FD_ZERO(&masterfds_); @@ -262,6 +260,10 @@ void TCPServer::handleConnect() ur_close(client_fd); } } + + int flag = 1; + ur_setsockopt(client_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); + { std::lock_guard lk(callback_mutex_); if (new_connection_callback_ && accepted) From c73d2733a833cb3191b910181a6dad8004a7b3eb Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 10 Jul 2026 10:58:07 +0200 Subject: [PATCH 4/5] Check return value of setsockopt and guard by accepted=true --- include/ur_client_library/comm/socket_t.h | 13 +++++++++++++ src/comm/tcp_server.cpp | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/ur_client_library/comm/socket_t.h b/include/ur_client_library/comm/socket_t.h index 8a7d61f7d..67e2b024b 100644 --- a/include/ur_client_library/comm/socket_t.h +++ b/include/ur_client_library/comm/socket_t.h @@ -71,6 +71,8 @@ typedef int socket_t; # define MSG_NOSIGNAL 0 #endif +#include "ur_client_library/log.h" + /*! * \brief Get the last socket error as an std::error_code * @@ -92,3 +94,14 @@ inline std::system_error makeSocketError(const std::string& message) { return std::system_error(getLastSocketErrorCode(), message); } + +inline void setSocketOptionAndWarnOnError(socket_t socket, int level, int optname, const void* optval, + unsigned int optlen, const std::string& option_name) +{ + int result = ur_setsockopt(socket, level, optname, optval, optlen); + if (result != 0) + { + std::error_code error_code = getLastSocketErrorCode(); + URCL_LOG_WARN("Failed to set socket option %s: %s", option_name.c_str(), error_code.message().c_str()); + } +} diff --git a/src/comm/tcp_server.cpp b/src/comm/tcp_server.cpp index e5cd84e0a..890f90e81 100644 --- a/src/comm/tcp_server.cpp +++ b/src/comm/tcp_server.cpp @@ -261,8 +261,11 @@ void TCPServer::handleConnect() } } - int flag = 1; - ur_setsockopt(client_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); + if (accepted) + { + constexpr int flag = 1; + setSocketOptionAndWarnOnError(client_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag), "TCP_NODELAY"); + } { std::lock_guard lk(callback_mutex_); From 21bab872535f72a89b303e61b7dfb70b65130def Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 10 Jul 2026 11:04:07 +0200 Subject: [PATCH 5/5] Use setSocketOptionAndWarnOnError instead of ur_setsockopt directly --- src/comm/tcp_server.cpp | 6 +++--- src/comm/tcp_socket.cpp | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/comm/tcp_server.cpp b/src/comm/tcp_server.cpp index 890f90e81..f67b84727 100644 --- a/src/comm/tcp_server.cpp +++ b/src/comm/tcp_server.cpp @@ -70,11 +70,11 @@ void TCPServer::init() { throw makeSocketError("Failed to create socket endpoint"); } - int flag = 1; + constexpr int flag = 1; #ifndef _WIN32 - ur_setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); + setSocketOptionAndWarnOnError(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag), "SO_REUSEADDR"); #endif - ur_setsockopt(listen_fd_, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(int)); + setSocketOptionAndWarnOnError(listen_fd_, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag), "SO_KEEPALIVE"); URCL_LOG_DEBUG("Created socket with FD %d", (int)listen_fd_); diff --git a/src/comm/tcp_socket.cpp b/src/comm/tcp_socket.cpp index 6af840e0d..96e3a4dae 100644 --- a/src/comm/tcp_socket.cpp +++ b/src/comm/tcp_socket.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "ur_client_library/comm/socket_t.h" #ifndef _WIN32 # include @@ -52,12 +53,12 @@ TCPSocket::~TCPSocket() void TCPSocket::setupOptions() { - int flag = 1; - ur_setsockopt(socket_fd_, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); + constexpr int flag = 1; + setSocketOptionAndWarnOnError(socket_fd_, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag), "TCP_NODELAY"); // macOS does not have TCP_QUICKACK #ifdef TCP_QUICKACK - ur_setsockopt(socket_fd_, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(int)); + setSocketOptionAndWarnOnError(socket_fd_, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(flag), "TCP_QUICKACK"); #endif if (recv_timeout_ != nullptr) @@ -65,9 +66,10 @@ void TCPSocket::setupOptions() #ifdef _WIN32 DWORD value = recv_timeout_->tv_sec * 1000; value += recv_timeout_->tv_usec / 1000; - ur_setsockopt(socket_fd_, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); + setSocketOptionAndWarnOnError(socket_fd_, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value), "SO_RCVTIMEO"); #else - ur_setsockopt(socket_fd_, SOL_SOCKET, SO_RCVTIMEO, recv_timeout_.get(), sizeof(timeval)); + setSocketOptionAndWarnOnError(socket_fd_, SOL_SOCKET, SO_RCVTIMEO, recv_timeout_.get(), sizeof(timeval), + "SO_RCVTIMEO"); #endif } }