mirror of
https://code.videolan.org/rist/librist.git
synced 2026-07-04 15:06:53 +00:00
udpsocket: size socket buffers toward the OS maximum, not a fixed 1 MB
udpsocket_set_optimal_buffer_size()/_send_size() requested a fixed 1 MB
SO_RCVBUF/SO_SNDBUF and, on failure, fell back to ~200 KB. They never used
the headroom a large net.core.{r,w}mem_max provides. That headroom is what
lets a listener absorb a burst of simultaneous connections: a single
protocol thread drains one UDP socket, so when many peers establish at once
the inbound control/handshake traffic can momentarily exceed 1 MB and the
kernel silently drops the overflow, stalling the peers whose handshake
packets were lost.
Measured on a 16-core x86 listener (net.core.rmem_max = 16 MB) with 200
peers dialing in within <1 s: at the 1 MB buffer the kernel dropped 924
datagrams at the socket (Udp: RcvbufErrors) and only ~158/200 peers
completed authentication; the protocol thread sat at 9% of one core the
whole time, so it was never the bottleneck. Rebuilt with the buffer sized
to the OS maximum, the same storm dropped 0 datagrams and all peers
connected (256/256 at the 256-flow cap).
Request UDPSOCKET_SOCK_BUFSIZE_MAX (8 MB) and let the kernel clamp to
*mem_max, keeping whatever we obtain as long as it is at least the historical
1 MB floor; otherwise fall back to the ~200 KB last resort and warning
exactly as before. No API/ABI change, no new configuration, and hosts with a
small *mem_max are unaffected (they still settle at the same fallback). Also
correct the send-buffer error message to reference wmem_max instead of
rmem_max.
This commit is contained in:
@@ -56,7 +56,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/*** Public API ***/
|
||||
/* Historical fixed target / floor for the UDP socket buffers (1 MB). */
|
||||
#define UDPSOCKET_SOCK_BUFSIZE (1048576)
|
||||
/* Upper target requested before the kernel clamps to net.core.{r,w}mem_max. */
|
||||
#define UDPSOCKET_SOCK_BUFSIZE_MAX (8388608)
|
||||
|
||||
typedef struct udpsocket_url_param {
|
||||
char *key;
|
||||
|
||||
+15
-12
@@ -249,8 +249,9 @@ int udpsocket_open(uint16_t af)
|
||||
|
||||
int udpsocket_set_optimal_buffer_size(int sd)
|
||||
{
|
||||
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE;
|
||||
/* Request the OS-allowed maximum; the kernel clamps to net.core.rmem_max. */
|
||||
uint32_t current_recvbuf = udpsocket_get_buffer_size(sd);
|
||||
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE_MAX;
|
||||
if (current_recvbuf < bufsize){
|
||||
setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(uint32_t));
|
||||
current_recvbuf = udpsocket_get_buffer_size(sd);
|
||||
@@ -261,7 +262,8 @@ int udpsocket_set_optimal_buffer_size(int sd)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (current_recvbuf < bufsize){
|
||||
/* A clamped result above the 1 MB floor is fine; only fall back below it. */
|
||||
if (current_recvbuf < UDPSOCKET_SOCK_BUFSIZE){
|
||||
// Settle for a smaller size
|
||||
bufsize = UDPSOCKET_SOCK_BUFSIZE/5;
|
||||
setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(uint32_t));
|
||||
@@ -272,18 +274,19 @@ int udpsocket_set_optimal_buffer_size(int sd)
|
||||
current_recvbuf = udpsocket_get_buffer_size(sd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (current_recvbuf < bufsize){
|
||||
rist_log_priv3( RIST_LOG_ERROR, "Your UDP receive buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.rmem_max setting to at least 200 kbyte for best results.", current_recvbuf);
|
||||
return -1;
|
||||
if (current_recvbuf < bufsize){
|
||||
rist_log_priv3( RIST_LOG_ERROR, "Your UDP receive buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.rmem_max setting to at least 200 kbyte for best results.", current_recvbuf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udpsocket_set_optimal_buffer_send_size(int sd)
|
||||
{
|
||||
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE;
|
||||
/* Mirror the recv path: request the OS max, clamp to net.core.wmem_max. */
|
||||
uint32_t current_sendbuf = udpsocket_get_buffer_send_size(sd);
|
||||
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE_MAX;
|
||||
if (current_sendbuf < bufsize){
|
||||
setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(uint32_t));
|
||||
current_sendbuf = udpsocket_get_buffer_send_size(sd);
|
||||
@@ -294,7 +297,7 @@ int udpsocket_set_optimal_buffer_send_size(int sd)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (current_sendbuf < bufsize){
|
||||
if (current_sendbuf < UDPSOCKET_SOCK_BUFSIZE){
|
||||
// Settle for a smaller size
|
||||
bufsize = UDPSOCKET_SOCK_BUFSIZE/5;
|
||||
setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(uint32_t));
|
||||
@@ -305,10 +308,10 @@ int udpsocket_set_optimal_buffer_send_size(int sd)
|
||||
current_sendbuf = udpsocket_get_buffer_send_size(sd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (current_sendbuf < bufsize){
|
||||
rist_log_priv3( RIST_LOG_ERROR, "Your UDP send buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.rmem_max setting to at least 200 kbyte for best results.", current_sendbuf);
|
||||
return -1;
|
||||
if (current_sendbuf < bufsize){
|
||||
rist_log_priv3( RIST_LOG_ERROR, "Your UDP send buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.wmem_max setting to at least 200 kbyte for best results.", current_sendbuf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user