This is an automated email from the ASF dual-hosted git repository.
chenBright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git
The following commit(s) were added to refs/heads/master by this push:
new 853fa6be fix: set socket buffer options before connect (#3368)
853fa6be is described below
commit 853fa6bede7d34ca950f7f6166ca9a5ae206f0c2
Author: sunhao <[email protected]>
AuthorDate: Sat Jul 18 16:50:30 2026 +0800
fix: set socket buffer options before connect (#3368)
---
src/brpc/server.cpp | 6 +-
src/brpc/socket.cpp | 36 +++++++-----
src/brpc/socket.h | 3 +
src/butil/endpoint.cpp | 10 +++-
src/butil/endpoint.h | 4 ++
test/brpc_socket_unittest.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++
6 files changed, 173 insertions(+), 19 deletions(-)
diff --git a/src/brpc/server.cpp b/src/brpc/server.cpp
index 6e1f9e88..99ecab8a 100644
--- a/src/brpc/server.cpp
+++ b/src/brpc/server.cpp
@@ -1124,7 +1124,8 @@ int Server::StartInternal(const butil::EndPoint& endpoint,
_listen_addr = endpoint;
for (int port = port_range.min_port; port <= port_range.max_port; ++port) {
_listen_addr.port = port;
- butil::fd_guard sockfd(tcp_listen(_listen_addr));
+ butil::fd_guard sockfd(tcp_listen(_listen_addr,
+ SetSocketBufferOptions));
if (sockfd < 0) {
if (port != port_range.max_port) { // not the last port, try next
continue;
@@ -1192,7 +1193,8 @@ int Server::StartInternal(const butil::EndPoint& endpoint,
butil::EndPoint internal_point = _listen_addr;
internal_point.port = _options.internal_port;
- butil::fd_guard sockfd(tcp_listen(internal_point));
+ butil::fd_guard sockfd(tcp_listen(internal_point,
+ SetSocketBufferOptions));
if (sockfd < 0) {
LOG(ERROR) << "Fail to listen " << internal_point << " (internal)";
return -1;
diff --git a/src/brpc/socket.cpp b/src/brpc/socket.cpp
index 1154ea49..95a7c6f4 100644
--- a/src/brpc/socket.cpp
+++ b/src/brpc/socket.cpp
@@ -628,22 +628,6 @@ void Socket::SetSocketOptions(int fd) {
PLOG(ERROR) << "Fail to set tos of fd=" << fd << " to " << _tos;
}
- if (FLAGS_socket_send_buffer_size > 0) {
- int buff_size = FLAGS_socket_send_buffer_size;
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buff_size,
sizeof(buff_size)) != 0) {
- PLOG(ERROR) << "Fail to set sndbuf of fd=" << fd << " to "
- << buff_size;
- }
- }
-
- if (FLAGS_socket_recv_buffer_size > 0) {
- int buff_size = FLAGS_socket_recv_buffer_size;
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buff_size,
sizeof(buff_size)) != 0) {
- PLOG(ERROR) << "Fail to set rcvbuf of fd=" << fd << " to "
- << buff_size;
- }
- }
-
#if defined(OS_LINUX)
if (_tcp_user_timeout_ms > 0) {
if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,
@@ -714,6 +698,24 @@ void Socket::SetSocketOptions(int fd) {
#endif
}
+void SetSocketBufferOptions(int fd) {
+ if (FLAGS_socket_send_buffer_size > 0) {
+ int buff_size = FLAGS_socket_send_buffer_size;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buff_size,
sizeof(buff_size)) != 0) {
+ PLOG(ERROR) << "Fail to set sndbuf of fd=" << fd << " to "
+ << buff_size;
+ }
+ }
+
+ if (FLAGS_socket_recv_buffer_size > 0) {
+ int buff_size = FLAGS_socket_recv_buffer_size;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buff_size,
sizeof(buff_size)) != 0) {
+ PLOG(ERROR) << "Fail to set rcvbuf of fd=" << fd << " to "
+ << buff_size;
+ }
+ }
+}
+
// SocketId = 32-bit version + 32-bit slot.
// version: from version part of _versioned_nref, must be an EVEN number.
// slot: designated by ResourcePool.
@@ -1275,6 +1277,8 @@ int Socket::Connect(const timespec* abstime,
CHECK_EQ(0, butil::make_close_on_exec(sockfd));
// We need to do async connect (to manage the timeout by ourselves).
CHECK_EQ(0, butil::make_non_blocking(sockfd));
+ // Socket buffer sizes need to be set before connect.
+ brpc::SetSocketBufferOptions(sockfd);
if (!_device_name.empty()) {
#ifdef SO_BINDTODEVICE
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
diff --git a/src/brpc/socket.h b/src/brpc/socket.h
index e4713d86..ca83b921 100644
--- a/src/brpc/socket.h
+++ b/src/brpc/socket.h
@@ -68,6 +68,9 @@ class EventDispatcher;
class Stream;
class Transport;
+// Set SO_SNDBUF/SO_RCVBUF according to socket_*_buffer_size flags.
+void SetSocketBufferOptions(int fd);
+
// A special closure for processing the about-to-recycle socket. Socket does
// not delete SocketUser, if you want, `delete this' at the end of
// BeforeRecycle().
diff --git a/src/butil/endpoint.cpp b/src/butil/endpoint.cpp
index c5a888b8..371b418d 100644
--- a/src/butil/endpoint.cpp
+++ b/src/butil/endpoint.cpp
@@ -561,7 +561,7 @@ int tcp_connect(const EndPoint& server, int* self_port, int
connect_timeout_ms)
return sockfd.release();
}
-int tcp_listen(EndPoint point) {
+int tcp_listen(EndPoint point, BeforeListenCallback before_listen) {
struct sockaddr_storage serv_addr;
socklen_t serv_addr_size = 0;
if (endpoint2sockaddr(point, &serv_addr, &serv_addr_size) != 0) {
@@ -602,6 +602,10 @@ int tcp_listen(EndPoint point) {
::unlink(((sockaddr_un*) &serv_addr)->sun_path);
}
+ if (before_listen) {
+ before_listen(sockfd);
+ }
+
if (::bind(sockfd, (struct sockaddr*)& serv_addr, serv_addr_size) != 0) {
return -1;
}
@@ -614,6 +618,10 @@ int tcp_listen(EndPoint point) {
return sockfd.release();
}
+int tcp_listen(EndPoint point) {
+ return tcp_listen(point, BeforeListenCallback());
+}
+
int get_local_side(int fd, EndPoint *out) {
struct sockaddr_storage addr;
socklen_t socklen = sizeof(addr);
diff --git a/src/butil/endpoint.h b/src/butil/endpoint.h
index c6d00bbb..265a241f 100644
--- a/src/butil/endpoint.h
+++ b/src/butil/endpoint.h
@@ -24,6 +24,7 @@
#include <netinet/in.h> // in_addr
#include <sys/un.h> // sockaddr_un
+#include <functional> // std::function
#include <iostream> // std::ostream
#include "butil/containers/hash_tables.h" // hashing functions
@@ -141,6 +142,9 @@ int tcp_connect(const EndPoint& server, int* self_port, int
connect_timeout_ms);
// To enable SO_REUSEPORT for the whole program, enable gflag -reuse_port
// Returns the socket descriptor, -1 otherwise and errno is set.
int tcp_listen(EndPoint ip_and_port);
+// If `before_listen' is set, it will be called before bind/listen.
+typedef std::function<void(int)> BeforeListenCallback;
+int tcp_listen(EndPoint ip_and_port, BeforeListenCallback before_listen);
// Get the local end of a socket connection
int get_local_side(int fd, EndPoint *out);
diff --git a/test/brpc_socket_unittest.cpp b/test/brpc_socket_unittest.cpp
index a283ffcf..34ba03bc 100644
--- a/test/brpc_socket_unittest.cpp
+++ b/test/brpc_socket_unittest.cpp
@@ -39,6 +39,7 @@
#include "brpc/policy/most_common_message.h"
#include "brpc/policy/http_rpc_protocol.h"
#include "brpc/server.h"
+#include "brpc/details/server_private_accessor.h"
#include "brpc/channel.h"
#include "brpc/controller.h"
#include "health_check.pb.h"
@@ -59,6 +60,8 @@ DECLARE_bool(socket_keepalive);
DECLARE_int32(socket_keepalive_idle_s);
DECLARE_int32(socket_keepalive_interval_s);
DECLARE_int32(socket_keepalive_count);
+DECLARE_int32(socket_recv_buffer_size);
+DECLARE_int32(socket_send_buffer_size);
DECLARE_int32(socket_tcp_user_timeout_ms);
}
@@ -1123,6 +1126,45 @@ void CheckKeepalive(int fd,
ASSERT_EQ(expected_keepalive_count, keepalive_count);
}
+struct SocketBufferValues {
+ int recv_buffer;
+ int send_buffer;
+
+ SocketBufferValues() : recv_buffer(0), send_buffer(0) {}
+};
+
+void GetSocketBufferValues(int fd, SocketBufferValues* values) {
+ socklen_t len = sizeof(values->recv_buffer);
+ ASSERT_EQ(0, getsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+ &values->recv_buffer, &len));
+ len = sizeof(values->send_buffer);
+ ASSERT_EQ(0, getsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+ &values->send_buffer, &len));
+}
+
+void GetExpectedSocketBufferValues(int buffer_size,
+ SocketBufferValues* expected) {
+ SocketBufferValues default_values;
+ butil::fd_guard default_fd(socket(AF_INET, SOCK_STREAM, 0));
+ ASSERT_GT(default_fd, 0);
+ GetSocketBufferValues(default_fd, &default_values);
+
+ butil::fd_guard reference_fd(socket(AF_INET, SOCK_STREAM, 0));
+ ASSERT_GT(reference_fd, 0);
+ ASSERT_EQ(0, setsockopt(reference_fd, SOL_SOCKET, SO_RCVBUF, &buffer_size,
+ sizeof(buffer_size)));
+ ASSERT_EQ(0, setsockopt(reference_fd, SOL_SOCKET, SO_SNDBUF, &buffer_size,
+ sizeof(buffer_size)));
+ GetSocketBufferValues(reference_fd, expected);
+}
+
+void CheckSocketBufferValues(int fd, const SocketBufferValues& expected) {
+ SocketBufferValues actual;
+ GetSocketBufferValues(fd, &actual);
+ ASSERT_EQ(expected.recv_buffer, actual.recv_buffer);
+ ASSERT_EQ(expected.send_buffer, actual.send_buffer);
+}
+
TEST_F(SocketTest, keepalive) {
int default_keepalive = 0;
int default_keepalive_idle = 0;
@@ -1425,6 +1467,97 @@ TEST_F(SocketTest, keepalive_input_message) {
ASSERT_EQ(EBADF, errno);
}
+TEST_F(SocketTest, socket_buffer_options_before_connect) {
+ gflags::FlagSaver flag_saver;
+ const int buffer_size = 256 * 1024;
+ brpc::FLAGS_socket_recv_buffer_size = buffer_size;
+ brpc::FLAGS_socket_send_buffer_size = buffer_size;
+
+ SocketBufferValues expected;
+ GetExpectedSocketBufferValues(buffer_size, &expected);
+
+ butil::EndPoint point;
+ ASSERT_EQ(0, str2endpoint("127.0.0.1:0", &point));
+ butil::fd_guard listening_fd(tcp_listen(point));
+ ASSERT_GT(listening_fd, 0) << berror();
+ ASSERT_EQ(0, butil::get_local_side(listening_fd, &point));
+
+ brpc::SocketOptions options;
+ options.remote_side = point;
+ brpc::SocketId id = brpc::INVALID_SOCKET_ID;
+ ASSERT_EQ(0, brpc::Socket::Create(options, &id));
+
+ brpc::SocketUniquePtr ptr;
+ ASSERT_EQ(0, brpc::Socket::Address(id, &ptr)) << "id=" << id;
+
+ const timespec duetime = butil::milliseconds_from_now(1000);
+ butil::fd_guard connected_fd(ptr->Connect(&duetime, NULL, NULL));
+ ASSERT_GT(connected_fd, 0);
+ CheckSocketBufferValues(connected_fd, expected);
+
+ ASSERT_EQ(0, ptr->SetFailed());
+}
+
+TEST_F(SocketTest, socket_buffer_options_before_accept) {
+ gflags::FlagSaver flag_saver;
+ const int buffer_size = 256 * 1024;
+ brpc::FLAGS_socket_recv_buffer_size = buffer_size;
+ brpc::FLAGS_socket_send_buffer_size = buffer_size;
+
+ SocketBufferValues expected;
+ GetExpectedSocketBufferValues(buffer_size, &expected);
+
+ butil::EndPoint point;
+ ASSERT_EQ(0, str2endpoint("127.0.0.1:0", &point));
+ brpc::Server server;
+ ASSERT_EQ(0, server.Start(point, NULL));
+ point = server.listen_address();
+
+ brpc::Acceptor* messenger =
+ brpc::ServerPrivateAccessor(&server).acceptor();
+ ASSERT_TRUE(messenger != NULL);
+ ASSERT_GT(messenger->listened_fd(), 0);
+ CheckSocketBufferValues(messenger->listened_fd(), expected);
+
+ // Accepted sockets should inherit the listener's buffer sizes, not use
+ // the flags at accept time.
+ brpc::FLAGS_socket_recv_buffer_size = buffer_size / 2;
+ brpc::FLAGS_socket_send_buffer_size = buffer_size / 2;
+
+ brpc::SocketOptions options;
+ options.remote_side = point;
+ options.connect_on_create = true;
+ brpc::SocketId id = brpc::INVALID_SOCKET_ID;
+ ASSERT_EQ(0, brpc::Socket::Create(options, &id));
+
+ const int64_t start_time = butil::cpuwide_time_us();
+ while (messenger->ConnectionCount() < 1) {
+ bthread_usleep(1000);
+ ASSERT_LT(butil::cpuwide_time_us(), start_time + 1000000L)
+ << "Too long!";
+ }
+
+ std::vector<brpc::SocketId> connections;
+ messenger->ListConnections(&connections);
+ ASSERT_EQ(1ul, connections.size());
+
+ {
+ brpc::SocketUniquePtr accepted_socket;
+ ASSERT_EQ(0, brpc::Socket::Address(connections[0], &accepted_socket));
+ ASSERT_GT(accepted_socket->fd(), 0);
+ CheckSocketBufferValues(accepted_socket->fd(), expected);
+ ASSERT_EQ(0, accepted_socket->SetFailed());
+ }
+
+ {
+ brpc::SocketUniquePtr client_socket;
+ ASSERT_EQ(0, brpc::Socket::Address(id, &client_socket));
+ ASSERT_EQ(0, client_socket->SetFailed());
+ }
+ server.Stop(0);
+ server.Join();
+}
+
#if defined(OS_LINUX)
void CheckTCPUserTimeout(int fd, int expect_tcp_user_timeout) {
int tcp_user_timeout = 0;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]