From 243ab1058dd523ac66676e364043107c8609ac5d Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 21 Sep 2022 21:25:53 +0300 Subject: [PATCH] refactor: fold session UDP innards into C++ class (#3794) * Use std::unique_ptr to manage UDP core object N.B.: it's no longer valid to call socket adjustments quirks from tr_sessionSetUTPEnabled() because the corresponding object may be not created yet. We have to create (or re-create) it explicitly (like it's done in tr_sessionSetDHTEnabled()) or just set is_utp_enabled_ flag of the session and assume that socket adjustments will be done later when the object is constructed. --- Transmission.xcodeproj/project.pbxproj | 4 - libtransmission/CMakeLists.txt | 1 - libtransmission/announcer-udp.cc | 42 +---- libtransmission/net.h | 1 + libtransmission/session.cc | 27 +--- libtransmission/session.h | 57 ++++++- libtransmission/tr-dht.cc | 19 ++- libtransmission/tr-udp.cc | 211 +++++++++++++++---------- libtransmission/tr-udp.h | 21 --- libtransmission/tr-utp.cc | 9 +- 10 files changed, 208 insertions(+), 184 deletions(-) delete mode 100644 libtransmission/tr-udp.h diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 20fd796d3..493e409c7 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -191,7 +191,6 @@ A2725D5D0DE7507C003445E7 /* TrackerTableView.mm in Sources */ = {isa = PBXBuildFile; fileRef = A2725D5C0DE7507C003445E7 /* TrackerTableView.mm */; }; A27F0F330E19AD9800B2DB97 /* TorrentGroup.mm in Sources */ = {isa = PBXBuildFile; fileRef = A27F0F320E19AD9800B2DB97 /* TorrentGroup.mm */; }; A284214412DA663E00FBDDBB /* tr-udp.cc in Sources */ = {isa = PBXBuildFile; fileRef = A284214212DA663E00FBDDBB /* tr-udp.cc */; }; - A284214512DA663E00FBDDBB /* tr-udp.h in Headers */ = {isa = PBXBuildFile; fileRef = A284214312DA663E00FBDDBB /* tr-udp.h */; }; A28F4F770E085BDC003A3882 /* ColorTextField.mm in Sources */ = {isa = PBXBuildFile; fileRef = A28F4F760E085BDC003A3882 /* ColorTextField.mm */; }; A292A6E80DFB45FC004B9C0A /* webseed.cc in Sources */ = {isa = PBXBuildFile; fileRef = A292A6E50DFB45EC004B9C0A /* webseed.cc */; }; A29304ED15D7465100B1F726 /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = A29304EC15D7465100B1F726 /* style.css */; }; @@ -928,7 +927,6 @@ A28393FD10D54A79005C0240 /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; A28393FF10D54A96005C0240 /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; A284214212DA663E00FBDDBB /* tr-udp.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "tr-udp.cc"; sourceTree = ""; }; - A284214312DA663E00FBDDBB /* tr-udp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "tr-udp.h"; sourceTree = ""; }; A28B3A2D160E1BC900D4A2BC /* pt_PT */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = pt_PT; path = pt_PT.lproj/Localizable.strings; sourceTree = ""; }; A28E1DDF0CFFD8EC00E16385 /* ButtonToolbarItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ButtonToolbarItem.h; sourceTree = ""; }; A28F4F750E085BDC003A3882 /* ColorTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColorTextField.h; sourceTree = ""; }; @@ -1720,7 +1718,6 @@ C1425B341EE9C5EA001DB85F /* tr-macros.h */, 888A256631B3DE536FEB8B01 /* tr-strbuf.h */, A284214212DA663E00FBDDBB /* tr-udp.cc */, - A284214312DA663E00FBDDBB /* tr-udp.h */, A2679292130E00A000CB7464 /* tr-utp.cc */, A2679293130E00A000CB7464 /* tr-utp.h */, BEFC1DF50C07861A00B0BB3C /* transmission.h */, @@ -2208,7 +2205,6 @@ 2856E0656A49F2665D69E760 /* benc.h in Headers */, E975121263DD973CAF4AEBA0 /* timer.h in Headers */, E975121263DD973CAF4AEBA2 /* timer-ev.h in Headers */, - A284214512DA663E00FBDDBB /* tr-udp.h in Headers */, C1077A4F183EB29600634C22 /* error.h in Headers */, A2679295130E00A000CB7464 /* tr-utp.h in Headers */, A23F29A1132A447400E9A83B /* announcer-common.h in Headers */, diff --git a/libtransmission/CMakeLists.txt b/libtransmission/CMakeLists.txt index 0acec25bd..cbde6bb55 100644 --- a/libtransmission/CMakeLists.txt +++ b/libtransmission/CMakeLists.txt @@ -201,7 +201,6 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS torrents.h tr-dht.h tr-lpd.h - tr-udp.h tr-utp.h trevent.h upnp.h diff --git a/libtransmission/announcer-udp.cc b/libtransmission/announcer-udp.cc index affaba388..347327c09 100644 --- a/libtransmission/announcer-udp.cc +++ b/libtransmission/announcer-udp.cc @@ -31,7 +31,6 @@ #include "peer-mgr.h" /* tr_peerMgrCompactToPex() */ #include "session.h" #include "tr-assert.h" -#include "tr-udp.h" #include "utils.h" #include "web-utils.h" @@ -57,31 +56,10 @@ static void tau_sockaddr_setport(struct sockaddr* sa, tr_port port) } } -static int tau_sendto(tr_session const* session, struct evutil_addrinfo* ai, tr_port port, void const* buf, size_t buflen) +void tr_session::tau_sendto(struct evutil_addrinfo* ai, tr_port port, void const* buf, size_t buflen) const { - auto sockfd = tr_socket_t{}; - - if (ai->ai_addr->sa_family == AF_INET) - { - sockfd = session->udp_socket; - } - else if (ai->ai_addr->sa_family == AF_INET6) - { - sockfd = session->udp6_socket; - } - else - { - sockfd = TR_BAD_SOCKET; - } - - if (sockfd == TR_BAD_SOCKET) - { - errno = EAFNOSUPPORT; - return -1; - } - tau_sockaddr_setport(ai->ai_addr, port); - return sendto(sockfd, static_cast(buf), buflen, 0, ai->ai_addr, ai->ai_addrlen); + udp_core_->sendto(buf, buflen, ai->ai_addr, ai->ai_addrlen); } static uint32_t announce_ip(tr_session const* session) @@ -497,7 +475,7 @@ static void tau_tracker_send_request(struct tau_tracker* tracker, void const* pa logdbg(tracker->key, fmt::format("sending request w/connection id {}", tracker->connection_id)); evbuffer_add_hton_64(buf, tracker->connection_id); evbuffer_add_reference(buf, payload, payload_len, nullptr, nullptr); - (void)tau_sendto(tracker->session, tracker->addr.get(), tracker->port, evbuffer_pullup(buf, -1), evbuffer_get_length(buf)); + tracker->session->tau_sendto(tracker->addr.get(), tracker->port, evbuffer_pullup(buf, -1), evbuffer_get_length(buf)); evbuffer_free(buf); } @@ -681,12 +659,7 @@ static void tau_tracker_upkeep_ex(struct tau_tracker* tracker, bool timeout_reqs evbuffer_add_hton_64(buf, 0x41727101980LL); evbuffer_add_hton_32(buf, TAU_ACTION_CONNECT); evbuffer_add_hton_32(buf, tracker->connection_transaction_id); - (void)tau_sendto( - tracker->session, - tracker->addr.get(), - tracker->port, - evbuffer_pullup(buf, -1), - evbuffer_get_length(buf)); + tracker->session->tau_sendto(tracker->addr.get(), tracker->port, evbuffer_pullup(buf, -1), evbuffer_get_length(buf)); evbuffer_free(buf); return; } @@ -825,9 +798,9 @@ void tr_tracker_udp_start_shutdown(tr_session* session) /* @brief process an incoming udp message if it's a tracker response. * @return true if msg was a tracker response; false otherwise */ -bool tau_handle_message(tr_session* session, uint8_t const* msg, size_t msglen) +bool tr_session::tau_handle_message(uint8_t const* msg, size_t msglen) const { - if (session == nullptr || session->announcer_udp == nullptr) + if (announcer_udp == nullptr) { return false; } @@ -849,10 +822,9 @@ bool tau_handle_message(tr_session* session, uint8_t const* msg, size_t msglen) } /* extract the transaction_id and look for a match */ - struct tr_announcer_udp* const tau = session->announcer_udp; tau_transaction_t const transaction_id = evbuffer_read_ntoh_32(buf); - for (auto& tracker : tau->trackers) + for (auto& tracker : announcer_udp->trackers) { // is it a connection response? if (tracker.connecting_at != 0 && transaction_id == tracker.connection_transaction_id) diff --git a/libtransmission/net.h b/libtransmission/net.h index 8146f83e3..6c766a74b 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -21,6 +21,7 @@ #include #include #include +#include #endif #ifdef _WIN32 diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 39abda022..1015b882a 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -56,7 +56,6 @@ #include "tr-dht.h" /* tr_dhtUpkeep() */ #include "tr-lpd.h" #include "tr-strbuf.h" -#include "tr-udp.h" #include "tr-utp.h" #include "trevent.h" #include "utils.h" @@ -632,8 +631,6 @@ tr_session* tr_sessionInit(char const* config_dir, bool message_queueing_enabled /* initialize the bare skeleton of the session object */ auto* const session = new tr_session{ config_dir }; - session->udp_socket = TR_BAD_SOCKET; - session->udp6_socket = TR_BAD_SOCKET; session->cache = std::make_unique(session->torrents(), 1024 * 1024 * 2); bandwidthGroupRead(session, config_dir); @@ -750,7 +747,7 @@ void tr_session::initImpl(init_data& data) tr_sessionSet(this, &settings); - tr_udpInit(this); + this->udp_core_ = std::make_unique(*this); this->web = tr_web::create(this->web_mediator_); @@ -1879,7 +1876,7 @@ void tr_session::closeImplFinish() /* we had to wait until UDP trackers were closed before closing these: */ tr_tracker_udp_close(this); - tr_udpUninit(this); + this->udp_core_.reset(); stats().saveIfDirty(); tr_peerMgrFree(peerMgr); @@ -2081,9 +2078,9 @@ void tr_sessionSetDHTEnabled(tr_session* session, bool enabled) session, [session, enabled]() { - tr_udpUninit(session); + session->udp_core_.reset(); session->is_dht_enabled_ = enabled; - tr_udpInit(session); + session->udp_core_ = std::make_unique(*session); }); } @@ -2115,21 +2112,9 @@ void tr_sessionSetUTPEnabled(tr_session* session, bool enabled) { return; } - tr_runInEventThread( - session, - [session, enabled]() - { - session->is_utp_enabled_ = enabled; - tr_udpSetSocketBuffers(session); - tr_udpSetSocketTOS(session); - // But don't call tr_utpClose -- - // see reset_timer in tr-utp.c for an explanation. - }); -} -/*** -**** -***/ + session->is_utp_enabled_ = enabled; +} void tr_sessionSetLPDEnabled(tr_session* session, bool enabled) { diff --git a/libtransmission/session.h b/libtransmission/session.h index 939dfd991..63af47fa1 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -478,13 +478,52 @@ public: struct tr_event_handle* events = nullptr; - /* The UDP sockets used for the DHT and uTP. */ - tr_port udp_port; - tr_socket_t udp_socket = TR_BAD_SOCKET; - tr_socket_t udp6_socket = TR_BAD_SOCKET; - unsigned char* udp6_bound = nullptr; - struct event* udp_event = nullptr; - struct event* udp6_event = nullptr; + // UDP connectivity used for the DHT and uTP + class tr_udp_core + { + public: + tr_udp_core(tr_session& session); + + ~tr_udp_core(); + + void set_socket_buffers(); + + void set_socket_tos() + { + session_.setSocketTOS(udp_socket_, TR_AF_INET); + session_.setSocketTOS(udp6_socket_, TR_AF_INET6); + } + + void sendto(void const* buf, size_t buflen, struct sockaddr const* to, socklen_t const tolen) const; + + [[nodiscard]] constexpr auto port() const noexcept + { + return udp_port_; + } + + [[nodiscard]] constexpr auto udp_socket() const noexcept + { + return udp_socket_; + } + + [[nodiscard]] constexpr auto udp6_socket() const noexcept + { + return udp6_socket_; + } + + private: + tr_port udp_port_ = {}; + tr_session& session_; + struct event* udp_event_ = nullptr; + struct event* udp6_event_ = nullptr; + unsigned char* udp6_bound_ = nullptr; + tr_socket_t udp_socket_ = TR_BAD_SOCKET; + tr_socket_t udp6_socket_ = TR_BAD_SOCKET; + + void rebind_ipv6(bool); + }; + + std::unique_ptr udp_core_; /* The open port on the local machine for incoming peer requests */ tr_port private_peer_port; @@ -958,6 +997,10 @@ private: public: struct struct_utp_context* utp_context = nullptr; std::unique_ptr utp_timer; + + // These UDP announcer quirks are tightly hooked with session + bool tau_handle_message(uint8_t const* msg, size_t msglen) const; + void tau_sendto(struct evutil_addrinfo* ai, tr_port port, void const* buf, size_t buflen) const; }; constexpr bool tr_isPriority(tr_priority_t p) diff --git a/libtransmission/tr-dht.cc b/libtransmission/tr-dht.cc index 742312045..551c9fea5 100644 --- a/libtransmission/tr-dht.cc +++ b/libtransmission/tr-dht.cc @@ -275,6 +275,9 @@ int tr_dhtInit(tr_session* ss) bool have_id = false; auto nodes = std::vector{}; auto nodes6 = std::vector{}; + auto udp_socket = ss->udp_core_->udp_socket(); + auto udp6_socket = ss->udp_core_->udp6_socket(); + if (ok) { auto sv = std::string_view{}; @@ -286,13 +289,13 @@ int tr_dhtInit(tr_session* ss) size_t raw_len = 0U; uint8_t const* raw = nullptr; - if (ss->udp_socket != TR_BAD_SOCKET && tr_variantDictFindRaw(&benc, TR_KEY_nodes, &raw, &raw_len) && raw_len % 6 == 0) + + if (udp_socket != TR_BAD_SOCKET && tr_variantDictFindRaw(&benc, TR_KEY_nodes, &raw, &raw_len) && raw_len % 6 == 0) { nodes.assign(raw, raw + raw_len); } - if (ss->udp6_socket != TR_BAD_SOCKET && tr_variantDictFindRaw(&benc, TR_KEY_nodes6, &raw, &raw_len) && - raw_len % 18 == 0) + if (udp6_socket != TR_BAD_SOCKET && tr_variantDictFindRaw(&benc, TR_KEY_nodes6, &raw, &raw_len) && raw_len % 18 == 0) { nodes6.assign(raw, raw + raw_len); } @@ -312,7 +315,7 @@ int tr_dhtInit(tr_session* ss) tr_rand_buffer(std::data(myid), std::size(myid)); } - if (int const rc = dht_init(ss->udp_socket, ss->udp6_socket, std::data(myid), nullptr); rc < 0) + if (int const rc = dht_init(udp_socket, udp6_socket, std::data(myid), nullptr); rc < 0) { auto const errcode = errno; tr_logAddDebug(fmt::format("DHT initialization failed: {} ({})", tr_strerror(errcode), errcode)); @@ -456,9 +459,11 @@ static void getstatus(getstatus_closure* const closure) int tr_dhtStatus(tr_session* session, int af, int* setme_node_count) { auto closure = getstatus_closure{ af, -1, -1 }; + auto udp_socket = session->udp_core_->udp_socket(); + auto udp6_socket = session->udp_core_->udp6_socket(); - if (!tr_dhtEnabled(session) || (af == AF_INET && session->udp_socket == TR_BAD_SOCKET) || - (af == AF_INET6 && session->udp6_socket == TR_BAD_SOCKET)) + if (!tr_dhtEnabled(session) || (af == AF_INET && udp_socket == TR_BAD_SOCKET) || + (af == AF_INET6 && udp6_socket == TR_BAD_SOCKET)) { if (setme_node_count != nullptr) { @@ -485,7 +490,7 @@ int tr_dhtStatus(tr_session* session, int af, int* setme_node_count) tr_port tr_dhtPort(tr_session const* ss) { - return tr_dhtEnabled(ss) ? ss->udp_port : tr_port{}; + return tr_dhtEnabled(ss) ? ss->udp_core_->port() : tr_port{}; } bool tr_dhtAddNode(tr_session* ss, tr_address const* address, tr_port port, bool bootstrap) diff --git a/libtransmission/tr-udp.cc b/libtransmission/tr-udp.cc index ac49f3416..849caac5b 100644 --- a/libtransmission/tr-udp.cc +++ b/libtransmission/tr-udp.cc @@ -25,7 +25,6 @@ #include "tr-assert.h" #include "tr-dht.h" #include "tr-utp.h" -#include "tr-udp.h" #include "utils.h" /* Since we use a single UDP socket in order to implement multiple @@ -92,51 +91,44 @@ static void set_socket_buffers(tr_socket_t fd, bool large) } } -void tr_udpSetSocketBuffers(tr_session const* session) +void tr_session::tr_udp_core::set_socket_buffers() { - bool const utp = session->allowsUTP(); + bool const utp = session_.allowsUTP(); - if (session->udp_socket != TR_BAD_SOCKET) + if (udp_socket_ != TR_BAD_SOCKET) { - set_socket_buffers(session->udp_socket, utp); + ::set_socket_buffers(udp_socket_, utp); } - - if (session->udp6_socket != TR_BAD_SOCKET) + if (udp6_socket_ != TR_BAD_SOCKET) { - set_socket_buffers(session->udp6_socket, utp); + ::set_socket_buffers(udp6_socket_, utp); } } -void tr_udpSetSocketTOS(tr_session* session) -{ - session->setSocketTOS(session->udp_socket, TR_AF_INET); - session->setSocketTOS(session->udp6_socket, TR_AF_INET6); -} - /* BEP-32 has a rather nice explanation of why we need to bind to one IPv6 address, if I may say so myself. */ // TODO: remove goto, it prevents reducing scope of local variables -static void rebind_ipv6(tr_session* ss, bool force) +void tr_session::tr_udp_core::rebind_ipv6(bool force) { struct sockaddr_in6 sin6; - unsigned char const* ipv6 = tr_globalIPv6(ss); + unsigned char const* ipv6 = tr_globalIPv6(&session_); int rc = -1; int one = 1; /* We currently have no way to enable or disable IPv6 after initialisation. No way to fix that without some surgery to the DHT code itself. */ - if (ipv6 == nullptr || (!force && ss->udp6_socket == TR_BAD_SOCKET)) + if (ipv6 == nullptr || (!force && udp6_socket_ == TR_BAD_SOCKET)) { - if (ss->udp6_bound != nullptr) + if (udp6_bound_ != nullptr) { - free(ss->udp6_bound); - ss->udp6_bound = nullptr; + free(udp6_bound_); + udp6_bound_ = nullptr; } return; } - if (ss->udp6_bound != nullptr && memcmp(ipv6, ss->udp6_bound, 16) == 0) + if (udp6_bound_ != nullptr && memcmp(ipv6, udp6_bound_, 16) == 0) { return; } @@ -162,7 +154,7 @@ static void rebind_ipv6(tr_session* ss, bool force) memcpy(&sin6.sin6_addr, ipv6, 16); } - sin6.sin6_port = ss->udp_port.network(); + sin6.sin6_port = udp_port_.network(); rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); @@ -171,14 +163,14 @@ static void rebind_ipv6(tr_session* ss, bool force) goto FAIL; } - if (ss->udp6_socket == TR_BAD_SOCKET) + if (udp6_socket_ == TR_BAD_SOCKET) { - ss->udp6_socket = s; + udp6_socket_ = s; } else { /* FIXME: dup2 doesn't work for sockets on Windows */ - rc = dup2(s, ss->udp6_socket); + rc = dup2(s, udp6_socket_); if (rc == -1) { @@ -188,14 +180,14 @@ static void rebind_ipv6(tr_session* ss, bool force) tr_netCloseSocket(s); } - if (ss->udp6_bound == nullptr) + if (udp6_bound_ == nullptr) { - ss->udp6_bound = static_cast(malloc(16)); + udp6_bound_ = static_cast(malloc(16)); } - if (ss->udp6_bound != nullptr) + if (udp6_bound_ != nullptr) { - memcpy(ss->udp6_bound, ipv6, 16); + memcpy(udp6_bound_, ipv6, 16); } return; @@ -217,10 +209,10 @@ FAIL: tr_netCloseSocket(s); } - if (ss->udp6_bound != nullptr) + if (udp6_bound_ != nullptr) { - free(ss->udp6_bound); - ss->udp6_bound = nullptr; + free(udp6_bound_); + udp6_bound_ = nullptr; } } @@ -256,7 +248,7 @@ static void event_callback(evutil_socket_t s, [[maybe_unused]] short type, void* } else if (rc >= 8 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] <= 3) { - if (!tau_handle_message(session, std::data(buf), rc)) + if (!session->tau_handle_message(std::data(buf), rc)) { tr_logAddTrace("Couldn't parse UDP tracker packet."); } @@ -274,26 +266,24 @@ static void event_callback(evutil_socket_t s, [[maybe_unused]] short type, void* } } -void tr_udpInit(tr_session* ss) +tr_session::tr_udp_core::tr_udp_core(tr_session& session) + : session_{ session } { - TR_ASSERT(ss->udp_socket == TR_BAD_SOCKET); - TR_ASSERT(ss->udp6_socket == TR_BAD_SOCKET); - - ss->udp_port = ss->peerPort(); - if (std::empty(ss->udp_port)) + udp_port_ = session_.peerPort(); + if (std::empty(udp_port_)) { return; } - ss->udp_socket = socket(PF_INET, SOCK_DGRAM, 0); + udp_socket_ = socket(PF_INET, SOCK_DGRAM, 0); - if (ss->udp_socket == TR_BAD_SOCKET) + if (udp_socket_ == TR_BAD_SOCKET) { tr_logAddWarn(_("Couldn't create IPv4 socket")); } else { - auto const [public_addr, is_default] = ss->publicAddress(TR_AF_INET); + auto const [public_addr, is_default] = session_.publicAddress(TR_AF_INET); auto sin = sockaddr_in{}; sin.sin_family = AF_INET; @@ -302,25 +292,25 @@ void tr_udpInit(tr_session* ss) memcpy(&sin.sin_addr, &public_addr.addr.addr4, sizeof(struct in_addr)); } - sin.sin_port = ss->udp_port.network(); - int const rc = bind(ss->udp_socket, (struct sockaddr*)&sin, sizeof(sin)); + sin.sin_port = udp_port_.network(); + int const rc = bind(udp_socket_, (struct sockaddr*)&sin, sizeof(sin)); if (rc == -1) { auto const error_code = errno; tr_logAddWarn(fmt::format( _("Couldn't bind IPv4 socket {address}: {error} ({error_code})"), - fmt::arg("address", public_addr.readable(ss->udp_port)), + fmt::arg("address", public_addr.readable(udp_port_)), fmt::arg("error", tr_strerror(error_code)), fmt::arg("error_code", error_code))); - tr_netCloseSocket(ss->udp_socket); - ss->udp_socket = TR_BAD_SOCKET; + tr_netCloseSocket(udp_socket_); + udp_socket_ = TR_BAD_SOCKET; } else { - ss->udp_event = event_new(ss->eventBase(), ss->udp_socket, EV_READ | EV_PERSIST, event_callback, ss); + udp_event_ = event_new(session_.eventBase(), udp_socket_, EV_READ | EV_PERSIST, event_callback, &session_); - if (ss->udp_event == nullptr) + if (udp_event_ == nullptr) { tr_logAddWarn(_("Couldn't allocate IPv4 event")); } @@ -331,70 +321,131 @@ void tr_udpInit(tr_session* ss) if (tr_globalIPv6(nullptr) != nullptr) { - rebind_ipv6(ss, true); + rebind_ipv6(true); } - if (ss->udp6_socket != TR_BAD_SOCKET) + if (udp6_socket_ != TR_BAD_SOCKET) { - ss->udp6_event = event_new(ss->eventBase(), ss->udp6_socket, EV_READ | EV_PERSIST, event_callback, ss); + udp6_event_ = event_new(session_.eventBase(), udp6_socket_, EV_READ | EV_PERSIST, event_callback, &session_); - if (ss->udp6_event == nullptr) + if (udp6_event_ == nullptr) { tr_logAddWarn(_("Couldn't allocate IPv6 event")); } } - tr_udpSetSocketBuffers(ss); + set_socket_buffers(); + set_socket_tos(); - tr_udpSetSocketTOS(ss); - - if (ss->allowsDHT()) + if (session_.allowsDHT()) { - tr_dhtInit(ss); + tr_dhtInit(&session_); } - if (ss->udp_event != nullptr) + if (udp_event_ != nullptr) { - event_add(ss->udp_event, nullptr); + event_add(udp_event_, nullptr); } - - if (ss->udp6_event != nullptr) + if (udp6_event_ != nullptr) { - event_add(ss->udp6_event, nullptr); + event_add(udp6_event_, nullptr); } } -void tr_udpUninit(tr_session* ss) +tr_session::tr_udp_core::~tr_udp_core() { - tr_dhtUninit(ss); + tr_dhtUninit(&session_); - if (ss->udp_socket != TR_BAD_SOCKET) + if (udp_socket_ != TR_BAD_SOCKET) { - tr_netCloseSocket(ss->udp_socket); - ss->udp_socket = TR_BAD_SOCKET; + tr_netCloseSocket(udp_socket_); + udp_socket_ = TR_BAD_SOCKET; } - if (ss->udp_event != nullptr) + if (udp_event_ != nullptr) { - event_free(ss->udp_event); - ss->udp_event = nullptr; + event_free(udp_event_); + udp_event_ = nullptr; } - if (ss->udp6_socket != TR_BAD_SOCKET) + if (udp6_socket_ != TR_BAD_SOCKET) { - tr_netCloseSocket(ss->udp6_socket); - ss->udp6_socket = TR_BAD_SOCKET; + tr_netCloseSocket(udp6_socket_); + udp6_socket_ = TR_BAD_SOCKET; } - if (ss->udp6_event != nullptr) + if (udp6_event_ != nullptr) { - event_free(ss->udp6_event); - ss->udp6_event = nullptr; + event_free(udp6_event_); + udp6_event_ = nullptr; } - if (ss->udp6_bound != nullptr) + if (udp6_bound_ != nullptr) { - free(ss->udp6_bound); - ss->udp6_bound = nullptr; + free(udp6_bound_); + udp6_bound_ = nullptr; + } +} + +void tr_session::tr_udp_core::sendto(void const* buf, size_t buflen, struct sockaddr const* to, socklen_t const tolen) const +{ + int error = 0; + std::array peer = {}; + + if (to->sa_family == AF_INET) + { + if (udp_socket_ != TR_BAD_SOCKET) + { + if (::sendto(udp_socket_, static_cast(buf), buflen, 0, to, tolen) == -1) + error = -1; + } + else + { + error = -1; + errno = EBADF; + } + if (error == -1) + { + evutil_inet_ntop( + AF_INET, + &((reinterpret_cast(to))->sin_addr), + std::data(peer), + std::size(peer)); + } + } + else if (to->sa_family == AF_INET6) + { + if (udp6_socket_ != TR_BAD_SOCKET) + { + if (::sendto(udp6_socket_, static_cast(buf), buflen, 0, to, tolen) == -1) + error = -1; + } + else + { + error = -1; + errno = EBADF; + } + if (error == -1) + { + evutil_inet_ntop( + AF_INET6, + &((reinterpret_cast(to))->sin6_addr), + std::data(peer), + std::size(peer)); + } + } + else + { + error = -1; + errno = EAFNOSUPPORT; + } + + if (error == -1) + { + tr_logAddWarn(fmt::format( + "Couldn't send to {address}: {errno} ({error})", + fmt::arg("address", std::data(peer)), + fmt::arg("errno", errno), + fmt::arg("error", tr_strerror(errno)))); } } diff --git a/libtransmission/tr-udp.h b/libtransmission/tr-udp.h deleted file mode 100644 index 44e969c30..000000000 --- a/libtransmission/tr-udp.h +++ /dev/null @@ -1,21 +0,0 @@ -// This file Copyright © 2010 Juliusz Chroboczek. -// It may be used under the MIT (SPDX: MIT) license. -// License text can be found in the licenses/ folder. - -#pragma once - -#ifndef __TRANSMISSION__ -#error only libtransmission should #include this header. -#endif - -#include // size_t -#include // uint8_t - -struct tr_session; - -void tr_udpInit(tr_session*); -void tr_udpUninit(tr_session*); -void tr_udpSetSocketBuffers(tr_session const*); -void tr_udpSetSocketTOS(tr_session*); - -bool tau_handle_message(tr_session* session, uint8_t const* msg, size_t msglen); diff --git a/libtransmission/tr-utp.cc b/libtransmission/tr-utp.cc index c39933fc6..a74dd4933 100644 --- a/libtransmission/tr-utp.cc +++ b/libtransmission/tr-utp.cc @@ -108,14 +108,7 @@ static void utp_send_to( struct sockaddr const* const to, socklen_t const tolen) { - if (to->sa_family == AF_INET && ss->udp_socket != TR_BAD_SOCKET) - { - (void)sendto(ss->udp_socket, reinterpret_cast(buf), buflen, 0, to, tolen); - } - else if (to->sa_family == AF_INET6 && ss->udp6_socket != TR_BAD_SOCKET) - { - (void)sendto(ss->udp6_socket, reinterpret_cast(buf), buflen, 0, to, tolen); - } + ss->udp_core_->sendto(buf, buflen, to, tolen); } #ifdef TR_UTP_TRACE