feat: use canonical peer priority to decide which peers to keep (#6981)

* feat: CRC32-C

* feat: canonical peer priority calculation bep-40

* test: add test cases for IPv4 canonical peer priority

* refactor: compare by canonical priority

* fix: use network byte order for peer ports

* test: more cases

* build: xcode

Co-authored-by: Dzmitry Neviadomski <nevack.d@gmail.com>

* ci: test system crc32c library

---------

Co-authored-by: Dzmitry Neviadomski <nevack.d@gmail.com>
This commit is contained in:
Yat Ho
2025-10-26 01:05:20 +08:00
committed by GitHub
parent e7d4a69107
commit 0715897fc8
14 changed files with 560 additions and 15 deletions

View File

@@ -362,7 +362,7 @@ jobs:
echo '${{ toJSON(runner) }}' echo '${{ toJSON(runner) }}'
sw_vers sw_vers
- name: Get Dependencies - name: Get Dependencies
run: brew install --formulae cmake gettext libdeflate libevent libpsl miniupnpc ninja node pkgconf run: brew install --formulae cmake gettext libdeflate libevent libpsl miniupnpc ninja node pkgconf crc32c
- name: Get Dependencies (GTK) - name: Get Dependencies (GTK)
if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }} if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }}
run: brew install --formula gtkmm3 run: brew install --formula gtkmm3
@@ -393,7 +393,8 @@ jobs:
-DENABLE_UTILS=${{ (needs.what-to-make.outputs.make-utils == 'true') && 'ON' || 'OFF' }} \ -DENABLE_UTILS=${{ (needs.what-to-make.outputs.make-utils == 'true') && 'ON' || 'OFF' }} \
-DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \ -DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \
-DENABLE_WERROR=ON \ -DENABLE_WERROR=ON \
-DRUN_CLANG_TIDY=OFF -DRUN_CLANG_TIDY=OFF \
-DUSE_SYSTEM_Crc32c=ON
- name: Make - name: Make
run: cmake --build obj --config RelWithDebInfo run: cmake --build obj --config RelWithDebInfo
- name: Test - name: Test
@@ -420,7 +421,7 @@ jobs:
echo '${{ toJSON(runner) }}' echo '${{ toJSON(runner) }}'
sw_vers sw_vers
- name: Get Dependencies - name: Get Dependencies
run: brew install --formulae cmake gettext libdeflate libevent libpsl miniupnpc ninja node pkgconf run: brew install --formulae cmake gettext libdeflate libevent libpsl miniupnpc ninja node pkgconf crc32c
- name: Get Source - name: Get Source
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
@@ -445,7 +446,8 @@ jobs:
-DENABLE_QT=OFF \ -DENABLE_QT=OFF \
-DENABLE_TESTS=OFF \ -DENABLE_TESTS=OFF \
-DENABLE_WERROR=ON \ -DENABLE_WERROR=ON \
-DRUN_CLANG_TIDY=OFF -DRUN_CLANG_TIDY=OFF \
-DUSE_SYSTEM_CRC32C=ON
- name: Make - name: Make
run: cmake --build obj --config RelWithDebInfo run: cmake --build obj --config RelWithDebInfo
@@ -468,6 +470,7 @@ jobs:
apk add \ apk add \
ca-certificates \ ca-certificates \
cmake \ cmake \
crc32c-dev \
curl-dev \ curl-dev \
fmt-dev \ fmt-dev \
g++ \ g++ \
@@ -509,7 +512,8 @@ jobs:
-DENABLE_UTILS=${{ (needs.what-to-make.outputs.make-utils == 'true') && 'ON' || 'OFF' }} \ -DENABLE_UTILS=${{ (needs.what-to-make.outputs.make-utils == 'true') && 'ON' || 'OFF' }} \
-DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \ -DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \
-DENABLE_WERROR=ON \ -DENABLE_WERROR=ON \
-DRUN_CLANG_TIDY=OFF -DRUN_CLANG_TIDY=OFF \
-DUSE_SYSTEM_CRC32C=ON
- name: Make - name: Make
run: cmake --build obj --config RelWithDebInfo run: cmake --build obj --config RelWithDebInfo
- name: Test - name: Test
@@ -864,6 +868,7 @@ jobs:
fmt-devel \ fmt-devel \
gcc-c++ \ gcc-c++ \
gettext \ gettext \
google-crc32c-devel \
libcurl-devel \ libcurl-devel \
libdeflate-devel \ libdeflate-devel \
libevent-devel \ libevent-devel \
@@ -905,7 +910,8 @@ jobs:
-DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \ -DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \
-DENABLE_DEPRECATED=ON \ -DENABLE_DEPRECATED=ON \
-DENABLE_WERROR=OFF \ -DENABLE_WERROR=OFF \
-DRUN_CLANG_TIDY=OFF -DRUN_CLANG_TIDY=OFF \
-DUSE_SYSTEM_Crc32c=ON
- name: Build - name: Build
run: cmake --build obj --config RelWithDebInfo run: cmake --build obj --config RelWithDebInfo
- name: Test - name: Test

3
.gitmodules vendored
View File

@@ -61,3 +61,6 @@
path = third-party/rpavlik-cmake-modules path = third-party/rpavlik-cmake-modules
# synced with https://github.com/rpavlik/cmake-modules.git # synced with https://github.com/rpavlik/cmake-modules.git
url = https://github.com/transmission/rpavlik-cmake-modules.git url = https://github.com/transmission/rpavlik-cmake-modules.git
[submodule "third-party/crc32c"]
path = third-party/crc32c
url = https://github.com/google/crc32c.git

View File

@@ -79,6 +79,7 @@ tr_auto_option(USE_SYSTEM_NATPMP "Use system natpmp library" AUTO)
tr_auto_option(USE_SYSTEM_UTP "Use system utp library" AUTO) tr_auto_option(USE_SYSTEM_UTP "Use system utp library" AUTO)
tr_auto_option(USE_SYSTEM_B64 "Use system b64 library" AUTO) tr_auto_option(USE_SYSTEM_B64 "Use system b64 library" AUTO)
tr_auto_option(USE_SYSTEM_PSL "Use system psl library" AUTO) tr_auto_option(USE_SYSTEM_PSL "Use system psl library" AUTO)
tr_auto_option(USE_SYSTEM_CRC32C "Use system crc32c library" AUTO)
tr_list_option(USE_GTK_VERSION "Use specific GTK version" AUTO 3 4) tr_list_option(USE_GTK_VERSION "Use specific GTK version" AUTO 3 4)
tr_list_option(USE_QT_VERSION "Use specific Qt version" AUTO 5 6) tr_list_option(USE_QT_VERSION "Use specific Qt version" AUTO 5 6)
tr_list_option(WITH_CRYPTO "Use specified crypto library" AUTO ccrypto mbedtls openssl wolfssl) tr_list_option(WITH_CRYPTO "Use specified crypto library" AUTO ccrypto mbedtls openssl wolfssl)
@@ -558,6 +559,14 @@ tr_add_external_auto_library(B64 libb64 b64
CMAKE_ARGS CMAKE_ARGS
-DLIBB64_SHARED:BOOL=OFF) -DLIBB64_SHARED:BOOL=OFF)
tr_add_external_auto_library(CRC32C crc32c crc32c
TARGET Crc32c::crc32c
CMAKE_ARGS
-DCRC32C_BUILD_TESTS=OFF
-DCRC32C_BUILD_BENCHMARKS=OFF
-DCRC32C_USE_GLOG=OFF
-DCRC32C_INSTALL=ON)
set(TR_WEB_ASSETS ${PROJECT_SOURCE_DIR}/web/public_html) set(TR_WEB_ASSETS ${PROJECT_SOURCE_DIR}/web/public_html)
if(REBUILD_WEB) if(REBUILD_WEB)
tr_get_required_flag(REBUILD_WEB NPM_IS_REQUIRED) tr_get_required_flag(REBUILD_WEB NPM_IS_REQUIRED)

View File

@@ -453,6 +453,20 @@
ED86936F2ADAE34D00342B1A /* DefaultAppHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED86936E2ADAE34D00342B1A /* DefaultAppHelper.mm */; }; ED86936F2ADAE34D00342B1A /* DefaultAppHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED86936E2ADAE34D00342B1A /* DefaultAppHelper.mm */; };
ED8A16412735A8AA000D61F9 /* peer-mgr-wishlist.h in Headers */ = {isa = PBXBuildFile; fileRef = ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */; }; ED8A16412735A8AA000D61F9 /* peer-mgr-wishlist.h in Headers */ = {isa = PBXBuildFile; fileRef = ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */; };
ED8A16422735A8AA000D61F9 /* peer-mgr-wishlist.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */; }; ED8A16422735A8AA000D61F9 /* peer-mgr-wishlist.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */; };
ED91F28B2CBDA72C008388AA /* crc32c.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED91F01E2CBDA72C008388AA /* crc32c.cc */; };
ED91F2B52CBDA72C008388AA /* crc32c_sse42.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED91F0312CBDA72C008388AA /* crc32c_sse42.cc */; settings = {COMPILER_FLAGS = "-msse4.2"; }; };
ED91F2F52CBDA72C008388AA /* crc32c_arm64.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED91F0202CBDA72C008388AA /* crc32c_arm64.cc */; };
ED91F3152CBDA72C008388AA /* crc32c_portable.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED91F0282CBDA72C008388AA /* crc32c_portable.cc */; };
ED91F33A2CBDA72C008388AA /* crc32c_arm64.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F01F2CBDA72C008388AA /* crc32c_arm64.h */; };
ED91F3432CBDA72C008388AA /* crc32c_prefetch.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F02A2CBDA72C008388AA /* crc32c_prefetch.h */; };
ED91F34B2CBDA72C008388AA /* crc32c_sse42_check.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F0322CBDA72C008388AA /* crc32c_sse42_check.h */; };
ED91F3502CBDA72C008388AA /* crc32c_round_up.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F02E2CBDA72C008388AA /* crc32c_round_up.h */; };
ED91F3542CBDA72C008388AA /* crc32c_sse42.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F0302CBDA72C008388AA /* crc32c_sse42.h */; };
ED91F35A2CBDA72C008388AA /* crc32c.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F01B2CBDA72C008388AA /* crc32c.h */; settings = {ATTRIBUTES = (Public, ); }; };
ED91F35D2CBDA72C008388AA /* crc32c_read_le.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F02C2CBDA72C008388AA /* crc32c_read_le.h */; };
ED91F3602CBDA72C008388AA /* crc32c_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F0272CBDA72C008388AA /* crc32c_internal.h */; };
ED91F3612CBDA72C008388AA /* crc32c_arm64_check.h in Headers */ = {isa = PBXBuildFile; fileRef = ED91F0212CBDA72C008388AA /* crc32c_arm64_check.h */; };
ED91F3962CBDAAED008388AA /* libcrc32c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ED91F00C2CBDA5D3008388AA /* libcrc32c.a */; };
ED9862972B979AA2002F3035 /* Utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED9862962B979AA2002F3035 /* Utils.mm */; }; ED9862972B979AA2002F3035 /* Utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED9862962B979AA2002F3035 /* Utils.mm */; };
EDBA61FF2D4180D5001470F8 /* torrent-queue.h in Headers */ = {isa = PBXBuildFile; fileRef = EDBA61FD2D4180D5001470F8 /* torrent-queue.h */; }; EDBA61FF2D4180D5001470F8 /* torrent-queue.h in Headers */ = {isa = PBXBuildFile; fileRef = EDBA61FD2D4180D5001470F8 /* torrent-queue.h */; };
EDBA62002D4180D5001470F8 /* torrent-queue.cc in Sources */ = {isa = PBXBuildFile; fileRef = EDBA61FE2D4180D5001470F8 /* torrent-queue.cc */; }; EDBA62002D4180D5001470F8 /* torrent-queue.cc in Sources */ = {isa = PBXBuildFile; fileRef = EDBA61FE2D4180D5001470F8 /* torrent-queue.cc */; };
@@ -590,6 +604,13 @@
remoteGlobalIDString = 4D18389609DEC0030047D688; remoteGlobalIDString = 4D18389609DEC0030047D688;
remoteInfo = libtransmission; remoteInfo = libtransmission;
}; };
ED91F3942CBDA9BD008388AA /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = ED91F00B2CBDA5D3008388AA;
remoteInfo = crc32c;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -1372,6 +1393,20 @@
ED86936E2ADAE34D00342B1A /* DefaultAppHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DefaultAppHelper.mm; sourceTree = "<group>"; }; ED86936E2ADAE34D00342B1A /* DefaultAppHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DefaultAppHelper.mm; sourceTree = "<group>"; };
ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = "peer-mgr-wishlist.h"; sourceTree = "<group>"; }; ED8A163D2735A8AA000D61F9 /* peer-mgr-wishlist.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = "peer-mgr-wishlist.h"; sourceTree = "<group>"; };
ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr-wishlist.cc"; sourceTree = "<group>"; }; ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-mgr-wishlist.cc"; sourceTree = "<group>"; };
ED91F00C2CBDA5D3008388AA /* libcrc32c.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcrc32c.a; sourceTree = BUILT_PRODUCTS_DIR; };
ED91F01B2CBDA72C008388AA /* crc32c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c.h; sourceTree = "<group>"; };
ED91F01E2CBDA72C008388AA /* crc32c.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crc32c.cc; sourceTree = "<group>"; };
ED91F01F2CBDA72C008388AA /* crc32c_arm64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_arm64.h; sourceTree = "<group>"; };
ED91F0202CBDA72C008388AA /* crc32c_arm64.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crc32c_arm64.cc; sourceTree = "<group>"; };
ED91F0212CBDA72C008388AA /* crc32c_arm64_check.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_arm64_check.h; sourceTree = "<group>"; };
ED91F0272CBDA72C008388AA /* crc32c_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_internal.h; sourceTree = "<group>"; };
ED91F0282CBDA72C008388AA /* crc32c_portable.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crc32c_portable.cc; sourceTree = "<group>"; };
ED91F02A2CBDA72C008388AA /* crc32c_prefetch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_prefetch.h; sourceTree = "<group>"; };
ED91F02C2CBDA72C008388AA /* crc32c_read_le.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_read_le.h; sourceTree = "<group>"; };
ED91F02E2CBDA72C008388AA /* crc32c_round_up.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_round_up.h; sourceTree = "<group>"; };
ED91F0302CBDA72C008388AA /* crc32c_sse42.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_sse42.h; sourceTree = "<group>"; };
ED91F0312CBDA72C008388AA /* crc32c_sse42.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crc32c_sse42.cc; sourceTree = "<group>"; };
ED91F0322CBDA72C008388AA /* crc32c_sse42_check.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crc32c_sse42_check.h; sourceTree = "<group>"; };
ED9862952B979AA2002F3035 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = "<group>"; }; ED9862952B979AA2002F3035 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = "<group>"; };
ED9862962B979AA2002F3035 /* Utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Utils.mm; sourceTree = "<group>"; }; ED9862962B979AA2002F3035 /* Utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Utils.mm; sourceTree = "<group>"; };
EDBA61FD2D4180D5001470F8 /* torrent-queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "torrent-queue.h"; sourceTree = "<group>"; }; EDBA61FD2D4180D5001470F8 /* torrent-queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "torrent-queue.h"; sourceTree = "<group>"; };
@@ -1466,6 +1501,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
ED91F3962CBDAAED008388AA /* libcrc32c.a in Frameworks */,
C1846BA9294F7B5A00A98F30 /* libwildmat.a in Frameworks */, C1846BA9294F7B5A00A98F30 /* libwildmat.a in Frameworks */,
C3D9062F27B7F7E200EF2386 /* libpsl.a in Frameworks */, C3D9062F27B7F7E200EF2386 /* libpsl.a in Frameworks */,
C3CEBBFC2794A12200683BE0 /* libdeflate.a in Frameworks */, C3CEBBFC2794A12200683BE0 /* libdeflate.a in Frameworks */,
@@ -1566,6 +1602,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ED91F00A2CBDA5D3008388AA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
@@ -1704,6 +1747,7 @@
C3CEBBA927949CA000683BE0 /* libdeflate.a */, C3CEBBA927949CA000683BE0 /* libdeflate.a */,
C3D9062127B7E3C900EF2386 /* libpsl.a */, C3D9062127B7E3C900EF2386 /* libpsl.a */,
C1846B9E294F7A3400A98F30 /* libwildmat.a */, C1846B9E294F7A3400A98F30 /* libwildmat.a */,
ED91F00C2CBDA5D3008388AA /* libcrc32c.a */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1727,6 +1771,7 @@
C3D9061627B7E12F00EF2386 /* libpsl */, C3D9061627B7E12F00EF2386 /* libpsl */,
C1639A751A55F52800E42033 /* b64 */, C1639A751A55F52800E42033 /* b64 */,
C1846B82294F777000A98F30 /* wildmat */, C1846B82294F777000A98F30 /* wildmat */,
ED91F2682CBDA72C008388AA /* crc32c */,
4DDBB71509E16B3F00284745 /* Libraries */, 4DDBB71509E16B3F00284745 /* Libraries */,
A2F35BBA15C5A0A100EBF632 /* Frameworks */, A2F35BBA15C5A0A100EBF632 /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */, 19C28FACFE9D520D11CA2CBB /* Products */,
@@ -2368,6 +2413,51 @@
name = "Overlay Window"; name = "Overlay Window";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
ED91F01C2CBDA72C008388AA /* crc32c */ = {
isa = PBXGroup;
children = (
ED91F01B2CBDA72C008388AA /* crc32c.h */,
);
path = crc32c;
sourceTree = "<group>";
};
ED91F01D2CBDA72C008388AA /* include */ = {
isa = PBXGroup;
children = (
ED91F01C2CBDA72C008388AA /* crc32c */,
);
path = include;
sourceTree = "<group>";
};
ED91F0362CBDA72C008388AA /* src */ = {
isa = PBXGroup;
children = (
ED91F01E2CBDA72C008388AA /* crc32c.cc */,
ED91F01F2CBDA72C008388AA /* crc32c_arm64.h */,
ED91F0202CBDA72C008388AA /* crc32c_arm64.cc */,
ED91F0212CBDA72C008388AA /* crc32c_arm64_check.h */,
ED91F0272CBDA72C008388AA /* crc32c_internal.h */,
ED91F0282CBDA72C008388AA /* crc32c_portable.cc */,
ED91F02A2CBDA72C008388AA /* crc32c_prefetch.h */,
ED91F02C2CBDA72C008388AA /* crc32c_read_le.h */,
ED91F02E2CBDA72C008388AA /* crc32c_round_up.h */,
ED91F0302CBDA72C008388AA /* crc32c_sse42.h */,
ED91F0312CBDA72C008388AA /* crc32c_sse42.cc */,
ED91F0322CBDA72C008388AA /* crc32c_sse42_check.h */,
);
path = src;
sourceTree = "<group>";
};
ED91F2682CBDA72C008388AA /* crc32c */ = {
isa = PBXGroup;
children = (
ED91F01D2CBDA72C008388AA /* include */,
ED91F0362CBDA72C008388AA /* src */,
);
name = crc32c;
path = "third-party/crc32c";
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */ /* Begin PBXHeadersBuildPhase section */
@@ -2573,6 +2663,22 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ED91F0082CBDA5D3008388AA /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
ED91F35A2CBDA72C008388AA /* crc32c.h in Headers */,
ED91F33A2CBDA72C008388AA /* crc32c_arm64.h in Headers */,
ED91F3612CBDA72C008388AA /* crc32c_arm64_check.h in Headers */,
ED91F34B2CBDA72C008388AA /* crc32c_sse42_check.h in Headers */,
ED91F3542CBDA72C008388AA /* crc32c_sse42.h in Headers */,
ED91F3432CBDA72C008388AA /* crc32c_prefetch.h in Headers */,
ED91F3502CBDA72C008388AA /* crc32c_round_up.h in Headers */,
ED91F35D2CBDA72C008388AA /* crc32c_read_le.h in Headers */,
ED91F3602CBDA72C008388AA /* crc32c_internal.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */ /* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -2605,6 +2711,7 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
ED91F3952CBDA9BD008388AA /* PBXTargetDependency */,
C1846BA7294F7B1400A98F30 /* PBXTargetDependency */, C1846BA7294F7B1400A98F30 /* PBXTargetDependency */,
C33E46A22794B3CC0090F2AA /* PBXTargetDependency */, C33E46A22794B3CC0090F2AA /* PBXTargetDependency */,
A226FDB10D0CDF6E005A7F71 /* PBXTargetDependency */, A226FDB10D0CDF6E005A7F71 /* PBXTargetDependency */,
@@ -2903,6 +3010,26 @@
productReference = C8B27BA128153F3400A22B5D /* transmission-show */; productReference = C8B27BA128153F3400A22B5D /* transmission-show */;
productType = "com.apple.product-type.tool"; productType = "com.apple.product-type.tool";
}; };
ED91F00B2CBDA5D3008388AA /* crc32c */ = {
isa = PBXNativeTarget;
buildConfigurationList = ED91F0172CBDA5D3008388AA /* Build configuration list for PBXNativeTarget "crc32c" */;
buildPhases = (
ED91F3982CBDAB95008388AA /* Copy libcrc32c headers */,
ED91F0082CBDA5D3008388AA /* Headers */,
ED91F0092CBDA5D3008388AA /* Sources */,
ED91F00A2CBDA5D3008388AA /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = crc32c;
packageProductDependencies = (
);
productName = crc32c;
productReference = ED91F00C2CBDA5D3008388AA /* libcrc32c.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
@@ -2926,6 +3053,9 @@
C3D9062027B7E3C900EF2386 = { C3D9062027B7E3C900EF2386 = {
CreatedOnToolsVersion = 13.0; CreatedOnToolsVersion = 13.0;
}; };
ED91F00B2CBDA5D3008388AA = {
CreatedOnToolsVersion = 16.0;
};
}; };
}; };
buildConfigurationList = 4DF0C59A089918A300DD8943 /* Build configuration list for PBXProject "Transmission" */; buildConfigurationList = 4DF0C59A089918A300DD8943 /* Build configuration list for PBXProject "Transmission" */;
@@ -2977,6 +3107,7 @@
C3CEBB9F27949CA000683BE0 /* deflate */, C3CEBB9F27949CA000683BE0 /* deflate */,
C3D9062027B7E3C900EF2386 /* psl */, C3D9062027B7E3C900EF2386 /* psl */,
C1846B96294F7A3400A98F30 /* wildmat */, C1846B96294F7A3400A98F30 /* wildmat */,
ED91F00B2CBDA5D3008388AA /* crc32c */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@@ -3140,6 +3271,25 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "sed 's|@LIBPSL_[A-Z_]*@|0|' < third-party/libpsl/include/libpsl.h.in > third-party/libpsl/include/libpsl.h\n\n# Generate files to be included\nPYTHON=$( command -v python3 ) || PYTHON=$( command -v python3.7 ) || PYTHON=$( command -v python2 )\n\"${PYTHON}\" \"third-party/libpsl/src/psl-make-dafsa\" --output-format=cxx+ \"third-party/libpsl/list/public_suffix_list.dat\" \"third-party/suffixes_dafsa.h\"\n"; shellScript = "sed 's|@LIBPSL_[A-Z_]*@|0|' < third-party/libpsl/include/libpsl.h.in > third-party/libpsl/include/libpsl.h\n\n# Generate files to be included\nPYTHON=$( command -v python3 ) || PYTHON=$( command -v python3.7 ) || PYTHON=$( command -v python2 )\n\"${PYTHON}\" \"third-party/libpsl/src/psl-make-dafsa\" --output-format=cxx+ \"third-party/libpsl/list/public_suffix_list.dat\" \"third-party/suffixes_dafsa.h\"\n";
}; };
ED91F3982CBDAB95008388AA /* Copy libcrc32c headers */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/third_party/macosx-crc32c-config.h",
);
name = "Copy libcrc32c headers";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
shellScript = "cd third-party/crc32c/include/crc32c\n\nif [ ! -e crc32c_config.h -a ! ../../../macosx-crc32c-config.h -ef crc32c_config.h ]; then\n ln -s ../../../macosx-crc32c-config.h crc32c_config.h;\nfi\n\n";
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -3497,6 +3647,17 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
ED91F0092CBDA5D3008388AA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
ED91F28B2CBDA72C008388AA /* crc32c.cc in Sources */,
ED91F2B52CBDA72C008388AA /* crc32c_sse42.cc in Sources */,
ED91F2F52CBDA72C008388AA /* crc32c_arm64.cc in Sources */,
ED91F3152CBDA72C008388AA /* crc32c_portable.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
@@ -3590,6 +3751,11 @@
target = 4D18389609DEC0030047D688 /* libtransmission */; target = 4D18389609DEC0030047D688 /* libtransmission */;
targetProxy = C8B27B9428153F3400A22B5D /* PBXContainerItemProxy */; targetProxy = C8B27B9428153F3400A22B5D /* PBXContainerItemProxy */;
}; };
ED91F3952CBDA9BD008388AA /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = ED91F00B2CBDA5D3008388AA /* crc32c */;
targetProxy = ED91F3942CBDA9BD008388AA /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
@@ -5133,6 +5299,36 @@
}; };
name = Release; name = Release;
}; };
ED91F0142CBDA5D3008388AA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_MASTER_OBJECT_FILE = YES;
HEADER_SEARCH_PATHS = "third-party/crc32c/include";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
ED91F0152CBDA5D3008388AA /* Release - Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_MASTER_OBJECT_FILE = YES;
HEADER_SEARCH_PATHS = "third-party/crc32c/include";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = "Release - Debug";
};
ED91F0162CBDA5D3008388AA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_MASTER_OBJECT_FILE = YES;
HEADER_SEARCH_PATHS = "third-party/crc32c/include";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@@ -5326,6 +5522,16 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug; defaultConfigurationName = Debug;
}; };
ED91F0172CBDA5D3008388AA /* Build configuration list for PBXNativeTarget "crc32c" */ = {
isa = XCConfigurationList;
buildConfigurations = (
ED91F0142CBDA5D3008388AA /* Debug */,
ED91F0152CBDA5D3008388AA /* Release - Debug */,
ED91F0162CBDA5D3008388AA /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;

30
cmake/FindCRC32C.cmake Normal file
View File

@@ -0,0 +1,30 @@
if(CRC32C_PREFER_STATIC_LIB)
set(CRC32C_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
endif()
find_path(CRC32C_INCLUDE_DIR
NAMES crc32c/crc32c.h)
find_library(CRC32C_LIBRARY
NAMES crc32c)
set(CRC32C_INCLUDE_DIRS ${CRC32C_INCLUDE_DIR})
set(CRC32C_LIBRARIES ${CRC32C_LIBRARY})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CRC32C
REQUIRED_VARS
CRC32C_INCLUDE_DIR
CRC32C_LIBRARY)
mark_as_advanced(CRC32C_INCLUDE_DIR CRC32C_LIBRARY)
if(CRC32C_PREFER_STATIC_LIB)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CRC32C_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
unset(CRC32C_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
endif()

View File

@@ -285,6 +285,7 @@ target_link_libraries(${TR_NAME}
utf8::cpp utf8::cpp
wildmat wildmat
WideInteger::WideInteger WideInteger::WideInteger
Crc32c::crc32c
$<$<BOOL:${WIN32}>:crypt32> $<$<BOOL:${WIN32}>:crypt32>
$<$<BOOL:${WIN32}>:shlwapi> $<$<BOOL:${WIN32}>:shlwapi>
"$<$<BOOL:${APPLE}>:-framework Foundation>" "$<$<BOOL:${APPLE}>:-framework Foundation>"

View File

@@ -21,6 +21,8 @@ extern "C"
#include <b64/cencode.h> #include <b64/cencode.h>
} }
#include <crc32c/crc32c.h>
#include <fmt/format.h> #include <fmt/format.h>
#include "libtransmission/crypto-utils.h" #include "libtransmission/crypto-utils.h"
@@ -239,6 +241,11 @@ std::optional<tr_sha256_digest_t> tr_sha256_from_string(std::string_view hex)
return digest; return digest;
} }
uint32_t tr_crc32c(uint8_t const* data, size_t count)
{
return crc32c::Crc32c(data, count);
}
// fallback implementation in case the system crypto library's RNG fails // fallback implementation in case the system crypto library's RNG fails
void tr_rand_buffer_std(void* buffer, size_t length) void tr_rand_buffer_std(void* buffer, size_t length)
{ {

View File

@@ -194,6 +194,11 @@ using tr_sha256_string = tr_strbuf<char, sizeof(tr_sha256_digest_t) * 2U + 1U>;
*/ */
[[nodiscard]] std::optional<tr_sha256_digest_t> tr_sha256_from_string(std::string_view hex); [[nodiscard]] std::optional<tr_sha256_digest_t> tr_sha256_from_string(std::string_view hex);
/**
* @brief Calculate CRC32-C checksum for a buffer.
*/
[[nodiscard]] uint32_t tr_crc32c(uint8_t const* data, size_t count);
// Convenience utility to efficiently get many random small values. // Convenience utility to efficiently get many random small values.
// Use this instead of making a lot of calls to tr_rand_int(). // Use this instead of making a lot of calls to tr_rand_int().
template<typename T = uint8_t, size_t N = 1024U> template<typename T = uint8_t, size_t N = 1024U>

View File

@@ -256,6 +256,64 @@ void tr_peer_info::merge(tr_peer_info& that) noexcept
} }
} }
void tr_peer_info::update_canonical_priority()
{
auto const type = client_external_address_.type;
// https://www.bittorrent.org/beps/bep_0040.html
// If the IP addresses are the same, the port numbers (16-bit integers) should be used instead:
// priority = crc32-c(sort(client_port, peer_port))
// N.B. Although not specified in BEP-40, in libtorrent's implementation, the port numbers are
// in network byte order when calculating the crc32-c result.
if (client_external_address_ == listen_address())
{
auto buf = std::array{ get_client_advertised_port_().host(), listen_port().host() };
static_assert(std::is_same_v<std::remove_reference_t<decltype(buf[0])>, uint16_t>);
std::sort(std::begin(buf), std::end(buf));
std::transform(std::begin(buf), std::end(buf), std::begin(buf), [](uint16_t p) { return htons(p); });
canonical_priority_ = tr_crc32c(reinterpret_cast<uint8_t*>(std::data(buf)), std::size(buf) * sizeof(uint16_t));
return;
}
// https://www.bittorrent.org/beps/bep_0040.html
// The formula to be used in prioritizing peers is this:
// priority = crc32-c(sort(masked_client_ip, masked_peer_ip))
// N.B. Although not specified in BEP-40, in libtorrent's implementation,
// smaller IP addresses go first.
auto const address_size = tr_address::CompactAddrBytes[type];
auto addresses = std::array{ client_external_address_, listen_address() };
std::sort(std::begin(addresses), std::end(addresses));
auto buf = std::array<std::byte, tr_address::CompactAddrMaxBytes * 2U>{};
auto const first = std::begin(buf);
auto const second = addresses[0].to_compact(first);
addresses[1].to_compact(second);
TR_ASSERT(second - first == address_size);
// https://www.bittorrent.org/beps/bep_0040.html
// For an IPv4 address, the mask to be used should be FF.FF.55.55
// unless the IP addresses are in the same /16. In that case, the
// mask to be used should be FF.FF.FF.55. If the IP addresses are
// in the same /24, the entire address should be used (mask FF.FF.FF.FF).
//
// For an IPv6 address, the mask should be derived in the same way,
// beginning with FFFF:FFFF:FFFF:5555:5555:5555:5555:5555. If the
// IP addresses are in the same /48, the mask to be used should be
// FFFF:FFFF:FFFF:FF55:5555:5555:5555:5555. If the IP addresses are
// in the same /56, the mask to be used should be
// FFFF:FFFF:FFFF:FFFF:5555:5555:5555:5555, etc...
static auto constexpr MaskStartBaseOffset = std::array{ 2U, 6U };
auto const base_idx = MaskStartBaseOffset[type];
auto const mismatch_idx = std::mismatch(first, second, second).first - first;
for (auto i = mismatch_idx >= base_idx ? mismatch_idx + 1 : base_idx; i < address_size; ++i)
{
first[i] &= std::byte{ 0x55 };
second[i] &= std::byte{ 0x55 };
}
canonical_priority_ = tr_crc32c(reinterpret_cast<uint8_t*>(std::data(buf)), address_size * 2U);
}
#define tr_logAddDebugSwarm(swarm, msg) tr_logAddDebugTor((swarm)->tor, msg) #define tr_logAddDebugSwarm(swarm, msg) tr_logAddDebugTor((swarm)->tor, msg)
#define tr_logAddTraceSwarm(swarm, msg) tr_logAddTraceTor((swarm)->tor, msg) #define tr_logAddTraceSwarm(swarm, msg) tr_logAddTraceTor((swarm)->tor, msg)
@@ -272,6 +330,12 @@ constexpr struct
return -val; return -val;
} }
// According to libtorrent, larger values has higher priority. Not specified in BEP-40.
if (auto const val = tr_compare_3way(a.get_canonical_priority(), b.get_canonical_priority()); val != 0)
{
return -val;
}
if (auto const val = tr_compare_3way(a.from_best(), b.from_best()); val != 0) if (auto const val = tr_compare_3way(a.from_best(), b.from_best()); val != 0)
{ {
return val; return val;
@@ -482,7 +546,14 @@ public:
else else
{ {
peer_info = connectable_pool peer_info = connectable_pool
.try_emplace(socket_address, std::make_shared<tr_peer_info>(socket_address, flags, from)) .try_emplace(
socket_address,
std::make_shared<tr_peer_info>(
socket_address,
flags,
from,
tor->session->global_address(socket_address.address().type).value_or(tr_address{}),
get_client_advertised_port))
.first->second; .first->second;
++stats.known_peer_from_count[from]; ++stats.known_peer_from_count[from];
} }
@@ -624,6 +695,11 @@ public:
tr_peerMsgs* optimistic = nullptr; /* the optimistic peer, or nullptr if none */ tr_peerMsgs* optimistic = nullptr; /* the optimistic peer, or nullptr if none */
std::function<tr_port()> const get_client_advertised_port = [this]
{
return tor->session->advertisedPeerPort();
};
private: private:
void rebuild_webseeds() void rebuild_webseeds()
{ {
@@ -1327,7 +1403,11 @@ void create_bit_torrent_peer(
if (result.io->is_incoming()) if (result.io->is_incoming())
{ {
info = std::make_shared<tr_peer_info>(socket_address.address(), 0U, TR_PEER_FROM_INCOMING); info = std::make_shared<tr_peer_info>(
socket_address.address(),
0U,
TR_PEER_FROM_INCOMING,
swarm->get_client_advertised_port);
} }
if (!info) if (!info)

View File

@@ -61,20 +61,29 @@ enum : uint8_t
class tr_peer_info class tr_peer_info
{ {
public: public:
tr_peer_info(tr_socket_address socket_address, uint8_t pex_flags, tr_peer_from from) tr_peer_info(
tr_socket_address socket_address,
uint8_t pex_flags,
tr_peer_from from,
tr_address client_external_address,
std::function<tr_port()> get_client_advertised_port)
: listen_socket_address_{ socket_address } : listen_socket_address_{ socket_address }
, client_external_address_{ std::move(client_external_address) }
, from_first_{ from } , from_first_{ from }
, from_best_{ from } , from_best_{ from }
, get_client_advertised_port_{ std::move(get_client_advertised_port) }
{ {
TR_ASSERT(!std::empty(socket_address.port())); TR_ASSERT(!std::empty(socket_address.port()));
++n_known_connectable; ++n_known_connectable;
set_pex_flags(pex_flags); set_pex_flags(pex_flags);
update_canonical_priority();
} }
tr_peer_info(tr_address address, uint8_t pex_flags, tr_peer_from from) tr_peer_info(tr_address address, uint8_t pex_flags, tr_peer_from from, std::function<tr_port()> get_client_advertised_port)
: listen_socket_address_{ address, tr_port{} } : listen_socket_address_{ address, tr_port{} }
, from_first_{ from } , from_first_{ from }
, from_best_{ from } , from_best_{ from }
, get_client_advertised_port_{ std::move(get_client_advertised_port) }
{ {
set_pex_flags(pex_flags); set_pex_flags(pex_flags);
} }
@@ -117,14 +126,15 @@ public:
void set_listen_port(tr_port port_in) noexcept void set_listen_port(tr_port port_in) noexcept
{ {
if (!std::empty(port_in)) if (auto& port = listen_socket_address_.port_; !std::empty(port_in) && port_in != port)
{ {
auto& port = listen_socket_address_.port_; if (std::empty(port))
if (std::empty(port)) // increment known connectable peers if we did not know the listening port of this peer before
{ {
// increment known connectable peers if we did not know the listening port of this peer before
++n_known_connectable; ++n_known_connectable;
} }
port = port_in; port = port_in;
update_canonical_priority();
} }
} }
@@ -474,6 +484,30 @@ public:
// --- // ---
void maybe_update_canonical_priority(tr_address client_external_address)
{
if (!client_external_address.is_valid() || client_external_address.type != listen_address().type)
{
return;
}
if (client_external_address == client_external_address_)
{
return;
}
client_external_address_ = client_external_address;
update_canonical_priority();
}
[[nodiscard]] constexpr auto get_canonical_priority() const noexcept
{
return canonical_priority_;
}
// ---
// merge two peer info objects that supposedly describes the same peer // merge two peer info objects that supposedly describes the same peer
void merge(tr_peer_info& that) noexcept; void merge(tr_peer_info& that) noexcept;
@@ -517,6 +551,8 @@ private:
} }
} }
void update_canonical_priority();
// the minimum we'll wait before attempting to reconnect to a peer // the minimum we'll wait before attempting to reconnect to a peer
static auto constexpr MinimumReconnectIntervalSecs = time_t{ 5U }; static auto constexpr MinimumReconnectIntervalSecs = time_t{ 5U };
static auto constexpr InactiveThresSecs = time_t{ 60 * 60 }; static auto constexpr InactiveThresSecs = time_t{ 60 * 60 };
@@ -525,6 +561,7 @@ private:
// if the port is 0, it SHOULD mean we don't know this peer's listen socket address // if the port is 0, it SHOULD mean we don't know this peer's listen socket address
tr_socket_address listen_socket_address_; tr_socket_address listen_socket_address_;
tr_address client_external_address_;
time_t connection_attempted_at_ = {}; time_t connection_attempted_at_ = {};
time_t connection_changed_at_ = {}; time_t connection_changed_at_ = {};
@@ -542,12 +579,17 @@ private:
uint8_t num_consecutive_fruitless_ = {}; uint8_t num_consecutive_fruitless_ = {};
uint8_t pex_flags_ = {}; uint8_t pex_flags_ = {};
// https://www.bittorrent.org/beps/bep_0040.html
uint32_t canonical_priority_ = {};
bool is_banned_ = false; bool is_banned_ = false;
bool is_connected_ = false; bool is_connected_ = false;
bool is_seed_ = false; bool is_seed_ = false;
bool is_upload_only_ = false; bool is_upload_only_ = false;
std::unique_ptr<tr_handshake> outgoing_handshake_; std::unique_ptr<tr_handshake> outgoing_handshake_;
std::function<tr_port()> const get_client_advertised_port_;
}; };
struct tr_pex struct tr_pex

View File

@@ -1307,6 +1307,27 @@ void tr_peerMsgsImpl::parse_ltep_handshake(MessageReader& payload)
set_user_agent(tr_interned_string{ tr_strv_convert_utf8(sv) }); set_user_agent(tr_interned_string{ tr_strv_convert_utf8(sv) });
} }
// https://www.bittorrent.org/beps/bep_0010.html
// A string containing the compact representation of the ip address
// this peer sees you as. i.e. this is the receiver's external ip
// address (no port is included). This may be either an IPv4 (4 bytes)
// or an IPv6 (16 bytes) address.
if (auto sv = std::string_view{}; tr_variantDictFindStrView(&*var, TR_KEY_yourip, &sv))
{
auto const* const bytes = reinterpret_cast<std::byte const*>(std::data(sv));
switch (std::size(sv))
{
case tr_address::CompactAddrBytes[TR_AF_INET]:
peer_info->maybe_update_canonical_priority(tr_address::from_compact_ipv4(bytes).first);
break;
case tr_address::CompactAddrBytes[TR_AF_INET6]:
peer_info->maybe_update_canonical_priority(tr_address::from_compact_ipv6(bytes).first);
break;
default:
break;
}
}
/* get peer's listening port */ /* get peer's listening port */
if (auto p = int64_t{}; tr_variantDictFindInt(&*var, TR_KEY_p, &p) && p > 0) if (auto p = int64_t{}; tr_variantDictFindInt(&*var, TR_KEY_p, &p) && p > 0)
{ {

View File

@@ -6,6 +6,7 @@
#include <array> #include <array>
#include <ctime> #include <ctime>
#include <optional> #include <optional>
#include <string_view>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
@@ -16,6 +17,8 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
using namespace std::literals;
using PeerInfoTest = ::testing::Test; using PeerInfoTest = ::testing::Test;
TEST_F(PeerInfoTest, mergeConnectable) TEST_F(PeerInfoTest, mergeConnectable)
@@ -54,8 +57,8 @@ TEST_F(PeerInfoTest, mergeConnectable)
{ {
auto const& [this_connectable, this_connected, that_connectable, that_connected] = condition; auto const& [this_connectable, this_connected, that_connectable, that_connected] = condition;
auto info_this = tr_peer_info{ tr_address{}, 0, TR_PEER_FROM_PEX }; auto info_this = tr_peer_info{ tr_address{}, 0, TR_PEER_FROM_PEX, {} };
auto info_that = tr_peer_info{ tr_address{}, 0, TR_PEER_FROM_PEX }; auto info_that = tr_peer_info{ tr_address{}, 0, TR_PEER_FROM_PEX, {} };
if (this_connectable) if (this_connectable)
{ {
@@ -74,3 +77,86 @@ TEST_F(PeerInfoTest, mergeConnectable)
EXPECT_EQ(info_this.is_connectable(), result); EXPECT_EQ(info_this.is_connectable(), result);
} }
} }
TEST_F(PeerInfoTest, updateCanonicalPriority)
{
static auto constexpr Tests = std::array{
// crc32-c(624C14007BD50000), default mask
std::tuple{ "123.213.32.10:51413"sv, "98.76.54.32:6881"sv, uint32_t{ 0xEC2D7224 } },
// crc32-c(7BD520007BD52140), /16 mask
std::tuple{ "123.213.32.10:51413"sv, "123.213.33.234:6881"sv, uint32_t{ 0xF61850A9 } },
// crc32-c(7BD5200A7BD520EA), /24 mask
std::tuple{ "123.213.32.10:51413"sv, "123.213.32.234:6881"sv, uint32_t{ 0x99568189 } },
// crc32-c(1AE1C8D5), peer port
std::tuple{ "123.213.32.10:51413"sv, "123.213.32.10:6881"sv, uint32_t{ 0x9F852E9F } },
// crc32-c(2A032880F177010550441004000005542A032880F27701455044100400000145), default mask
std::tuple{ "[2a03:2880:f277:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:185:face:b00c:0:25de]:6881"sv,
uint32_t{ 0xE4D0F2E2 } },
// crc32-c(2A032880F177F14550441004000001452A032880F177F2055044100400000554), /48 mask
std::tuple{ "[2a03:2880:f177:f1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:f285:face:b00c:0:25de]:6881"sv,
uint32_t{ 0xCD993D35 } },
// crc32-c(2A032880F177018550441004000005542A032880F17701CD5044100400000145), /56 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:185:face:b00c:0:25de]:6881"sv,
uint32_t{ 0xF47E9889 } },
// crc32-c(2A032880F17701CDFA441004000001452A032880F17701CDFB44100400000554), /64 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:fbce:b00c:0:25de]:6881"sv,
uint32_t{ 0x2BC35C30 } },
// crc32-c(2A032880F17701CDFACE1004000001452A032880F17701CDFACF100400000554), /72 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:facf:b00c:0:25de]:6881"sv,
uint32_t{ 0x04BFAA11 } },
// crc32-c(2A032880F17701CDFACEB005000005542A032880F17701CDFACEB50400000145), /80 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b50c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:face:b00d:0:25de]:6881"sv,
uint32_t{ 0xA0F96012 } },
// crc32-c(2A032880F17701CDFACEB00C000001452A032880F17701CDFACEB00D00000554), /88 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:face:b00d:0:25de]:6881"sv,
uint32_t{ 0x47FC5342 } },
// crc32-c(2A032880F17701CDFACEB00C005505542A032880F17701CDFACEB00CFF000145), /96 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:ff00:167]:51413"sv,
"[2a03:2880:f177:1cd:face:b00c:ff:25de]:6881"sv,
uint32_t{ 0x51BB5B16 } },
// crc32-c(2A032880F17701CDFACEB00C000001452A032880F17701CDFACEB00C00010554), /104 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:face:b00c:1:25de]:6881"sv,
uint32_t{ 0xDAACAE90 } },
// crc32-c(2A032880F17701CDFACEB00C000001452A032880F17701CDFACEB00C00002554), /112 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:face:b00c:0:25de]:6881"sv,
uint32_t{ 0x0066DFEC } },
// crc32-c(2A032880F17701CDFACEB00C000001452A032880F17701CDFACEB00C00001654), /120 mask
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:51413"sv,
"[2a03:2880:f177:1cd:face:b00c:0:16de]:6881"sv,
uint32_t{ 0x74CF65F6 } },
// crc32-c(1AE11AE2), peer port
std::tuple{ "[2a03:2880:f177:1cd:face:b00c:0:167]:6882"sv,
"[2a03:2880:f177:1cd:face:b00c:0:167]:6881"sv,
uint32_t{ 0x67F8FE57 } },
};
for (auto [client_sockaddr_str, peer_sockaddr_str, expected] : Tests)
{
auto client_sockaddr = tr_socket_address::from_string(client_sockaddr_str);
auto peer_sockaddr = tr_socket_address::from_string(peer_sockaddr_str);
EXPECT_TRUE(client_sockaddr && peer_sockaddr) << "Test case is bugged";
if (!client_sockaddr || !peer_sockaddr)
{
continue;
}
auto const info = tr_peer_info{ *peer_sockaddr,
0,
TR_PEER_FROM_PEX,
client_sockaddr->address(),
[&client_sockaddr]
{
return client_sockaddr->port();
} };
EXPECT_EQ(info.get_canonical_priority(), expected);
}
}

1
third-party/crc32c vendored Submodule

Submodule third-party/crc32c added at 2bbb3be42e

48
third-party/macosx-crc32c-config.h vendored Normal file
View File

@@ -0,0 +1,48 @@
// Copyright 2017 The CRC32C Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#ifndef CRC32C_CRC32C_CONFIG_H_
#define CRC32C_CRC32C_CONFIG_H_
// Define to 1 if building for a big-endian platform.
#undef BYTE_ORDER_BIG_ENDIAN
// Define to 1 if the compiler has the __builtin_prefetch intrinsic.
#if __has_builtin(__builtin_prefetch)
#define HAVE_BUILTIN_PREFETCH 1
#else
#undef HAVE_BUILTIN_PREFETCH
#endif
// Define to 1 if targeting X86 and the compiler has the _mm_prefetch intrinsic.
#undef HAVE_MM_PREFETCH
// Define to 1 if targeting X86 and the compiler has the _mm_crc32_u{8,32,64}
// intrinsics.
#if defined(__x86_64__)
#define HAVE_SSE42 1
#else
#undef HAVE_SSE42
#endif
// Define to 1 if targeting ARM and the compiler has the __crc32c{b,h,w,d} and
// the vmull_p64 intrinsics.
#if defined(__aarch64__)
#define HAVE_ARM64_CRC32C 1
#else
#undef HAVE_ARM64_CRC32C
#endif
// Define to 1 if the system libraries have the getauxval function in the
// <sys/auxv.h> header. Should be true on Linux and Android API level 20+.
#undef HAVE_STRONG_GETAUXVAL
// Define to 1 if the compiler supports defining getauxval as a weak symbol.
// Should be true for any compiler that supports __attribute__((weak)).
#undef HAVE_WEAK_GETAUXVAL
// Define to 1 if CRC32C tests have been built with Google Logging.
#undef CRC32C_TESTS_BUILT_WITH_GLOG
#endif // CRC32C_CRC32C_CONFIG_H_