refactor: port forwarding (#3850)
* refactor: rename state enum type as tr_port_forwarding_state * chore: use snake_case for tr_shared struct fields * refactor: replace tr_shared with tr_port_forwarding * refactor: make tr_natpmp_state an enum class * refactor: uniform naming for port-forwarding module * refactor: move output-only parameters in tr_natpmp::pulse() to return struct * fix: use a nullptr multicastif if bindaddr is empty * chore: use PascalCase for enum class values * chore: clean up port-forwarding #includes * chore: remove unused tr_port_forwarding::peerPort()
This commit is contained in:
parent
a5ca289f41
commit
bf156a97cf
|
@ -251,7 +251,7 @@
|
|||
A2EA52321686AC0D00180493 /* quark.h in Headers */ = {isa = PBXBuildFile; fileRef = A2EA52301686AC0D00180493 /* quark.h */; };
|
||||
A2EB2E7715C8CF2C00FBD5B4 /* QuickLookPlugin.qlgenerator in CopyFiles */ = {isa = PBXBuildFile; fileRef = A2F35BB915C5A0A100EBF632 /* QuickLookPlugin.qlgenerator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
A2ED7D8F0CEF431B00970975 /* FilterButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = A2ED7D8E0CEF431B00970975 /* FilterButton.mm */; };
|
||||
A2EE726F14DCCC950093C99A /* natpmp_local.h in Headers */ = {isa = PBXBuildFile; fileRef = A2EE726E14DCCC950093C99A /* natpmp_local.h */; };
|
||||
A2EE726F14DCCC950093C99A /* port-forwarding-natpmp.h in Headers */ = {isa = PBXBuildFile; fileRef = A2EE726E14DCCC950093C99A /* port-forwarding-natpmp.h */; };
|
||||
A2F35BBC15C5A0A100EBF632 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A2F35BBB15C5A0A100EBF632 /* QuickLook.framework */; };
|
||||
A2F35BC815C5A0A100EBF632 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A2F35BC615C5A0A100EBF632 /* InfoPlist.strings */; };
|
||||
A2F35BCA15C5A0A100EBF632 /* GenerateThumbnailForURL.mm in Sources */ = {isa = PBXBuildFile; fileRef = A2F35BC915C5A0A100EBF632 /* GenerateThumbnailForURL.mm */; };
|
||||
|
@ -292,8 +292,8 @@
|
|||
BEFC1E290C07861A00B0BB3C /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF00C07861A00B0BB3C /* version.h */; };
|
||||
BEFC1E2A0C07861A00B0BB3C /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF10C07861A00B0BB3C /* utils.h */; };
|
||||
BEFC1E2B0C07861A00B0BB3C /* utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF20C07861A00B0BB3C /* utils.cc */; };
|
||||
BEFC1E2C0C07861A00B0BB3C /* upnp.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF30C07861A00B0BB3C /* upnp.h */; };
|
||||
BEFC1E2D0C07861A00B0BB3C /* upnp.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF40C07861A00B0BB3C /* upnp.cc */; };
|
||||
BEFC1E2C0C07861A00B0BB3C /* port-forwarding-upnp.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF30C07861A00B0BB3C /* port-forwarding-upnp.h */; };
|
||||
BEFC1E2D0C07861A00B0BB3C /* port-forwarding-upnp.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF40C07861A00B0BB3C /* port-forwarding-upnp.cc */; };
|
||||
BEFC1E2F0C07861A00B0BB3C /* session.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF60C07861A00B0BB3C /* session.cc */; };
|
||||
BEFC1E320C07861A00B0BB3C /* torrent.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF90C07861A00B0BB3C /* torrent.cc */; };
|
||||
BEFC1E350C07861A00B0BB3C /* port-forwarding.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DFC0C07861A00B0BB3C /* port-forwarding.h */; };
|
||||
|
@ -302,7 +302,7 @@
|
|||
BEFC1E3C0C07861A00B0BB3C /* platform.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E030C07861A00B0BB3C /* platform.cc */; };
|
||||
BEFC1E450C07861A00B0BB3C /* net.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E0C0C07861A00B0BB3C /* net.h */; };
|
||||
BEFC1E460C07861A00B0BB3C /* net.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E0D0C07861A00B0BB3C /* net.cc */; };
|
||||
BEFC1E480C07861A00B0BB3C /* natpmp.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E0F0C07861A00B0BB3C /* natpmp.cc */; };
|
||||
BEFC1E480C07861A00B0BB3C /* port-forwarding-natpmp.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E0F0C07861A00B0BB3C /* port-forwarding-natpmp.cc */; };
|
||||
BEFC1E4D0C07861A00B0BB3C /* session.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E140C07861A00B0BB3C /* session.h */; };
|
||||
BEFC1E4E0C07861A00B0BB3C /* inout.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E150C07861A00B0BB3C /* inout.h */; };
|
||||
BEFC1E4F0C07861A00B0BB3C /* inout.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E160C07861A00B0BB3C /* inout.cc */; };
|
||||
|
@ -1009,7 +1009,7 @@
|
|||
A2EA8E3E0CC3C9830081201C /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
A2ED7D8D0CEF431B00970975 /* FilterButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilterButton.h; sourceTree = "<group>"; };
|
||||
A2ED7D8E0CEF431B00970975 /* FilterButton.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FilterButton.mm; sourceTree = "<group>"; };
|
||||
A2EE726E14DCCC950093C99A /* natpmp_local.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = natpmp_local.h; sourceTree = "<group>"; };
|
||||
A2EE726E14DCCC950093C99A /* port-forwarding-natpmp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = port-forwarding-natpmp.h; sourceTree = "<group>"; };
|
||||
A2F35BB915C5A0A100EBF632 /* QuickLookPlugin.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QuickLookPlugin.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A2F35BBB15C5A0A100EBF632 /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = System/Library/Frameworks/QuickLook.framework; sourceTree = SDKROOT; };
|
||||
A2F35BBD15C5A0A100EBF632 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; };
|
||||
|
@ -1062,8 +1062,8 @@
|
|||
BEFC1DF00C07861A00B0BB3C /* version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
|
||||
BEFC1DF10C07861A00B0BB3C /* utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
|
||||
BEFC1DF20C07861A00B0BB3C /* utils.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cc; sourceTree = "<group>"; };
|
||||
BEFC1DF30C07861A00B0BB3C /* upnp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = upnp.h; sourceTree = "<group>"; };
|
||||
BEFC1DF40C07861A00B0BB3C /* upnp.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = upnp.cc; sourceTree = "<group>"; };
|
||||
BEFC1DF30C07861A00B0BB3C /* port-forwarding-upnp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = port-forwarding-upnp.h; sourceTree = "<group>"; };
|
||||
BEFC1DF40C07861A00B0BB3C /* port-forwarding-upnp.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = port-forwarding-upnp.cc; sourceTree = "<group>"; };
|
||||
BEFC1DF50C07861A00B0BB3C /* transmission.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = transmission.h; sourceTree = "<group>"; };
|
||||
BEFC1DF60C07861A00B0BB3C /* session.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = session.cc; sourceTree = "<group>"; };
|
||||
BEFC1DF90C07861A00B0BB3C /* torrent.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = torrent.cc; sourceTree = "<group>"; };
|
||||
|
@ -1073,7 +1073,7 @@
|
|||
BEFC1E030C07861A00B0BB3C /* platform.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = platform.cc; sourceTree = "<group>"; };
|
||||
BEFC1E0C0C07861A00B0BB3C /* net.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = net.h; sourceTree = "<group>"; };
|
||||
BEFC1E0D0C07861A00B0BB3C /* net.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = net.cc; sourceTree = "<group>"; };
|
||||
BEFC1E0F0C07861A00B0BB3C /* natpmp.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = natpmp.cc; sourceTree = "<group>"; };
|
||||
BEFC1E0F0C07861A00B0BB3C /* port-forwarding-natpmp.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = port-forwarding-natpmp.cc; sourceTree = "<group>"; };
|
||||
BEFC1E140C07861A00B0BB3C /* session.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = "<group>"; };
|
||||
BEFC1E150C07861A00B0BB3C /* inout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = inout.h; sourceTree = "<group>"; };
|
||||
BEFC1E160C07861A00B0BB3C /* inout.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = inout.cc; sourceTree = "<group>"; };
|
||||
|
@ -1650,8 +1650,8 @@
|
|||
A2BE9C4E0C1E4ADA002D16E6 /* makemeta.cc */,
|
||||
A2BE9C4F0C1E4ADA002D16E6 /* makemeta.h */,
|
||||
CAB35C62252F6F5E00552A55 /* mime-types.h */,
|
||||
A2EE726E14DCCC950093C99A /* natpmp_local.h */,
|
||||
BEFC1E0F0C07861A00B0BB3C /* natpmp.cc */,
|
||||
A2EE726E14DCCC950093C99A /* port-forwarding-natpmp.h */,
|
||||
BEFC1E0F0C07861A00B0BB3C /* port-forwarding-natpmp.cc */,
|
||||
BEFC1E0D0C07861A00B0BB3C /* net.cc */,
|
||||
BEFC1E0C0C07861A00B0BB3C /* net.h */,
|
||||
BEFC1E1A0C07861A00B0BB3C /* open-files.cc */,
|
||||
|
@ -1723,8 +1723,8 @@
|
|||
BEFC1DF50C07861A00B0BB3C /* transmission.h */,
|
||||
A24621360C769CF400088E81 /* trevent.cc */,
|
||||
A24621350C769CF400088E81 /* trevent.h */,
|
||||
BEFC1DF40C07861A00B0BB3C /* upnp.cc */,
|
||||
BEFC1DF30C07861A00B0BB3C /* upnp.h */,
|
||||
BEFC1DF40C07861A00B0BB3C /* port-forwarding-upnp.cc */,
|
||||
BEFC1DF30C07861A00B0BB3C /* port-forwarding-upnp.h */,
|
||||
BEFC1DF20C07861A00B0BB3C /* utils.cc */,
|
||||
BEFC1DF10C07861A00B0BB3C /* utils.h */,
|
||||
A25BFD63167BED3B0039D1AA /* variant-benc.cc */,
|
||||
|
@ -2149,7 +2149,7 @@
|
|||
C1077A51183EB29600634C22 /* file.h in Headers */,
|
||||
BEFC1E290C07861A00B0BB3C /* version.h in Headers */,
|
||||
BEFC1E2A0C07861A00B0BB3C /* utils.h in Headers */,
|
||||
BEFC1E2C0C07861A00B0BB3C /* upnp.h in Headers */,
|
||||
BEFC1E2C0C07861A00B0BB3C /* port-forwarding-upnp.h in Headers */,
|
||||
A2AAB65D0DE0CF6200E04DDA /* rpcimpl.h in Headers */,
|
||||
A2AAB65E0DE0CF6200E04DDA /* rpc-server.h in Headers */,
|
||||
BEFC1E350C07861A00B0BB3C /* port-forwarding.h in Headers */,
|
||||
|
@ -2208,7 +2208,7 @@
|
|||
C1077A4F183EB29600634C22 /* error.h in Headers */,
|
||||
A2679295130E00A000CB7464 /* tr-utp.h in Headers */,
|
||||
A23F29A1132A447400E9A83B /* announcer-common.h in Headers */,
|
||||
A2EE726F14DCCC950093C99A /* natpmp_local.h in Headers */,
|
||||
A2EE726F14DCCC950093C99A /* port-forwarding-natpmp.h in Headers */,
|
||||
A2D77451154CC25700A62B93 /* WebSeedTableView.h in Headers */,
|
||||
A2A7B32B164F87D400B98C65 /* jsonsl.h in Headers */,
|
||||
A25BFD6A167BED3B0039D1AA /* variant-common.h in Headers */,
|
||||
|
@ -2873,7 +2873,7 @@
|
|||
files = (
|
||||
BEFC1E2B0C07861A00B0BB3C /* utils.cc in Sources */,
|
||||
A2AAB65F0DE0CF6200E04DDA /* rpcimpl.cc in Sources */,
|
||||
BEFC1E2D0C07861A00B0BB3C /* upnp.cc in Sources */,
|
||||
BEFC1E2D0C07861A00B0BB3C /* port-forwarding-upnp.cc in Sources */,
|
||||
A2AAB65C0DE0CF6200E04DDA /* rpc-server.cc in Sources */,
|
||||
ED8A16402735A8AA000D61F9 /* peer-mgr-active-requests.cc in Sources */,
|
||||
BEFC1E2F0C07861A00B0BB3C /* session.cc in Sources */,
|
||||
|
@ -2884,7 +2884,7 @@
|
|||
BEFC1E3C0C07861A00B0BB3C /* platform.cc in Sources */,
|
||||
BEFC1E460C07861A00B0BB3C /* net.cc in Sources */,
|
||||
C1033E091A3279B800EF44D8 /* crypto-utils.cc in Sources */,
|
||||
BEFC1E480C07861A00B0BB3C /* natpmp.cc in Sources */,
|
||||
BEFC1E480C07861A00B0BB3C /* port-forwarding-natpmp.cc in Sources */,
|
||||
C1077A4E183EB29600634C22 /* error.cc in Sources */,
|
||||
BEFC1E4F0C07861A00B0BB3C /* inout.cc in Sources */,
|
||||
BEFC1E530C07861A00B0BB3C /* open-files.cc in Sources */,
|
||||
|
|
|
@ -33,7 +33,6 @@ set(PROJECT_FILES
|
|||
log.cc
|
||||
magnet-metainfo.cc
|
||||
makemeta.cc
|
||||
natpmp.cc
|
||||
net.cc
|
||||
open-files.cc
|
||||
peer-io.cc
|
||||
|
@ -44,6 +43,8 @@ set(PROJECT_FILES
|
|||
peer-msgs.cc
|
||||
platform-quota.cc
|
||||
platform.cc
|
||||
port-forwarding-natpmp.cc
|
||||
port-forwarding-upnp.cc
|
||||
port-forwarding.cc
|
||||
quark.cc
|
||||
resume.cc
|
||||
|
@ -69,7 +70,6 @@ set(PROJECT_FILES
|
|||
tr-udp.cc
|
||||
tr-utp.cc
|
||||
trevent.cc
|
||||
upnp.cc
|
||||
utils.cc
|
||||
variant-benc.cc
|
||||
variant-json.cc
|
||||
|
@ -175,7 +175,6 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS
|
|||
lru-cache.h
|
||||
magnet-metainfo.h
|
||||
mime-types.h
|
||||
natpmp_local.h
|
||||
net.h
|
||||
open-files.h
|
||||
peer-common.h
|
||||
|
@ -188,6 +187,8 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS
|
|||
peer-socket.h
|
||||
platform-quota.h
|
||||
platform.h
|
||||
port-forwarding-natpmp.h
|
||||
port-forwarding-upnp.h
|
||||
port-forwarding.h
|
||||
resume.h
|
||||
rpc-server.h
|
||||
|
@ -203,7 +204,6 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS
|
|||
tr-lpd.h
|
||||
tr-utp.h
|
||||
trevent.h
|
||||
upnp.h
|
||||
variant-common.h
|
||||
verify.h
|
||||
version.h
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
#define ENABLE_STRNATPMPERR
|
||||
#include "natpmp.h"
|
||||
|
||||
#define LIBTRANSMISSION_PORT_FORWARDING_MODULE
|
||||
|
||||
#include "transmission.h"
|
||||
#include "natpmp_local.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "net.h" /* tr_netCloseSocket */
|
||||
#include "port-forwarding-natpmp.h"
|
||||
#include "port-forwarding.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -55,23 +57,23 @@ void tr_natpmp::setCommandTime()
|
|||
command_time_ = tr_time() + CommandWaitSecs;
|
||||
}
|
||||
|
||||
tr_port_forwarding tr_natpmp::pulse(tr_port private_port, bool is_enabled, tr_port* public_port, tr_port* real_private_port)
|
||||
tr_natpmp::PulseResult tr_natpmp::pulse(tr_port private_port, bool is_enabled)
|
||||
{
|
||||
if (is_enabled && state_ == TR_NATPMP_DISCOVER)
|
||||
if (is_enabled && state_ == State::Discover)
|
||||
{
|
||||
int val = initnatpmp(&natpmp_, 0, 0);
|
||||
logVal("initnatpmp", val);
|
||||
val = sendpublicaddressrequest(&natpmp_);
|
||||
logVal("sendpublicaddressrequest", val);
|
||||
state_ = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_PUB;
|
||||
state_ = val < 0 ? State::Err : State::RecvPub;
|
||||
has_discovered_ = true;
|
||||
setCommandTime();
|
||||
}
|
||||
|
||||
if (state_ == TR_NATPMP_RECV_PUB && canSendCommand())
|
||||
if (state_ == State::RecvPub && canSendCommand())
|
||||
{
|
||||
natpmpresp_t response;
|
||||
int const val = readnatpmpresponseorretry(&natpmp_, &response);
|
||||
auto const val = readnatpmpresponseorretry(&natpmp_, &response);
|
||||
logVal("readnatpmpresponseorretry", val);
|
||||
|
||||
if (val >= 0)
|
||||
|
@ -79,31 +81,31 @@ tr_port_forwarding tr_natpmp::pulse(tr_port private_port, bool is_enabled, tr_po
|
|||
auto str = std::array<char, 128>{};
|
||||
evutil_inet_ntop(AF_INET, &response.pnu.publicaddress.addr, std::data(str), std::size(str));
|
||||
tr_logAddInfo(fmt::format(_("Found public address '{address}'"), fmt::arg("address", std::data(str))));
|
||||
state_ = TR_NATPMP_IDLE;
|
||||
state_ = State::Idle;
|
||||
}
|
||||
else if (val != NATPMP_TRYAGAIN)
|
||||
{
|
||||
state_ = TR_NATPMP_ERR;
|
||||
state_ = State::Err;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state_ == TR_NATPMP_IDLE || state_ == TR_NATPMP_ERR) && is_mapped_ && (!is_enabled || private_port_ != private_port))
|
||||
if ((state_ == State::Idle || state_ == State::Err) && is_mapped_ && (!is_enabled || private_port_ != private_port))
|
||||
{
|
||||
state_ = TR_NATPMP_SEND_UNMAP;
|
||||
state_ = State::SendUnmap;
|
||||
}
|
||||
|
||||
if (state_ == TR_NATPMP_SEND_UNMAP && canSendCommand())
|
||||
if (state_ == State::SendUnmap && canSendCommand())
|
||||
{
|
||||
int const val = sendnewportmappingrequest(&natpmp_, NATPMP_PROTOCOL_TCP, private_port_.host(), public_port_.host(), 0);
|
||||
auto const val = sendnewportmappingrequest(&natpmp_, NATPMP_PROTOCOL_TCP, private_port_.host(), public_port_.host(), 0);
|
||||
logVal("sendnewportmappingrequest", val);
|
||||
state_ = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_UNMAP;
|
||||
state_ = val < 0 ? State::Err : State::RecvUnmap;
|
||||
setCommandTime();
|
||||
}
|
||||
|
||||
if (state_ == TR_NATPMP_RECV_UNMAP)
|
||||
if (state_ == State::RecvUnmap)
|
||||
{
|
||||
natpmpresp_t resp;
|
||||
int const val = readnatpmpresponseorretry(&natpmp_, &resp);
|
||||
auto resp = natpmpresp_t{};
|
||||
auto const val = readnatpmpresponseorretry(&natpmp_, &resp);
|
||||
logVal("readnatpmpresponseorretry", val);
|
||||
|
||||
if (val >= 0)
|
||||
|
@ -116,50 +118,50 @@ tr_port_forwarding tr_natpmp::pulse(tr_port private_port, bool is_enabled, tr_po
|
|||
{
|
||||
private_port_.clear();
|
||||
public_port_.clear();
|
||||
state_ = TR_NATPMP_IDLE;
|
||||
state_ = State::Idle;
|
||||
is_mapped_ = false;
|
||||
}
|
||||
}
|
||||
else if (val != NATPMP_TRYAGAIN)
|
||||
{
|
||||
state_ = TR_NATPMP_ERR;
|
||||
state_ = State::Err;
|
||||
}
|
||||
}
|
||||
|
||||
if (state_ == TR_NATPMP_IDLE)
|
||||
if (state_ == State::Idle)
|
||||
{
|
||||
if (is_enabled && !is_mapped_ && has_discovered_)
|
||||
{
|
||||
state_ = TR_NATPMP_SEND_MAP;
|
||||
state_ = State::SendMap;
|
||||
}
|
||||
else if (is_mapped_ && tr_time() >= renew_time_)
|
||||
{
|
||||
state_ = TR_NATPMP_SEND_MAP;
|
||||
state_ = State::SendMap;
|
||||
}
|
||||
}
|
||||
|
||||
if (state_ == TR_NATPMP_SEND_MAP && canSendCommand())
|
||||
if (state_ == State::SendMap && canSendCommand())
|
||||
{
|
||||
int const val = sendnewportmappingrequest(
|
||||
auto const val = sendnewportmappingrequest(
|
||||
&natpmp_,
|
||||
NATPMP_PROTOCOL_TCP,
|
||||
private_port.host(),
|
||||
private_port.host(),
|
||||
LifetimeSecs);
|
||||
logVal("sendnewportmappingrequest", val);
|
||||
state_ = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_MAP;
|
||||
state_ = val < 0 ? State::Err : State::RecvMap;
|
||||
setCommandTime();
|
||||
}
|
||||
|
||||
if (state_ == TR_NATPMP_RECV_MAP)
|
||||
if (state_ == State::RecvMap)
|
||||
{
|
||||
natpmpresp_t resp;
|
||||
int const val = readnatpmpresponseorretry(&natpmp_, &resp);
|
||||
auto resp = natpmpresp_t{};
|
||||
auto const val = readnatpmpresponseorretry(&natpmp_, &resp);
|
||||
logVal("readnatpmpresponseorretry", val);
|
||||
|
||||
if (val >= 0)
|
||||
{
|
||||
state_ = TR_NATPMP_IDLE;
|
||||
state_ = State::Idle;
|
||||
is_mapped_ = true;
|
||||
renew_time_ = tr_time() + (resp.pnu.newportmapping.lifetime / 2);
|
||||
private_port_ = tr_port::fromHost(resp.pnu.newportmapping.privateport);
|
||||
|
@ -168,30 +170,28 @@ tr_port_forwarding tr_natpmp::pulse(tr_port private_port, bool is_enabled, tr_po
|
|||
}
|
||||
else if (val != NATPMP_TRYAGAIN)
|
||||
{
|
||||
state_ = TR_NATPMP_ERR;
|
||||
state_ = State::Err;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state_)
|
||||
{
|
||||
case TR_NATPMP_IDLE:
|
||||
*public_port = public_port_;
|
||||
*real_private_port = private_port_;
|
||||
return is_mapped_ ? TR_PORT_MAPPED : TR_PORT_UNMAPPED;
|
||||
case State::Idle:
|
||||
return { is_mapped_ ? TR_PORT_MAPPED : TR_PORT_UNMAPPED, public_port_, private_port_ };
|
||||
|
||||
case TR_NATPMP_DISCOVER:
|
||||
return TR_PORT_UNMAPPED;
|
||||
case State::Discover:
|
||||
return { TR_PORT_UNMAPPED, {}, {} };
|
||||
|
||||
case TR_NATPMP_RECV_PUB:
|
||||
case TR_NATPMP_SEND_MAP:
|
||||
case TR_NATPMP_RECV_MAP:
|
||||
return TR_PORT_MAPPING;
|
||||
case State::RecvPub:
|
||||
case State::SendMap:
|
||||
case State::RecvMap:
|
||||
return { TR_PORT_MAPPING, {}, {} };
|
||||
|
||||
case TR_NATPMP_SEND_UNMAP:
|
||||
case TR_NATPMP_RECV_UNMAP:
|
||||
return TR_PORT_UNMAPPING;
|
||||
case State::SendUnmap:
|
||||
case State::RecvUnmap:
|
||||
return { TR_PORT_UNMAPPING, {}, {} };
|
||||
|
||||
default:
|
||||
return TR_PORT_ERROR;
|
||||
return { TR_PORT_ERROR, {}, {} };
|
||||
}
|
||||
}
|
|
@ -5,14 +5,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef __TRANSMISSION__
|
||||
#error only libtransmission should #include this header.
|
||||
#ifndef LIBTRANSMISSION_PORT_FORWARDING_MODULE
|
||||
#error only the libtransmission port forwarding module should #include this header.
|
||||
#endif
|
||||
|
||||
#include <ctime> // time_t
|
||||
#include <cstdint>
|
||||
|
||||
#include "transmission.h" // tr_port_forwarding
|
||||
#include "transmission.h" // tr_port_forwarding_state
|
||||
|
||||
#include "natpmp.h"
|
||||
#include "net.h" // tr_port
|
||||
|
@ -35,19 +35,27 @@ public:
|
|||
return renew_time_;
|
||||
}
|
||||
|
||||
tr_port_forwarding pulse(tr_port port, bool is_enabled, tr_port* public_port, tr_port* real_private_port);
|
||||
struct PulseResult
|
||||
{
|
||||
tr_port_forwarding_state state = TR_PORT_ERROR;
|
||||
|
||||
tr_port public_port = {};
|
||||
tr_port private_port = {};
|
||||
};
|
||||
|
||||
PulseResult pulse(tr_port port, bool is_enabled);
|
||||
|
||||
private:
|
||||
enum tr_natpmp_state
|
||||
enum class State
|
||||
{
|
||||
TR_NATPMP_IDLE,
|
||||
TR_NATPMP_ERR,
|
||||
TR_NATPMP_DISCOVER,
|
||||
TR_NATPMP_RECV_PUB,
|
||||
TR_NATPMP_SEND_MAP,
|
||||
TR_NATPMP_RECV_MAP,
|
||||
TR_NATPMP_SEND_UNMAP,
|
||||
TR_NATPMP_RECV_UNMAP
|
||||
Idle,
|
||||
Err,
|
||||
Discover,
|
||||
RecvPub,
|
||||
SendMap,
|
||||
RecvMap,
|
||||
SendUnmap,
|
||||
RecvUnmap
|
||||
};
|
||||
|
||||
static constexpr auto LifetimeSecs = uint32_t{ 3600 };
|
||||
|
@ -64,7 +72,7 @@ private:
|
|||
|
||||
time_t renew_time_ = 0;
|
||||
time_t command_time_ = 0;
|
||||
tr_natpmp_state state_ = TR_NATPMP_DISCOVER;
|
||||
State state_ = State::Discover;
|
||||
|
||||
bool has_discovered_ = false;
|
||||
bool is_mapped_ = false;
|
|
@ -22,42 +22,44 @@
|
|||
#include <miniupnp/upnpcommands.h>
|
||||
#endif
|
||||
|
||||
#define LIBTRANSMISSION_PORT_FORWARDING_MODULE
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "port-forwarding-upnp.h"
|
||||
#include "port-forwarding.h"
|
||||
#include "session.h"
|
||||
#include "tr-assert.h"
|
||||
#include "upnp.h"
|
||||
#include "utils.h"
|
||||
#include "utils.h" // for _(), tr_strerror()
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
enum class UpnpState
|
||||
{
|
||||
IDLE,
|
||||
FAILED,
|
||||
WILL_DISCOVER, // next action is upnpDiscover()
|
||||
DISCOVERING, // currently making blocking upnpDiscover() call in a worker thread
|
||||
WILL_MAP, // next action is UPNP_AddPortMapping()
|
||||
WILL_UNMAP // next action is UPNP_DeletePortMapping()
|
||||
Idle,
|
||||
Failed,
|
||||
WillDiscover, // next action is upnpDiscover()
|
||||
Discovering, // currently making blocking upnpDiscover() call in a worker thread
|
||||
WillMap, // next action is UPNP_AddPortMapping()
|
||||
WillUnmap // next action is UPNP_DeletePortMapping()
|
||||
};
|
||||
|
||||
constexpr tr_port_forwarding portFwdState(UpnpState upnp_state, bool is_mapped)
|
||||
constexpr auto portFwdState(UpnpState upnp_state, bool is_mapped)
|
||||
{
|
||||
switch (upnp_state)
|
||||
{
|
||||
case UpnpState::WILL_DISCOVER:
|
||||
case UpnpState::DISCOVERING:
|
||||
case UpnpState::WillDiscover:
|
||||
case UpnpState::Discovering:
|
||||
return TR_PORT_UNMAPPED;
|
||||
|
||||
case UpnpState::WILL_MAP:
|
||||
case UpnpState::WillMap:
|
||||
return TR_PORT_MAPPING;
|
||||
|
||||
case UpnpState::WILL_UNMAP:
|
||||
case UpnpState::WillUnmap:
|
||||
return TR_PORT_UNMAPPING;
|
||||
|
||||
case UpnpState::IDLE:
|
||||
case UpnpState::Idle:
|
||||
return is_mapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED;
|
||||
|
||||
default: // UpnpState::FAILED:
|
||||
|
@ -79,8 +81,8 @@ struct tr_upnp
|
|||
{
|
||||
TR_ASSERT(!isMapped);
|
||||
TR_ASSERT(
|
||||
state == UpnpState::IDLE || state == UpnpState::FAILED || state == UpnpState::WILL_DISCOVER ||
|
||||
state == UpnpState::DISCOVERING);
|
||||
state == UpnpState::Idle || state == UpnpState::Failed || state == UpnpState::WillDiscover ||
|
||||
state == UpnpState::Discovering);
|
||||
|
||||
FreeUPNPUrls(&urls);
|
||||
}
|
||||
|
@ -91,7 +93,7 @@ struct tr_upnp
|
|||
tr_port port;
|
||||
std::string lanaddr;
|
||||
bool isMapped = false;
|
||||
UpnpState state = UpnpState::WILL_DISCOVER;
|
||||
UpnpState state = UpnpState::WillDiscover;
|
||||
|
||||
// Used to return the results of upnpDiscover() from a worker thread
|
||||
// to be processed without blocking in tr_upnpPulse().
|
||||
|
@ -248,7 +250,10 @@ enum
|
|||
|
||||
static auto* discoverThreadfunc(std::string bindaddr) // NOLINT performance-unnecessary-value-param
|
||||
{
|
||||
return tr_upnpDiscover(2000, bindaddr.c_str());
|
||||
// If multicastif is not NULL, it will be used instead of the default
|
||||
// multicast interface for sending SSDP discover packets.
|
||||
char const* multicastif = std::empty(bindaddr) ? nullptr : bindaddr.c_str();
|
||||
return tr_upnpDiscover(2000, multicastif);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -257,20 +262,20 @@ static bool isFutureReady(std::future<T> const& future)
|
|||
return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
|
||||
}
|
||||
|
||||
tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled, bool do_port_check, std::string bindaddr)
|
||||
tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled, bool do_port_check, std::string bindaddr)
|
||||
{
|
||||
if (is_enabled && handle->state == UpnpState::WILL_DISCOVER)
|
||||
if (is_enabled && handle->state == UpnpState::WillDiscover)
|
||||
{
|
||||
TR_ASSERT(!handle->discover_future);
|
||||
|
||||
auto task = std::packaged_task<UPNPDev*(std::string)>{ discoverThreadfunc };
|
||||
handle->discover_future = task.get_future();
|
||||
handle->state = UpnpState::DISCOVERING;
|
||||
handle->state = UpnpState::Discovering;
|
||||
|
||||
std::thread(std::move(task), std::move(bindaddr)).detach();
|
||||
}
|
||||
|
||||
if (is_enabled && handle->state == UpnpState::DISCOVERING && handle->discover_future &&
|
||||
if (is_enabled && handle->state == UpnpState::Discovering && handle->discover_future &&
|
||||
isFutureReady(*handle->discover_future))
|
||||
{
|
||||
auto* const devlist = handle->discover_future->get();
|
||||
|
@ -283,13 +288,13 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled,
|
|||
{
|
||||
tr_logAddInfo(fmt::format(_("Found Internet Gateway Device '{url}'"), fmt::arg("url", handle->urls.controlURL)));
|
||||
tr_logAddInfo(fmt::format(_("Local Address is '{address}'"), fmt::arg("address", std::data(handle->lanaddr))));
|
||||
handle->state = UpnpState::IDLE;
|
||||
handle->state = UpnpState::Idle;
|
||||
handle->hasDiscovered = true;
|
||||
handle->lanaddr = std::data(lanaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
handle->state = UpnpState::FAILED;
|
||||
handle->state = UpnpState::Failed;
|
||||
tr_logAddDebug(fmt::format("UPNP_GetValidIGD failed: {} ({})", tr_strerror(errno), errno));
|
||||
tr_logAddDebug("If your router supports UPnP, please make sure UPnP is enabled!");
|
||||
}
|
||||
|
@ -297,9 +302,9 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled,
|
|||
freeUPNPDevlist(devlist);
|
||||
}
|
||||
|
||||
if ((handle->state == UpnpState::IDLE) && (handle->isMapped) && (!is_enabled || handle->port != port))
|
||||
if ((handle->state == UpnpState::Idle) && (handle->isMapped) && (!is_enabled || handle->port != port))
|
||||
{
|
||||
handle->state = UpnpState::WILL_UNMAP;
|
||||
handle->state = UpnpState::WillUnmap;
|
||||
}
|
||||
|
||||
if (is_enabled && handle->isMapped && do_port_check &&
|
||||
|
@ -310,7 +315,7 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled,
|
|||
handle->isMapped = false;
|
||||
}
|
||||
|
||||
if (handle->state == UpnpState::WILL_UNMAP)
|
||||
if (handle->state == UpnpState::WillUnmap)
|
||||
{
|
||||
tr_upnpDeletePortMapping(handle, "TCP", handle->port);
|
||||
tr_upnpDeletePortMapping(handle, "UDP", handle->port);
|
||||
|
@ -321,16 +326,16 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled,
|
|||
fmt::arg("type", handle->data.first.servicetype)));
|
||||
|
||||
handle->isMapped = false;
|
||||
handle->state = UpnpState::IDLE;
|
||||
handle->state = UpnpState::Idle;
|
||||
handle->port = {};
|
||||
}
|
||||
|
||||
if ((handle->state == UpnpState::IDLE) && is_enabled && !handle->isMapped)
|
||||
if ((handle->state == UpnpState::Idle) && is_enabled && !handle->isMapped)
|
||||
{
|
||||
handle->state = UpnpState::WILL_MAP;
|
||||
handle->state = UpnpState::WillMap;
|
||||
}
|
||||
|
||||
if (handle->state == UpnpState::WILL_MAP)
|
||||
if (handle->state == UpnpState::WillMap)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
|
@ -340,7 +345,7 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled,
|
|||
}
|
||||
else
|
||||
{
|
||||
auto const desc = fmt::format(FMT_STRING("{:s} at {:d}"), TR_NAME, port.host());
|
||||
auto const desc = fmt::format(FMT_STRING("Transmission at {:d}"), port.host());
|
||||
int const err_tcp = tr_upnpAddPortMapping(handle, "TCP", port, desc.c_str());
|
||||
int const err_udp = tr_upnpAddPortMapping(handle, "UDP", port, desc.c_str());
|
||||
|
||||
|
@ -358,13 +363,13 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled,
|
|||
{
|
||||
tr_logAddInfo(fmt::format(_("Port {port} is forwarded"), fmt::arg("port", port.host())));
|
||||
handle->port = port;
|
||||
handle->state = UpnpState::IDLE;
|
||||
handle->state = UpnpState::Idle;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_logAddInfo(_("If your router supports UPnP, please make sure UPnP is enabled!"));
|
||||
handle->port = {};
|
||||
handle->state = UpnpState::FAILED;
|
||||
handle->state = UpnpState::Failed;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef __TRANSMISSION__
|
||||
#error only libtransmission should #include this header.
|
||||
#ifndef LIBTRANSMISSION_PORT_FORWARDING_MODULE
|
||||
#error only the libtransmission port forwarding module should #include this header.
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,6 @@ tr_upnp* tr_upnpInit(void);
|
|||
|
||||
void tr_upnpClose(tr_upnp*);
|
||||
|
||||
tr_port_forwarding tr_upnpPulse(tr_upnp*, tr_port port, bool is_enabled, bool do_port_check, std::string);
|
||||
tr_port_forwarding_state tr_upnpPulse(tr_upnp*, tr_port port, bool is_enabled, bool do_port_check, std::string);
|
||||
|
||||
/* @} */
|
|
@ -9,241 +9,232 @@
|
|||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#define LIBTRANSMISSION_PORT_FORWARDING_MODULE
|
||||
|
||||
#include "transmission.h"
|
||||
#include "natpmp_local.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "net.h"
|
||||
#include "peer-mgr.h"
|
||||
#include "port-forwarding-natpmp.h"
|
||||
#include "port-forwarding-upnp.h"
|
||||
#include "port-forwarding.h"
|
||||
#include "session.h"
|
||||
#include "timer.h"
|
||||
#include "torrent.h"
|
||||
#include "tr-assert.h"
|
||||
#include "upnp.h"
|
||||
#include "utils.h" // for _()
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
struct tr_shared
|
||||
class tr_port_forwarding_impl final : public tr_port_forwarding
|
||||
{
|
||||
explicit tr_shared(tr_session& session_in)
|
||||
: session{ session_in }
|
||||
public:
|
||||
explicit tr_port_forwarding_impl(tr_session& session)
|
||||
: session_{ session }
|
||||
, timer_maker_{ session.timerMaker() }
|
||||
{
|
||||
}
|
||||
|
||||
tr_session& session;
|
||||
~tr_port_forwarding_impl() override
|
||||
{
|
||||
is_shutting_down_ = true;
|
||||
stopForwarding();
|
||||
}
|
||||
|
||||
bool isEnabled = false;
|
||||
bool isShuttingDown = false;
|
||||
bool doPortCheck = false;
|
||||
tr_port_forwarding_impl(tr_port_forwarding_impl&&) = delete;
|
||||
tr_port_forwarding_impl(tr_port_forwarding_impl const&) = delete;
|
||||
tr_port_forwarding_impl& operator=(tr_port_forwarding_impl&&) = delete;
|
||||
tr_port_forwarding_impl& operator=(tr_port_forwarding_impl const&) = delete;
|
||||
|
||||
tr_port_forwarding natpmpStatus = TR_PORT_UNMAPPED;
|
||||
tr_port_forwarding upnpStatus = TR_PORT_UNMAPPED;
|
||||
void portChanged() override
|
||||
{
|
||||
if (!is_enabled_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tr_upnp* upnp = nullptr;
|
||||
std::unique_ptr<tr_natpmp> natpmp;
|
||||
stopTimer();
|
||||
natPulse(false);
|
||||
startTimer();
|
||||
}
|
||||
|
||||
std::unique_ptr<libtransmission::Timer> timer;
|
||||
void setEnabled(bool enabled) override
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
is_enabled_ = true;
|
||||
startTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
is_enabled_ = false;
|
||||
stopForwarding();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isEnabled() const noexcept override
|
||||
{
|
||||
return is_enabled_;
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_port_forwarding_state state() const noexcept override
|
||||
{
|
||||
return std::max(natpmp_state_, upnp_state_);
|
||||
}
|
||||
|
||||
private:
|
||||
void stopTimer()
|
||||
{
|
||||
timer_.reset();
|
||||
}
|
||||
|
||||
void stopForwarding()
|
||||
{
|
||||
tr_logAddTrace("stopped");
|
||||
natPulse(false);
|
||||
|
||||
natpmp_.reset();
|
||||
natpmp_state_ = TR_PORT_UNMAPPED;
|
||||
|
||||
tr_upnpClose(upnp_);
|
||||
upnp_ = nullptr;
|
||||
upnp_state_ = TR_PORT_UNMAPPED;
|
||||
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
void startTimer()
|
||||
{
|
||||
timer_ = timer_maker_.create([this]() { this->onTimer(); });
|
||||
restartTimer();
|
||||
}
|
||||
|
||||
void restartTimer()
|
||||
{
|
||||
if (!timer_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// when to wake up again
|
||||
switch (state())
|
||||
{
|
||||
case TR_PORT_MAPPED:
|
||||
// if we're mapped, everything is fine... check back at `renew_time`
|
||||
// to renew the port forwarding if it's expired
|
||||
do_port_check_ = true;
|
||||
if (auto const now = tr_time(); natpmp_->renewTime() > now)
|
||||
{
|
||||
timer_->startSingleShot(std::chrono::seconds{ natpmp_->renewTime() - now });
|
||||
}
|
||||
else // ???
|
||||
{
|
||||
timer_->startSingleShot(1min);
|
||||
}
|
||||
break;
|
||||
|
||||
case TR_PORT_ERROR:
|
||||
// some kind of an error. wait a minute and retry
|
||||
timer_->startSingleShot(1min);
|
||||
break;
|
||||
|
||||
default:
|
||||
// in progress. pulse frequently.
|
||||
timer_->startSingleShot(333ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onTimer()
|
||||
{
|
||||
TR_ASSERT(timer_);
|
||||
|
||||
// do something
|
||||
natPulse(do_port_check_);
|
||||
do_port_check_ = false;
|
||||
|
||||
// set up the timer for the next pulse
|
||||
restartTimer();
|
||||
}
|
||||
|
||||
static constexpr char const* getNatStateStr(int state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TR_PORT_MAPPING:
|
||||
return _("Starting");
|
||||
|
||||
case TR_PORT_MAPPED:
|
||||
return _("Forwarded");
|
||||
|
||||
case TR_PORT_UNMAPPING:
|
||||
return _("Stopping");
|
||||
|
||||
case TR_PORT_UNMAPPED:
|
||||
return _("Not forwarded");
|
||||
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
void natPulse(bool do_check)
|
||||
{
|
||||
auto& session = session_;
|
||||
auto const is_enabled = is_enabled_ && !is_shutting_down_;
|
||||
|
||||
if (!natpmp_)
|
||||
{
|
||||
natpmp_ = std::make_unique<tr_natpmp>();
|
||||
}
|
||||
|
||||
if (upnp_ == nullptr)
|
||||
{
|
||||
upnp_ = tr_upnpInit();
|
||||
}
|
||||
|
||||
auto const old_state = state();
|
||||
|
||||
auto const result = natpmp_->pulse(session.private_peer_port, is_enabled);
|
||||
natpmp_state_ = result.state;
|
||||
if (!std::empty(result.public_port) && !std::empty(result.private_port))
|
||||
{
|
||||
session.public_peer_port = result.public_port;
|
||||
session.private_peer_port = result.private_port;
|
||||
tr_logAddInfo(fmt::format(
|
||||
_("Mapped private port {private_port} to public port {public_port}"),
|
||||
fmt::arg("public_port", session.public_peer_port.host()),
|
||||
fmt::arg("private_port", session.private_peer_port.host())));
|
||||
}
|
||||
|
||||
upnp_state_ = tr_upnpPulse(upnp_, session.private_peer_port, is_enabled, do_check, session.bind_ipv4.readable());
|
||||
|
||||
if (auto const new_state = state(); new_state != old_state)
|
||||
{
|
||||
tr_logAddInfo(fmt::format(
|
||||
_("State changed from '{old_state}' to '{state}'"),
|
||||
fmt::arg("old_state", getNatStateStr(old_state)),
|
||||
fmt::arg("state", getNatStateStr(new_state))));
|
||||
}
|
||||
}
|
||||
|
||||
tr_session& session_;
|
||||
libtransmission::TimerMaker& timer_maker_;
|
||||
|
||||
bool is_enabled_ = false;
|
||||
bool is_shutting_down_ = false;
|
||||
bool do_port_check_ = false;
|
||||
|
||||
tr_port_forwarding_state natpmp_state_ = TR_PORT_UNMAPPED;
|
||||
tr_port_forwarding_state upnp_state_ = TR_PORT_UNMAPPED;
|
||||
|
||||
tr_upnp* upnp_ = nullptr;
|
||||
std::unique_ptr<tr_natpmp> natpmp_;
|
||||
|
||||
std::unique_ptr<libtransmission::Timer> timer_;
|
||||
};
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static char const* getNatStateStr(int state)
|
||||
std::unique_ptr<tr_port_forwarding> tr_port_forwarding::create(tr_session& session)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TR_PORT_MAPPING:
|
||||
return _("Starting");
|
||||
|
||||
case TR_PORT_MAPPED:
|
||||
return _("Forwarded");
|
||||
|
||||
case TR_PORT_UNMAPPING:
|
||||
return _("Stopping");
|
||||
|
||||
case TR_PORT_UNMAPPED:
|
||||
return _("Not forwarded");
|
||||
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static void natPulse(tr_shared* s, bool do_check)
|
||||
{
|
||||
auto& session = s->session;
|
||||
tr_port const private_peer_port = session.private_peer_port;
|
||||
bool const is_enabled = s->isEnabled && !s->isShuttingDown;
|
||||
|
||||
if (!s->natpmp)
|
||||
{
|
||||
s->natpmp = std::make_unique<tr_natpmp>();
|
||||
}
|
||||
|
||||
if (s->upnp == nullptr)
|
||||
{
|
||||
s->upnp = tr_upnpInit();
|
||||
}
|
||||
|
||||
auto const old_status = tr_sharedTraversalStatus(s);
|
||||
|
||||
auto public_peer_port = tr_port{};
|
||||
auto received_private_port = tr_port{};
|
||||
s->natpmpStatus = s->natpmp->pulse(private_peer_port, is_enabled, &public_peer_port, &received_private_port);
|
||||
|
||||
if (s->natpmpStatus == TR_PORT_MAPPED)
|
||||
{
|
||||
session.public_peer_port = public_peer_port;
|
||||
session.private_peer_port = received_private_port;
|
||||
tr_logAddInfo(fmt::format(
|
||||
_("Mapped private port {private_port} to public port {public_port}"),
|
||||
fmt::arg("public_port", session.public_peer_port.host()),
|
||||
fmt::arg("private_port", session.private_peer_port.host())));
|
||||
}
|
||||
|
||||
s->upnpStatus = tr_upnpPulse(s->upnp, private_peer_port, is_enabled, do_check, session.bind_ipv4.readable());
|
||||
|
||||
auto const new_status = tr_sharedTraversalStatus(s);
|
||||
|
||||
if (new_status != old_status)
|
||||
{
|
||||
tr_logAddInfo(fmt::format(
|
||||
_("State changed from '{old_state}' to '{state}'"),
|
||||
fmt::arg("old_state", getNatStateStr(old_status)),
|
||||
fmt::arg("state", getNatStateStr(new_status))));
|
||||
}
|
||||
}
|
||||
|
||||
static void restartTimer(tr_shared* s)
|
||||
{
|
||||
auto& timer = s->timer;
|
||||
if (!timer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// when to wake up again
|
||||
switch (tr_sharedTraversalStatus(s))
|
||||
{
|
||||
case TR_PORT_MAPPED:
|
||||
// if we're mapped, everything is fine... check back at `renew_time`
|
||||
// to renew the port forwarding if it's expired
|
||||
s->doPortCheck = true;
|
||||
if (auto const now = tr_time(); s->natpmp->renewTime() > now)
|
||||
{
|
||||
timer->startSingleShot(std::chrono::seconds{ s->natpmp->renewTime() - now });
|
||||
}
|
||||
else // ???
|
||||
{
|
||||
timer->startSingleShot(1min);
|
||||
}
|
||||
break;
|
||||
|
||||
case TR_PORT_ERROR:
|
||||
// some kind of an error. wait a minute and retry
|
||||
timer->startSingleShot(1min);
|
||||
break;
|
||||
|
||||
default:
|
||||
// in progress. pulse frequently.
|
||||
timer->startSingleShot(333ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void onTimer(void* vshared)
|
||||
{
|
||||
auto* s = static_cast<tr_shared*>(vshared);
|
||||
|
||||
TR_ASSERT(s != nullptr);
|
||||
TR_ASSERT(s->timer);
|
||||
|
||||
/* do something */
|
||||
natPulse(s, s->doPortCheck);
|
||||
s->doPortCheck = false;
|
||||
|
||||
/* set up the timer for the next pulse */
|
||||
restartTimer(s);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_shared* tr_sharedInit(tr_session& session)
|
||||
{
|
||||
return new tr_shared{ session };
|
||||
}
|
||||
|
||||
static void stop_timer(tr_shared* s)
|
||||
{
|
||||
s->timer.reset();
|
||||
}
|
||||
|
||||
static void stop_forwarding(tr_shared* s)
|
||||
{
|
||||
tr_logAddTrace("stopped");
|
||||
natPulse(s, false);
|
||||
|
||||
s->natpmp.reset();
|
||||
s->natpmpStatus = TR_PORT_UNMAPPED;
|
||||
|
||||
tr_upnpClose(s->upnp);
|
||||
s->upnp = nullptr;
|
||||
s->upnpStatus = TR_PORT_UNMAPPED;
|
||||
|
||||
stop_timer(s);
|
||||
}
|
||||
|
||||
void tr_sharedClose(tr_session& session)
|
||||
{
|
||||
tr_shared* shared = session.shared;
|
||||
|
||||
shared->isShuttingDown = true;
|
||||
stop_forwarding(shared);
|
||||
shared->session.shared = nullptr;
|
||||
delete shared;
|
||||
}
|
||||
|
||||
static void start_timer(tr_shared* s)
|
||||
{
|
||||
s->timer = s->session.timerMaker().create(onTimer, s);
|
||||
restartTimer(s);
|
||||
}
|
||||
|
||||
void tr_sharedTraversalEnable(tr_shared* s, bool is_enable)
|
||||
{
|
||||
if (is_enable)
|
||||
{
|
||||
s->isEnabled = true;
|
||||
start_timer(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->isEnabled = false;
|
||||
stop_forwarding(s);
|
||||
}
|
||||
}
|
||||
|
||||
void tr_sharedPortChanged(tr_session& session)
|
||||
{
|
||||
auto* const s = session.shared;
|
||||
|
||||
if (s->isEnabled)
|
||||
{
|
||||
stop_timer(s);
|
||||
natPulse(s, false);
|
||||
start_timer(s);
|
||||
}
|
||||
}
|
||||
|
||||
bool tr_sharedTraversalIsEnabled(tr_shared const* s)
|
||||
{
|
||||
return s->isEnabled;
|
||||
}
|
||||
|
||||
int tr_sharedTraversalStatus(tr_shared const* s)
|
||||
{
|
||||
return std::max(s->natpmpStatus, s->upnpStatus);
|
||||
return std::make_unique<tr_port_forwarding_impl>(session);
|
||||
}
|
||||
|
|
|
@ -9,22 +9,24 @@
|
|||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#include "net.h" // tr_port
|
||||
#include <memory> // for std::unique_ptr
|
||||
|
||||
#include "transmission.h" // for tr_port_forwarding_state
|
||||
|
||||
struct tr_bindsockets;
|
||||
struct tr_session;
|
||||
struct tr_shared;
|
||||
|
||||
tr_shared* tr_sharedInit(tr_session&);
|
||||
class tr_port_forwarding
|
||||
{
|
||||
public:
|
||||
virtual ~tr_port_forwarding() = default;
|
||||
|
||||
void tr_sharedClose(tr_session&);
|
||||
virtual void portChanged() = 0;
|
||||
|
||||
void tr_sharedPortChanged(tr_session&);
|
||||
virtual void setEnabled(bool enabled) = 0;
|
||||
|
||||
void tr_sharedTraversalEnable(tr_shared*, bool is_enabled);
|
||||
[[nodiscard]] virtual bool isEnabled() const = 0;
|
||||
|
||||
tr_port tr_sharedGetPeerPort(tr_shared const* s);
|
||||
[[nodiscard]] virtual tr_port_forwarding_state state() const = 0;
|
||||
|
||||
bool tr_sharedTraversalIsEnabled(tr_shared const* s);
|
||||
|
||||
int tr_sharedTraversalStatus(tr_shared const*);
|
||||
[[nodiscard]] static std::unique_ptr<tr_port_forwarding> create(tr_session&);
|
||||
};
|
||||
|
|
|
@ -731,7 +731,7 @@ void tr_session::initImpl(init_data& data)
|
|||
|
||||
this->peerMgr = tr_peerMgrNew(this);
|
||||
|
||||
this->shared = tr_sharedInit(*this);
|
||||
this->port_forwarding_ = tr_port_forwarding::create(*this);
|
||||
|
||||
/**
|
||||
*** Blocklist
|
||||
|
@ -1262,7 +1262,7 @@ static void peerPortChanged(tr_session* const session)
|
|||
open_incoming_peer_port(session);
|
||||
}
|
||||
|
||||
tr_sharedPortChanged(*session);
|
||||
session->port_forwarding_->portChanged();
|
||||
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
|
@ -1312,11 +1312,11 @@ bool tr_sessionGetPeerPortRandomOnStart(tr_session const* session)
|
|||
return session->isPortRandom();
|
||||
}
|
||||
|
||||
tr_port_forwarding tr_sessionGetPortForwarding(tr_session const* session)
|
||||
tr_port_forwarding_state tr_sessionGetPortForwarding(tr_session const* session)
|
||||
{
|
||||
TR_ASSERT(session != nullptr);
|
||||
|
||||
return tr_port_forwarding(tr_sharedTraversalStatus(session->shared));
|
||||
return session->port_forwarding_->state();
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -1812,7 +1812,7 @@ void tr_session::closeImplStart()
|
|||
now_timer_.reset();
|
||||
|
||||
verifier_.reset();
|
||||
tr_sharedClose(*this);
|
||||
port_forwarding_.reset();
|
||||
|
||||
close_incoming_peer_port(this);
|
||||
this->rpc_server_.reset();
|
||||
|
@ -1910,17 +1910,17 @@ void tr_sessionClose(tr_session* session)
|
|||
tr_wait_msec(10);
|
||||
}
|
||||
|
||||
/* "shared" and "tracker" have live sockets,
|
||||
/* "port_forwarding" and "tracker" have live sockets,
|
||||
* so we need to keep the transmission thread alive
|
||||
* for a bit while they tell the router & tracker
|
||||
* that we're closing now */
|
||||
while ((session->shared != nullptr || !session->web->isClosed() || session->announcer != nullptr ||
|
||||
while ((session->port_forwarding_ || !session->web->isClosed() || session->announcer != nullptr ||
|
||||
session->announcer_udp != nullptr) &&
|
||||
!deadlineReached(deadline))
|
||||
{
|
||||
tr_logAddTrace(fmt::format(
|
||||
"waiting on port unmap ({}) or announcer ({})... now {} deadline {}",
|
||||
fmt::ptr(session->shared),
|
||||
fmt::ptr(session->port_forwarding_.get()),
|
||||
fmt::ptr(session->announcer),
|
||||
time(nullptr),
|
||||
deadline));
|
||||
|
@ -2218,14 +2218,14 @@ tr_bandwidth& tr_session::getBandwidthGroup(std::string_view name)
|
|||
|
||||
void tr_sessionSetPortForwardingEnabled(tr_session* session, bool enabled)
|
||||
{
|
||||
tr_runInEventThread(session, tr_sharedTraversalEnable, session->shared, enabled);
|
||||
tr_runInEventThread(session, [session, enabled]() { session->port_forwarding_->setEnabled(enabled); });
|
||||
}
|
||||
|
||||
bool tr_sessionIsPortForwardingEnabled(tr_session const* session)
|
||||
{
|
||||
TR_ASSERT(session != nullptr);
|
||||
|
||||
return tr_sharedTraversalIsEnabled(session->shared);
|
||||
return session->port_forwarding_->isEnabled();
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
@ -56,6 +56,7 @@ struct evdns_base;
|
|||
class tr_rpc_server;
|
||||
class tr_web;
|
||||
class tr_lpd;
|
||||
class tr_port_forwarding;
|
||||
struct BlocklistFile;
|
||||
struct struct_utp_context;
|
||||
struct tr_announcer;
|
||||
|
@ -550,7 +551,7 @@ public:
|
|||
}
|
||||
|
||||
struct tr_peerMgr* peerMgr = nullptr;
|
||||
struct tr_shared* shared = nullptr;
|
||||
std::unique_ptr<tr_port_forwarding> port_forwarding_;
|
||||
|
||||
std::unique_ptr<Cache> cache;
|
||||
|
||||
|
|
|
@ -474,7 +474,7 @@ void tr_sessionSetPeerPortRandomOnStart(tr_session* session, bool random);
|
|||
|
||||
bool tr_sessionGetPeerPortRandomOnStart(tr_session const* session);
|
||||
|
||||
enum tr_port_forwarding
|
||||
enum tr_port_forwarding_state
|
||||
{
|
||||
TR_PORT_ERROR,
|
||||
TR_PORT_UNMAPPED,
|
||||
|
@ -483,7 +483,7 @@ enum tr_port_forwarding
|
|||
TR_PORT_MAPPED
|
||||
};
|
||||
|
||||
tr_port_forwarding tr_sessionGetPortForwarding(tr_session const* session);
|
||||
tr_port_forwarding_state tr_sessionGetPortForwarding(tr_session const* session);
|
||||
|
||||
enum tr_direction
|
||||
{
|
||||
|
|
|
@ -449,7 +449,7 @@
|
|||
|
||||
- (void)updatePortStatus
|
||||
{
|
||||
tr_port_forwarding const fwd = tr_sessionGetPortForwarding(self.fHandle);
|
||||
auto const fwd = tr_sessionGetPortForwarding(self.fHandle);
|
||||
int const port = tr_sessionGetPeerPort(self.fHandle);
|
||||
BOOL natStatusChanged = (self.fNatStatus != fwd);
|
||||
BOOL peerPortChanged = (self.fPeerPort != port);
|
||||
|
|
Loading…
Reference in New Issue