You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.8 KiB
102 lines
2.8 KiB
From a58f31659a924c59f6342d79d2c19ee956453d82 Mon Sep 17 00:00:00 2001 |
|
From: Mark Andrews <marka@isc.org> |
|
Date: Sat, 18 Oct 2014 12:40:13 +1100 |
|
Subject: [PATCH 2/2] 3980. [bug] Improve --with-tuning=large by |
|
self tuning of SO_RCVBUF size. [RT #37187] |
|
|
|
(cherry picked from commit 871f3c8beeb2134b17414ec167b90a57adb8e122) |
|
--- |
|
lib/isc/unix/socket.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- |
|
1 file changed, 61 insertions(+), 5 deletions(-) |
|
|
|
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c |
|
index af0c3bc..90953ff 100644 |
|
--- a/lib/isc/unix/socket.c |
|
+++ b/lib/isc/unix/socket.c |
|
@@ -2245,6 +2245,62 @@ free_socket(isc__socket_t **socketp) { |
|
*socketp = NULL; |
|
} |
|
|
|
+#ifdef SO_RCVBUF |
|
+static isc_once_t rcvbuf_once = ISC_ONCE_INIT; |
|
+static int rcvbuf = RCVBUFSIZE; |
|
+ |
|
+static void |
|
+set_rcvbuf(void) { |
|
+ int fd; |
|
+ int max = rcvbuf, min; |
|
+ ISC_SOCKADDR_LEN_T len; |
|
+ |
|
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
|
+#if defined(ISC_PLATFORM_HAVEIPV6) |
|
+ if (fd == -1) { |
|
+ switch (errno) { |
|
+ case EPROTONOSUPPORT: |
|
+ case EPFNOSUPPORT: |
|
+ case EAFNOSUPPORT: |
|
+ /* |
|
+ * Linux 2.2 (and maybe others) return EINVAL instead of |
|
+ * EAFNOSUPPORT. |
|
+ */ |
|
+ case EINVAL: |
|
+ fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
|
+ break; |
|
+ } |
|
+ } |
|
+#endif |
|
+ if (fd == -1) |
|
+ return; |
|
+ |
|
+ len = sizeof(min); |
|
+ if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&min, &len) >= 0 && |
|
+ min < rcvbuf) { |
|
+ again: |
|
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf, |
|
+ sizeof(rcvbuf)) == -1) { |
|
+ if (errno == ENOBUFS && rcvbuf > min) { |
|
+ max = rcvbuf - 1; |
|
+ rcvbuf = (rcvbuf + min) / 2; |
|
+ goto again; |
|
+ } else { |
|
+ rcvbuf = min; |
|
+ goto cleanup; |
|
+ } |
|
+ } else |
|
+ min = rcvbuf; |
|
+ if (min != max) { |
|
+ rcvbuf = max; |
|
+ goto again; |
|
+ } |
|
+ } |
|
+ cleanup: |
|
+ close (fd); |
|
+} |
|
+#endif |
|
+ |
|
#ifdef SO_BSDCOMPAT |
|
/* |
|
* This really should not be necessary to do. Having to workout |
|
@@ -2609,15 +2665,15 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, |
|
#if defined(SO_RCVBUF) |
|
optlen = sizeof(size); |
|
if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, |
|
- (void *)&size, &optlen) >= 0 && |
|
- size < RCVBUFSIZE) { |
|
- size = RCVBUFSIZE; |
|
+ (void *)&size, &optlen) >= 0 && size < rcvbuf) { |
|
+ RUNTIME_CHECK(isc_once_do(&rcvbuf_once, |
|
+ set_rcvbuf) == ISC_R_SUCCESS); |
|
if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, |
|
- (void *)&size, sizeof(size)) == -1) { |
|
+ (void *)&rcvbuf, sizeof(rcvbuf)) == -1) { |
|
isc__strerror(errno, strbuf, sizeof(strbuf)); |
|
UNEXPECTED_ERROR(__FILE__, __LINE__, |
|
"setsockopt(%d, SO_RCVBUF, %d) %s: %s", |
|
- sock->fd, size, |
|
+ sock->fd, rcvbuf, |
|
isc_msgcat_get(isc_msgcat, |
|
ISC_MSGSET_GENERAL, |
|
ISC_MSG_FAILED, |
|
-- |
|
2.9.5 |
|
|
|
|