Skip to content

Commit 296e240

Browse files
committed
fix: set socket buffer options before connect
1 parent f1d04c8 commit 296e240

6 files changed

Lines changed: 173 additions & 19 deletions

File tree

src/brpc/server.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,8 @@ int Server::StartInternal(const butil::EndPoint& endpoint,
11241124
_listen_addr = endpoint;
11251125
for (int port = port_range.min_port; port <= port_range.max_port; ++port) {
11261126
_listen_addr.port = port;
1127-
butil::fd_guard sockfd(tcp_listen(_listen_addr));
1127+
butil::fd_guard sockfd(tcp_listen(_listen_addr,
1128+
SetSocketBufferOptions));
11281129
if (sockfd < 0) {
11291130
if (port != port_range.max_port) { // not the last port, try next
11301131
continue;
@@ -1192,7 +1193,8 @@ int Server::StartInternal(const butil::EndPoint& endpoint,
11921193

11931194
butil::EndPoint internal_point = _listen_addr;
11941195
internal_point.port = _options.internal_port;
1195-
butil::fd_guard sockfd(tcp_listen(internal_point));
1196+
butil::fd_guard sockfd(tcp_listen(internal_point,
1197+
SetSocketBufferOptions));
11961198
if (sockfd < 0) {
11971199
LOG(ERROR) << "Fail to listen " << internal_point << " (internal)";
11981200
return -1;

src/brpc/socket.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -624,22 +624,6 @@ void Socket::SetSocketOptions(int fd) {
624624
PLOG(ERROR) << "Fail to set tos of fd=" << fd << " to " << _tos;
625625
}
626626

627-
if (FLAGS_socket_send_buffer_size > 0) {
628-
int buff_size = FLAGS_socket_send_buffer_size;
629-
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buff_size, sizeof(buff_size)) != 0) {
630-
PLOG(ERROR) << "Fail to set sndbuf of fd=" << fd << " to "
631-
<< buff_size;
632-
}
633-
}
634-
635-
if (FLAGS_socket_recv_buffer_size > 0) {
636-
int buff_size = FLAGS_socket_recv_buffer_size;
637-
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buff_size, sizeof(buff_size)) != 0) {
638-
PLOG(ERROR) << "Fail to set rcvbuf of fd=" << fd << " to "
639-
<< buff_size;
640-
}
641-
}
642-
643627
#if defined(OS_LINUX)
644628
if (_tcp_user_timeout_ms > 0) {
645629
if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,
@@ -710,6 +694,24 @@ void Socket::SetSocketOptions(int fd) {
710694
#endif
711695
}
712696

697+
void SetSocketBufferOptions(int fd) {
698+
if (FLAGS_socket_send_buffer_size > 0) {
699+
int buff_size = FLAGS_socket_send_buffer_size;
700+
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buff_size, sizeof(buff_size)) != 0) {
701+
PLOG(ERROR) << "Fail to set sndbuf of fd=" << fd << " to "
702+
<< buff_size;
703+
}
704+
}
705+
706+
if (FLAGS_socket_recv_buffer_size > 0) {
707+
int buff_size = FLAGS_socket_recv_buffer_size;
708+
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buff_size, sizeof(buff_size)) != 0) {
709+
PLOG(ERROR) << "Fail to set rcvbuf of fd=" << fd << " to "
710+
<< buff_size;
711+
}
712+
}
713+
}
714+
713715
// SocketId = 32-bit version + 32-bit slot.
714716
// version: from version part of _versioned_nref, must be an EVEN number.
715717
// slot: designated by ResourcePool.
@@ -1271,6 +1273,8 @@ int Socket::Connect(const timespec* abstime,
12711273
CHECK_EQ(0, butil::make_close_on_exec(sockfd));
12721274
// We need to do async connect (to manage the timeout by ourselves).
12731275
CHECK_EQ(0, butil::make_non_blocking(sockfd));
1276+
// Socket buffer sizes need to be set before connect.
1277+
brpc::SetSocketBufferOptions(sockfd);
12741278
if (!_device_name.empty()) {
12751279
#ifdef SO_BINDTODEVICE
12761280
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,

src/brpc/socket.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class EventDispatcher;
6868
class Stream;
6969
class Transport;
7070

71+
// Set SO_SNDBUF/SO_RCVBUF according to socket_*_buffer_size flags.
72+
void SetSocketBufferOptions(int fd);
73+
7174
// A special closure for processing the about-to-recycle socket. Socket does
7275
// not delete SocketUser, if you want, `delete this' at the end of
7376
// BeforeRecycle().

src/butil/endpoint.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ int tcp_connect(const EndPoint& server, int* self_port, int connect_timeout_ms)
561561
return sockfd.release();
562562
}
563563

564-
int tcp_listen(EndPoint point) {
564+
int tcp_listen(EndPoint point, BeforeListenCallback before_listen) {
565565
struct sockaddr_storage serv_addr;
566566
socklen_t serv_addr_size = 0;
567567
if (endpoint2sockaddr(point, &serv_addr, &serv_addr_size) != 0) {
@@ -602,6 +602,10 @@ int tcp_listen(EndPoint point) {
602602
::unlink(((sockaddr_un*) &serv_addr)->sun_path);
603603
}
604604

605+
if (before_listen) {
606+
before_listen(sockfd);
607+
}
608+
605609
if (::bind(sockfd, (struct sockaddr*)& serv_addr, serv_addr_size) != 0) {
606610
return -1;
607611
}
@@ -614,6 +618,10 @@ int tcp_listen(EndPoint point) {
614618
return sockfd.release();
615619
}
616620

621+
int tcp_listen(EndPoint point) {
622+
return tcp_listen(point, BeforeListenCallback());
623+
}
624+
617625
int get_local_side(int fd, EndPoint *out) {
618626
struct sockaddr_storage addr;
619627
socklen_t socklen = sizeof(addr);

src/butil/endpoint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <netinet/in.h> // in_addr
2626
#include <sys/un.h> // sockaddr_un
27+
#include <functional> // std::function
2728
#include <iostream> // std::ostream
2829
#include "butil/containers/hash_tables.h" // hashing functions
2930

@@ -141,6 +142,9 @@ int tcp_connect(const EndPoint& server, int* self_port, int connect_timeout_ms);
141142
// To enable SO_REUSEPORT for the whole program, enable gflag -reuse_port
142143
// Returns the socket descriptor, -1 otherwise and errno is set.
143144
int tcp_listen(EndPoint ip_and_port);
145+
// If `before_listen' is set, it will be called before bind/listen.
146+
typedef std::function<void(int)> BeforeListenCallback;
147+
int tcp_listen(EndPoint ip_and_port, BeforeListenCallback before_listen);
144148

145149
// Get the local end of a socket connection
146150
int get_local_side(int fd, EndPoint *out);

test/brpc_socket_unittest.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "brpc/policy/most_common_message.h"
4040
#include "brpc/policy/http_rpc_protocol.h"
4141
#include "brpc/server.h"
42+
#include "brpc/details/server_private_accessor.h"
4243
#include "brpc/channel.h"
4344
#include "brpc/controller.h"
4445
#include "health_check.pb.h"
@@ -59,6 +60,8 @@ DECLARE_bool(socket_keepalive);
5960
DECLARE_int32(socket_keepalive_idle_s);
6061
DECLARE_int32(socket_keepalive_interval_s);
6162
DECLARE_int32(socket_keepalive_count);
63+
DECLARE_int32(socket_recv_buffer_size);
64+
DECLARE_int32(socket_send_buffer_size);
6265
DECLARE_int32(socket_tcp_user_timeout_ms);
6366
}
6467

@@ -1123,6 +1126,45 @@ void CheckKeepalive(int fd,
11231126
ASSERT_EQ(expected_keepalive_count, keepalive_count);
11241127
}
11251128

1129+
struct SocketBufferValues {
1130+
int recv_buffer;
1131+
int send_buffer;
1132+
1133+
SocketBufferValues() : recv_buffer(0), send_buffer(0) {}
1134+
};
1135+
1136+
void GetSocketBufferValues(int fd, SocketBufferValues* values) {
1137+
socklen_t len = sizeof(values->recv_buffer);
1138+
ASSERT_EQ(0, getsockopt(fd, SOL_SOCKET, SO_RCVBUF,
1139+
&values->recv_buffer, &len));
1140+
len = sizeof(values->send_buffer);
1141+
ASSERT_EQ(0, getsockopt(fd, SOL_SOCKET, SO_SNDBUF,
1142+
&values->send_buffer, &len));
1143+
}
1144+
1145+
void GetExpectedSocketBufferValues(int buffer_size,
1146+
SocketBufferValues* expected) {
1147+
SocketBufferValues default_values;
1148+
butil::fd_guard default_fd(socket(AF_INET, SOCK_STREAM, 0));
1149+
ASSERT_GT(default_fd, 0);
1150+
GetSocketBufferValues(default_fd, &default_values);
1151+
1152+
butil::fd_guard reference_fd(socket(AF_INET, SOCK_STREAM, 0));
1153+
ASSERT_GT(reference_fd, 0);
1154+
ASSERT_EQ(0, setsockopt(reference_fd, SOL_SOCKET, SO_RCVBUF, &buffer_size,
1155+
sizeof(buffer_size)));
1156+
ASSERT_EQ(0, setsockopt(reference_fd, SOL_SOCKET, SO_SNDBUF, &buffer_size,
1157+
sizeof(buffer_size)));
1158+
GetSocketBufferValues(reference_fd, expected);
1159+
}
1160+
1161+
void CheckSocketBufferValues(int fd, const SocketBufferValues& expected) {
1162+
SocketBufferValues actual;
1163+
GetSocketBufferValues(fd, &actual);
1164+
ASSERT_EQ(expected.recv_buffer, actual.recv_buffer);
1165+
ASSERT_EQ(expected.send_buffer, actual.send_buffer);
1166+
}
1167+
11261168
TEST_F(SocketTest, keepalive) {
11271169
int default_keepalive = 0;
11281170
int default_keepalive_idle = 0;
@@ -1425,6 +1467,97 @@ TEST_F(SocketTest, keepalive_input_message) {
14251467
ASSERT_EQ(EBADF, errno);
14261468
}
14271469

1470+
TEST_F(SocketTest, socket_buffer_options_before_connect) {
1471+
gflags::FlagSaver flag_saver;
1472+
const int buffer_size = 256 * 1024;
1473+
brpc::FLAGS_socket_recv_buffer_size = buffer_size;
1474+
brpc::FLAGS_socket_send_buffer_size = buffer_size;
1475+
1476+
SocketBufferValues expected;
1477+
GetExpectedSocketBufferValues(buffer_size, &expected);
1478+
1479+
butil::EndPoint point;
1480+
ASSERT_EQ(0, str2endpoint("127.0.0.1:0", &point));
1481+
butil::fd_guard listening_fd(tcp_listen(point));
1482+
ASSERT_GT(listening_fd, 0) << berror();
1483+
ASSERT_EQ(0, butil::get_local_side(listening_fd, &point));
1484+
1485+
brpc::SocketOptions options;
1486+
options.remote_side = point;
1487+
brpc::SocketId id = brpc::INVALID_SOCKET_ID;
1488+
ASSERT_EQ(0, brpc::Socket::Create(options, &id));
1489+
1490+
brpc::SocketUniquePtr ptr;
1491+
ASSERT_EQ(0, brpc::Socket::Address(id, &ptr)) << "id=" << id;
1492+
1493+
const timespec duetime = butil::milliseconds_from_now(1000);
1494+
butil::fd_guard connected_fd(ptr->Connect(&duetime, NULL, NULL));
1495+
ASSERT_GT(connected_fd, 0);
1496+
CheckSocketBufferValues(connected_fd, expected);
1497+
1498+
ASSERT_EQ(0, ptr->SetFailed());
1499+
}
1500+
1501+
TEST_F(SocketTest, socket_buffer_options_before_accept) {
1502+
gflags::FlagSaver flag_saver;
1503+
const int buffer_size = 256 * 1024;
1504+
brpc::FLAGS_socket_recv_buffer_size = buffer_size;
1505+
brpc::FLAGS_socket_send_buffer_size = buffer_size;
1506+
1507+
SocketBufferValues expected;
1508+
GetExpectedSocketBufferValues(buffer_size, &expected);
1509+
1510+
butil::EndPoint point;
1511+
ASSERT_EQ(0, str2endpoint("127.0.0.1:0", &point));
1512+
brpc::Server server;
1513+
ASSERT_EQ(0, server.Start(point, NULL));
1514+
point = server.listen_address();
1515+
1516+
brpc::Acceptor* messenger =
1517+
brpc::ServerPrivateAccessor(&server).acceptor();
1518+
ASSERT_TRUE(messenger != NULL);
1519+
ASSERT_GT(messenger->listened_fd(), 0);
1520+
CheckSocketBufferValues(messenger->listened_fd(), expected);
1521+
1522+
// Accepted sockets should inherit the listener's buffer sizes, not use
1523+
// the flags at accept time.
1524+
brpc::FLAGS_socket_recv_buffer_size = buffer_size / 2;
1525+
brpc::FLAGS_socket_send_buffer_size = buffer_size / 2;
1526+
1527+
brpc::SocketOptions options;
1528+
options.remote_side = point;
1529+
options.connect_on_create = true;
1530+
brpc::SocketId id = brpc::INVALID_SOCKET_ID;
1531+
ASSERT_EQ(0, brpc::Socket::Create(options, &id));
1532+
1533+
const int64_t start_time = butil::cpuwide_time_us();
1534+
while (messenger->ConnectionCount() < 1) {
1535+
bthread_usleep(1000);
1536+
ASSERT_LT(butil::cpuwide_time_us(), start_time + 1000000L)
1537+
<< "Too long!";
1538+
}
1539+
1540+
std::vector<brpc::SocketId> connections;
1541+
messenger->ListConnections(&connections);
1542+
ASSERT_EQ(1ul, connections.size());
1543+
1544+
{
1545+
brpc::SocketUniquePtr accepted_socket;
1546+
ASSERT_EQ(0, brpc::Socket::Address(connections[0], &accepted_socket));
1547+
ASSERT_GT(accepted_socket->fd(), 0);
1548+
CheckSocketBufferValues(accepted_socket->fd(), expected);
1549+
ASSERT_EQ(0, accepted_socket->SetFailed());
1550+
}
1551+
1552+
{
1553+
brpc::SocketUniquePtr client_socket;
1554+
ASSERT_EQ(0, brpc::Socket::Address(id, &client_socket));
1555+
ASSERT_EQ(0, client_socket->SetFailed());
1556+
}
1557+
server.Stop(0);
1558+
server.Join();
1559+
}
1560+
14281561
#if defined(OS_LINUX)
14291562
void CheckTCPUserTimeout(int fd, int expect_tcp_user_timeout) {
14301563
int tcp_user_timeout = 0;

0 commit comments

Comments
 (0)