From fb3fa2a3998132410ee7b942aa298568bb612aae Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 10 Nov 2017 21:32:59 +0000 Subject: [PATCH] Add support for TcpNice on OSX, remove on Windows I'm not convinced that it does anything on Windows without an RTT estimate, which we can't get without administrator access: https://msdn.microsoft.com/en-us/library/windows/desktop/bb485738(v=vs.85).aspx (cherry picked from commit b646d22f415bbc8f5b5b065ed7462166591404f2) --- infrastructure/cmake/CMakeLists.txt | 6 ++++-- infrastructure/m4/boxbackup_tests.m4 | 4 ++-- lib/bbackupd/BackupClientContext.cpp | 10 ++++++++-- lib/bbackupd/BackupClientContext.h | 4 ++++ lib/server/TcpNice.cpp | 29 ++++++++++++++++++++++++---- lib/server/TcpNice.h | 11 +++++++++++ 6 files changed, 54 insertions(+), 10 deletions(-) diff --git a/infrastructure/cmake/CMakeLists.txt b/infrastructure/cmake/CMakeLists.txt index 4e52a3afd..556c1c21b 100644 --- a/infrastructure/cmake/CMakeLists.txt +++ b/infrastructure/cmake/CMakeLists.txt @@ -509,13 +509,15 @@ foreach(m4_filename boxbackup_tests.m4 ax_check_mount_point.m4 ax_func_syscall.m foreach(function_name ${function_names}) list(APPEND detect_functions ${function_name}) endforeach() - elseif(m4_function MATCHES "^ *AC_CHECK_DECLS\\(\\[([A-Za-z._/ ]+)\\](,,, ..#include <([^>]+)>..)?\\)$") + elseif(m4_function MATCHES "^ *AC_CHECK_DECLS\\(\\[([A-Za-z._/ ,]+)\\](,,, ..#include <([^>]+)>..)?\\)$") if(DEBUG) message(STATUS "Processing ac_check_decls: ${CMAKE_MATCH_1} in ${CMAKE_MATCH_3}") endif() + # Multiple declarations to check are comma-separated, which is unusual. # http://stackoverflow.com/questions/5272781/what-is-common-way-to-split-string-into-list-with-cmake - string(REPLACE " " ";" decl_names "${CMAKE_MATCH_1}") + string(REPLACE "," ";" decl_names "${CMAKE_MATCH_1}") + string(REPLACE " " "" decl_names "${decl_names}") string(REPLACE " " ";" header_files "${CMAKE_MATCH_3}") foreach(decl_name ${decl_names}) diff --git a/infrastructure/m4/boxbackup_tests.m4 b/infrastructure/m4/boxbackup_tests.m4 index 9c9913858..6e85f23fb 100644 --- a/infrastructure/m4/boxbackup_tests.m4 +++ b/infrastructure/m4/boxbackup_tests.m4 @@ -248,8 +248,8 @@ AC_CHECK_DECLS([O_BINARY],,, [[#include ]]) AC_CHECK_DECLS([ENOTSUP],,, [[#include ]]) AC_CHECK_DECLS([INFTIM],,, [[#include ]]) AC_CHECK_DECLS([SO_PEERCRED],,, [[#include ]]) -AC_CHECK_DECLS([SOL_TCP],,, [[#include ]]) -AC_CHECK_DECLS([TCP_INFO],,, [[#include ]]) +AC_CHECK_DECLS([IPPROTO_TCP],,, [[#include ]]) +AC_CHECK_DECLS([SOL_TCP,TCP_INFO,TCP_CONNECTION_INFO],,, [[#include ]]) if test -n "$have_sys_socket_h"; then AC_CHECK_DECLS([SO_SNDBUF],,, [[#include ]]) diff --git a/lib/bbackupd/BackupClientContext.cpp b/lib/bbackupd/BackupClientContext.cpp index 863575e22..a43c4368c 100644 --- a/lib/bbackupd/BackupClientContext.cpp +++ b/lib/bbackupd/BackupClientContext.cpp @@ -73,8 +73,10 @@ BackupClientContext::BackupClientContext mKeepAliveTimer(0, "KeepAliveTime"), mbIsManaged(false), mrProgressNotifier(rProgressNotifier), - mTcpNiceMode(TcpNiceMode), - mpNice(NULL) + mTcpNiceMode(TcpNiceMode) +#ifdef ENABLE_TCP_NICE + , mpNice(NULL) +#endif { } @@ -135,6 +137,7 @@ BackupProtocolCallable &BackupClientContext::GetConnection() if(mTcpNiceMode) { +#ifdef ENABLE_TCP_NICE // Pass control of apSocket to NiceSocketStream, // which will take care of destroying it for us. // But we need to hang onto a pointer to the nice @@ -142,6 +145,9 @@ BackupProtocolCallable &BackupClientContext::GetConnection() // This is scary, it could be deallocated under us. mpNice = new NiceSocketStream(apSocket); apSocket.reset(mpNice); +#else + BOX_WARNING("TcpNice option is enabled but not supported on this system"); +#endif } // We need to call some methods that aren't defined in diff --git a/lib/bbackupd/BackupClientContext.h b/lib/bbackupd/BackupClientContext.h index df43a2321..854938b50 100644 --- a/lib/bbackupd/BackupClientContext.h +++ b/lib/bbackupd/BackupClientContext.h @@ -216,7 +216,9 @@ class BackupClientContext : public DiffTimer { if(mTcpNiceMode) { +#ifdef ENABLE_TCP_NICE mpNice->SetEnabled(enabled); +#endif } } @@ -246,7 +248,9 @@ class BackupClientContext : public DiffTimer int mMaximumDiffingTime; ProgressNotifier &mrProgressNotifier; bool mTcpNiceMode; +#ifdef ENABLE_TCP_NICE NiceSocketStream *mpNice; +#endif }; #endif // BACKUPCLIENTCONTEXT__H diff --git a/lib/server/TcpNice.cpp b/lib/server/TcpNice.cpp index 775c5955f..36fd57358 100644 --- a/lib/server/TcpNice.cpp +++ b/lib/server/TcpNice.cpp @@ -30,6 +30,7 @@ #include "MemLeakFindOn.h" +#ifdef ENABLE_TCP_NICE // -------------------------------------------------------------------------- // // Function @@ -139,7 +140,6 @@ NiceSocketStream::NiceSocketStream(std::auto_ptr apSocket) // -------------------------------------------------------------------------- void NiceSocketStream::Write(const void *pBuffer, int NBytes, int Timeout) { -#if HAVE_DECL_SO_SNDBUF && HAVE_DECL_TCP_INFO if(mEnabled && mapTimer.get() && mapTimer->HasExpired()) { box_time_t newPeriodStart = GetCurrentBoxTime(); @@ -148,6 +148,7 @@ void NiceSocketStream::Write(const void *pBuffer, int NBytes, int Timeout) int rtt = 50; // WAG # if HAVE_DECL_SOL_TCP && defined HAVE_STRUCT_TCP_INFO_TCPI_RTT + // The Linux way struct tcp_info info; socklen_t optlen = sizeof(info); if(getsockopt(socket, SOL_TCP, TCP_INFO, &info, &optlen) == -1) @@ -165,6 +166,27 @@ void NiceSocketStream::Write(const void *pBuffer, int NBytes, int Timeout) { rtt = info.tcpi_rtt; } +# elif HAVE_DECL_IPPROTO_TCP && defined HAVE_DECL_TCP_CONNECTION_INFO + // The OSX way: https://stackoverflow.com/a/40478874/648162 + struct tcp_connection_info info; + socklen_t optlen = sizeof(info); + if(getsockopt(socket, IPPROTO_TCP, TCP_CONNECTION_INFO, &info, &optlen) == -1) + { + BOX_LOG_SYS_WARNING("getsockopt(" << socket << ", IPPROTO_TCP, " + "TCP_CONNECTION_INFO) failed"); + } + else if(optlen < sizeof(info)) + { + BOX_WARNING("getsockopt(" << socket << ", IPPROTO_TCP, " + "TCP_CONNECTION_INFO) return structure size " << optlen << ", " + "expected " << sizeof(info)); + } + else + { + rtt = info.tcpi_rttcur; + } +# else +# error "Don't know how to get current TCP RTT" # endif // HAVE_DECL_SOL_TCP && defined HAVE_STRUCT_TCP_INFO_TCPI_RTT int newWindow = mTcpNice.GetNextWindowSize(mBytesWrittenThisPeriod, @@ -192,7 +214,6 @@ void NiceSocketStream::Write(const void *pBuffer, int NBytes, int Timeout) } mBytesWrittenThisPeriod += NBytes; -#endif // HAVE_DECL_SO_SNDBUF mapSocket->Write(pBuffer, NBytes, Timeout); } @@ -214,7 +235,6 @@ void NiceSocketStream::SetEnabled(bool enabled) if(!enabled) { StopTimer(); -#if HAVE_DECL_SO_SNDBUF int socket = mapSocket->GetSocketHandle(); int newWindow = 1<<17; if(setsockopt(socket, SOL_SOCKET, SO_SNDBUF, @@ -231,6 +251,7 @@ void NiceSocketStream::SetEnabled(bool enabled) BOX_LOG_SYS_WARNING("getsockopt(" << socket << ", SOL_SOCKET, " "SO_SNDBUF, " << newWindow << ") failed"); } -#endif } } + +#endif // ENABLE_TCP_NICE diff --git a/lib/server/TcpNice.h b/lib/server/TcpNice.h index 09a0d59b8..215a0bd93 100644 --- a/lib/server/TcpNice.h +++ b/lib/server/TcpNice.h @@ -18,6 +18,16 @@ #include "SocketStream.h" #include "Timer.h" +#if HAVE_DECL_SO_SNDBUF +# if HAVE_DECL_SOL_TCP && defined HAVE_STRUCT_TCP_INFO_TCPI_RTT +# define ENABLE_TCP_NICE +# elif HAVE_DECL_IPPROTO_TCP && HAVE_DECL_TCP_CONNECTION_INFO +// https://stackoverflow.com/a/40478874/648162 +# define ENABLE_TCP_NICE +# endif +#endif + +#ifdef ENABLE_TCP_NICE // -------------------------------------------------------------------------- // // Class @@ -176,5 +186,6 @@ class NiceSocketStream : public SocketStream NiceSocketStream(const NiceSocketStream &rToCopy) { /* do not call */ } }; +#endif // ENABLE_TCP_NICE #endif // TCPNICE__H