From e8a9a366db7bf834a3e93c6ec05336e5aca882c4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 28 Nov 2015 14:01:24 +0900 Subject: [PATCH] Add --socket-recv-buffer-size option Set the maximum socket receive buffer in bytes. Specifing 0 will disable this option. This value will be set to socket file descriptor using SO_RCVBUF socket option with setsockopt() call. See GH-487 about the usecase of this option --- doc/manual-src/en/aria2c.rst | 8 +++++++ src/Context.cc | 2 ++ src/OptionHandlerFactory.cc | 10 +++++++++ src/SocketCore.cc | 41 ++++++++++++++++++++++++++++++++++++ src/SocketCore.h | 5 +++++ src/prefs.cc | 2 ++ src/prefs.h | 2 ++ src/usage_text.h | 6 ++++++ 8 files changed, 76 insertions(+) diff --git a/doc/manual-src/en/aria2c.rst b/doc/manual-src/en/aria2c.rst index 8a2657a3..d42ecdac 100644 --- a/doc/manual-src/en/aria2c.rst +++ b/doc/manual-src/en/aria2c.rst @@ -1562,6 +1562,14 @@ Advanced Options :option:`--save-session` option every SEC seconds. If ``0`` is given, file will be saved only when aria2 exits. Default: ``0`` + +.. option:: --socket-recv-buffer-size= + + Set the maximum socket receive buffer in bytes. Specifing ``0`` + will disable this option. This value will be set to socket file + descriptor using ``SO_RCVBUF`` socket option with ``setsockopt()`` + call. Default: ``0`` + .. option:: --stop= Stop application after SEC seconds has passed. diff --git a/src/Context.cc b/src/Context.cc index 70bbb4e5..1f6d8d10 100644 --- a/src/Context.cc +++ b/src/Context.cc @@ -223,6 +223,8 @@ Context::Context(bool standalone, setDefaultAIFlags(0); } SocketCore::setIpDscp(op->getAsInt(PREF_DSCP)); + SocketCore::setSocketRecvBufferSize(op->getAsInt + (PREF_SOCKET_RECV_BUFFER_SIZE)); net::checkAddrconfig(); // Bind interface if(!op->get(PREF_INTERFACE).empty()) { diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 85642c4b..3967d3c7 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -811,6 +811,16 @@ std::vector OptionHandlerFactory::createOptionHandlers() op->addTag(TAG_ADVANCED); handlers.push_back(op); } + { + OptionHandler* op(new UnitNumberOptionHandler + (PREF_SOCKET_RECV_BUFFER_SIZE, + TEXT_SOCKET_RECV_BUFFER_SIZE, + "0", + 0, + 16_m)); + op->addTag(TAG_ADVANCED); + handlers.push_back(op); + } { OptionHandler* op(new NumberOptionHandler (PREF_STOP, diff --git a/src/SocketCore.cc b/src/SocketCore.cc index 3b8cb4a5..96727837 100644 --- a/src/SocketCore.cc +++ b/src/SocketCore.cc @@ -143,6 +143,8 @@ SocketCore::bindAddrsList_; std::vector > >::iterator SocketCore::bindAddrsListIt_; +int SocketCore::socketRecvBufferSize_ = 0; + #ifdef ENABLE_SSL std::shared_ptr SocketCore::clTlsContext_; std::shared_ptr SocketCore::svTlsContext_; @@ -187,6 +189,23 @@ SocketCore::~SocketCore() { closeConnection(); } +namespace { +void applySocketBufferSize(sock_t fd) +{ + auto recvBufSize = SocketCore::getSocketRecvBufferSize(); + if (recvBufSize == 0) { + return; + } + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (a2_sockopt_t)&recvBufSize, + sizeof(recvBufSize)) < 0) { + auto errNum = SOCKET_ERRNO; + A2_LOG_WARN(fmt("Failed to set socket buffer size. Cause: %s", + errorMsg(errNum).c_str())); + } +} +} // namespace + void SocketCore::create(int family, int protocol) { int errNum; @@ -205,6 +224,9 @@ void SocketCore::create(int family, int protocol) throw DL_ABORT_EX (fmt("Failed to create socket. Cause:%s", errorMsg(errNum).c_str())); } + + applySocketBufferSize(fd); + sockfd_ = fd; } @@ -240,6 +262,9 @@ static sock_t bindInternal } } #endif // IPV6_V6ONLY + + applySocketBufferSize(fd); + if(::bind(fd, addr, addrlen) == -1) { errNum = SOCKET_ERRNO; error = errorMsg(errNum); @@ -364,6 +389,9 @@ std::shared_ptr SocketCore::acceptConnection() const if(fd == (sock_t) -1) { throw DL_ABORT_EX(fmt(EX_SOCKET_ACCEPT, errorMsg(errNum).c_str())); } + + applySocketBufferSize(fd); + auto sock = std::make_shared(fd, sockType_); sock->setNonBlockingMode(); return sock; @@ -437,6 +465,9 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port, CLOSE(fd); continue; } + + applySocketBufferSize(fd); + if(!bindAddrs_.empty()) { bool bindSuccess = false; for(std::vector >:: @@ -1284,6 +1315,16 @@ void SocketCore::bindAllAddress(const std::string& ifaces) bindAddrs_ = *bindAddrsListIt_; } +void SocketCore::setSocketRecvBufferSize(int size) +{ + socketRecvBufferSize_ = size; +} + +int SocketCore::getSocketRecvBufferSize() +{ + return socketRecvBufferSize_; +} + void getInterfaceAddress (std::vector >& ifAddrs, const std::string& iface, int family, int aiFlags) diff --git a/src/SocketCore.h b/src/SocketCore.h index de8e6cd2..9b346666 100644 --- a/src/SocketCore.h +++ b/src/SocketCore.h @@ -76,6 +76,8 @@ private: static std::vector > > bindAddrsList_; static std::vector > >::iterator bindAddrsListIt_; + static int socketRecvBufferSize_; + bool blocking_; int secure_; @@ -359,6 +361,9 @@ public: protocolFamily_ = protocolFamily; } + static void setSocketRecvBufferSize(int size); + static int getSocketRecvBufferSize(); + // Bind socket to interface. interface may be specified as a // hostname, IP address or interface name like eth0. If the given // interface is not found or binding socket is failed, exception diff --git a/src/prefs.cc b/src/prefs.cc index a3046b54..7da29859 100644 --- a/src/prefs.cc +++ b/src/prefs.cc @@ -375,6 +375,8 @@ PrefPtr PREF_PAUSE_METADATA = makePref("pause-metadata"); PrefPtr PREF_RLIMIT_NOFILE = makePref("rlimit-nofile"); // values: SSLv3 | TLSv1 | TLSv1.1 | TLSv1.2 PrefPtr PREF_MIN_TLS_VERSION = makePref("min-tls-version"); +// value: 1*digit +PrefPtr PREF_SOCKET_RECV_BUFFER_SIZE = makePref("socket-recv-buffer-size"); /** * FTP related preferences diff --git a/src/prefs.h b/src/prefs.h index 66eda2fb..615f8449 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -312,6 +312,8 @@ extern PrefPtr PREF_PAUSE_METADATA; extern PrefPtr PREF_RLIMIT_NOFILE; // values: SSLv3 | TLSv1 | TLSv1.1 | TLSv1.2 extern PrefPtr PREF_MIN_TLS_VERSION; +// value: 1*digit +extern PrefPtr PREF_SOCKET_RECV_BUFFER_SIZE; /** * FTP related preferences diff --git a/src/usage_text.h b/src/usage_text.h index d595c233..9a4b93c3 100644 --- a/src/usage_text.h +++ b/src/usage_text.h @@ -1040,3 +1040,9 @@ " public key when SFTP is used. If this option is\n" \ " not set, which is default, no validation takes\n" \ " place.") +#define TEXT_SOCKET_RECV_BUFFER_SIZE \ + _(" --socket-recv-buffer-size=SIZE\n" \ + " Set the maximum socket receive buffer in bytes.\n" \ + " Specifing 0 will disable this option. This value\n" \ + " will be set to socket file descriptor using\n" \ + " SO_RCVBUF socket option with setsockopt() call.")