diff --git a/BUILD.gn b/BUILD.gn index 373e029de9..b3c84aa9b0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -650,7 +650,6 @@ if (rtc_include_tests && !build_with_chromium) { "api/video_codecs/test:video_codecs_api_unittests", "api/voip:compile_all_headers", "call:fake_network_pipe_unittests", - "p2p:libstunprober_unittests", "p2p:rtc_p2p_unittests", "rtc_base:async_dns_resolver_unittests", "rtc_base:async_packet_socket_unittest", diff --git a/examples/BUILD.gn b/examples/BUILD.gn index d21d70535e..6183b9fe3d 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -42,10 +42,6 @@ group("examples") { } } - if (!build_with_chromium) { - deps += [ ":stun_prober" ] - } - if (is_ios || (is_mac && target_cpu != "x86")) { deps += [ ":AppRTCMobile" ] } @@ -869,32 +865,3 @@ if (is_android) { ] ] } } - -if (!build_with_chromium) { - # Doesn't build within Chrome on Win. - rtc_executable("stun_prober") { - testonly = true - sources = [ "stunprober/main.cc" ] - deps = [ - "../p2p:basic_packet_socket_factory", - "../p2p:libstunprober", - "../p2p:rtc_p2p", - "../rtc_base:checks", - "../rtc_base:crypto_random", - "../rtc_base:logging", - "../rtc_base:network", - "../rtc_base:socket_address", - "../rtc_base:ssl_adapter", - "../rtc_base:threading", - "../rtc_base:timeutils", - "../test:scoped_key_value_config", - "//third_party/abseil-cpp/absl/flags:flag", - "//third_party/abseil-cpp/absl/flags:parse", - ] - if (is_win) { - deps += [ - "../rtc_base:win32_socket_init", - ] - } - } -} diff --git a/examples/stunprober/main.cc b/examples/stunprober/main.cc deleted file mode 100644 index 023c52fa0e..0000000000 --- a/examples/stunprober/main.cc +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include -#include -#include -#include -#include - -#include "absl/flags/flag.h" -#include "absl/flags/parse.h" -#include "p2p/base/basic_packet_socket_factory.h" -#include "p2p/stunprober/stun_prober.h" -#include "rtc_base/crypto_random.h" -#include "rtc_base/logging.h" -#include "rtc_base/network.h" -#include "rtc_base/physical_socket_server.h" -#include "rtc_base/socket_address.h" -#include "rtc_base/ssl_adapter.h" -#include "rtc_base/thread.h" -#include "rtc_base/time_utils.h" -#include "test/scoped_key_value_config.h" - -#ifdef WEBRTC_WIN -#include "rtc_base/win32_socket_init.h" -#endif // WEBRTC_WIN - -using stunprober::AsyncCallback; -using stunprober::StunProber; - -ABSL_FLAG(int, - interval, - 10, - "Interval of consecutive stun pings in milliseconds"); -ABSL_FLAG(bool, - shared_socket, - false, - "Share socket mode for different remote IPs"); -ABSL_FLAG(int, - pings_per_ip, - 10, - "Number of consecutive stun pings to send for each IP"); -ABSL_FLAG(int, - timeout, - 1000, - "Milliseconds of wait after the last ping sent before exiting"); -ABSL_FLAG( - std::string, - servers, - "stun.l.google.com:19302,stun1.l.google.com:19302,stun2.l.google.com:19302", - "Comma separated STUN server addresses with ports"); - -namespace { - -const char* PrintNatType(stunprober::NatType type) { - switch (type) { - case stunprober::NATTYPE_NONE: - return "Not behind a NAT"; - case stunprober::NATTYPE_UNKNOWN: - return "Unknown NAT type"; - case stunprober::NATTYPE_SYMMETRIC: - return "Symmetric NAT"; - case stunprober::NATTYPE_NON_SYMMETRIC: - return "Non-Symmetric NAT"; - default: - return "Invalid"; - } -} - -void PrintStats(StunProber* prober) { - StunProber::Stats stats; - if (!prober->GetStats(&stats)) { - RTC_LOG(LS_WARNING) << "Results are inconclusive."; - return; - } - - RTC_LOG(LS_INFO) << "Shared Socket Mode: " << stats.shared_socket_mode; - RTC_LOG(LS_INFO) << "Requests sent: " << stats.num_request_sent; - RTC_LOG(LS_INFO) << "Responses received: " << stats.num_response_received; - RTC_LOG(LS_INFO) << "Target interval (ns): " - << stats.target_request_interval_ns; - RTC_LOG(LS_INFO) << "Actual interval (ns): " - << stats.actual_request_interval_ns; - RTC_LOG(LS_INFO) << "NAT Type: " << PrintNatType(stats.nat_type); - RTC_LOG(LS_INFO) << "Host IP: " << stats.host_ip; - RTC_LOG(LS_INFO) << "Server-reflexive ips: "; - for (auto& ip : stats.srflx_addrs) { - RTC_LOG(LS_INFO) << "\t" << ip; - } - - RTC_LOG(LS_INFO) << "Success Precent: " << stats.success_percent; - RTC_LOG(LS_INFO) << "Response Latency:" << stats.average_rtt_ms; -} - -void StopTrial(rtc::Thread* thread, StunProber* prober, int result) { - thread->Quit(); - if (prober) { - RTC_LOG(LS_INFO) << "Result: " << result; - if (result == StunProber::SUCCESS) { - PrintStats(prober); - } - } -} - -} // namespace - -int main(int argc, char* argv[]) { -#ifdef WEBRTC_WIN - rtc::WinsockInitializer winsock_init; -#endif // WEBRTC_WIN - absl::ParseCommandLine(argc, argv); - - std::vector server_addresses; - std::istringstream servers(absl::GetFlag(FLAGS_servers)); - std::string server; - while (getline(servers, server, ',')) { - rtc::SocketAddress addr; - if (!addr.FromString(server)) { - RTC_LOG(LS_ERROR) << "Parsing " << server << " failed."; - return -1; - } - server_addresses.push_back(addr); - } - - rtc::InitializeSSL(); - rtc::InitRandom(rtc::Time32()); - webrtc::test::ScopedKeyValueConfig field_trials; - rtc::PhysicalSocketServer socket_server; - rtc::AutoSocketServerThread thread(&socket_server); - auto socket_factory = - std::make_unique(&socket_server); - std::unique_ptr network_manager( - new rtc::BasicNetworkManager(&socket_server, &field_trials)); - std::vector networks = network_manager->GetNetworks(); - auto prober = std::make_unique(socket_factory.get(), - rtc::Thread::Current(), networks); - auto finish_callback = [&thread](StunProber* prober, int result) { - StopTrial(&thread, prober, result); - }; - prober->Start(server_addresses, absl::GetFlag(FLAGS_shared_socket), - absl::GetFlag(FLAGS_interval), - absl::GetFlag(FLAGS_pings_per_ip), absl::GetFlag(FLAGS_timeout), - AsyncCallback(finish_callback)); - thread.Run(); - return 0; -} diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn index d0de88b60b..0c58b5e482 100644 --- a/p2p/BUILD.gn +++ b/p2p/BUILD.gn @@ -9,10 +9,7 @@ import("../webrtc.gni") group("p2p") { - deps = [ - ":libstunprober", - ":rtc_p2p", - ] + deps = [ ":rtc_p2p" ] } rtc_library("rtc_p2p") { @@ -1258,53 +1255,3 @@ rtc_library("p2p_server_utils") { "//third_party/abseil-cpp/absl/strings:string_view", ] } - -rtc_library("libstunprober") { - visibility = [ "*" ] - sources = [ - "stunprober/stun_prober.cc", - "stunprober/stun_prober.h", - ] - - deps = [ - "../api:array_view", - "../api:async_dns_resolver", - "../api:packet_socket_factory", - "../api:sequence_checker", - "../api/task_queue:pending_task_safety_flag", - "../api/transport:stun_types", - "../api/units:time_delta", - "../rtc_base:async_packet_socket", - "../rtc_base:byte_buffer", - "../rtc_base:checks", - "../rtc_base:ip_address", - "../rtc_base:logging", - "../rtc_base:network", - "../rtc_base:socket_address", - "../rtc_base:ssl", - "../rtc_base:threading", - "../rtc_base:timeutils", - "../rtc_base/network:received_packet", - "../rtc_base/system:rtc_export", - ] -} - -if (rtc_include_tests) { - rtc_library("libstunprober_unittests") { - testonly = true - - sources = [ "stunprober/stun_prober_unittest.cc" ] - deps = [ - ":basic_packet_socket_factory", - ":libstunprober", - ":p2p_test_utils", - "../rtc_base:checks", - "../rtc_base:gunit_helpers", - "../rtc_base:ip_address", - "../rtc_base:rtc_base_tests_utils", - "../rtc_base:ssl_adapter", - "../test:test_support", - "//testing/gtest", - ] - } -} diff --git a/p2p/stunprober/stun_prober.cc b/p2p/stunprober/stun_prober.cc deleted file mode 100644 index d130d780dc..0000000000 --- a/p2p/stunprober/stun_prober.cc +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/stunprober/stun_prober.h" - -#include -#include -#include -#include -#include -#include - -#include "api/array_view.h" -#include "api/packet_socket_factory.h" -#include "api/task_queue/pending_task_safety_flag.h" -#include "api/transport/stun.h" -#include "api/units/time_delta.h" -#include "rtc_base/async_packet_socket.h" -#include "rtc_base/checks.h" -#include "rtc_base/network/received_packet.h" -#include "rtc_base/thread.h" -#include "rtc_base/time_utils.h" - -namespace stunprober { - -namespace { -using ::webrtc::SafeTask; -using ::webrtc::TimeDelta; - -const int THREAD_WAKE_UP_INTERVAL_MS = 5; - -template -void IncrementCounterByAddress(std::map* counter_per_ip, const T& ip) { - counter_per_ip->insert(std::make_pair(ip, 0)).first->second++; -} - -} // namespace - -// A requester tracks the requests and responses from a single socket to many -// STUN servers -class StunProber::Requester : public sigslot::has_slots<> { - public: - // Each Request maps to a request and response. - struct Request { - // Actual time the STUN bind request was sent. - int64_t sent_time_ms = 0; - // Time the response was received. - int64_t received_time_ms = 0; - - // Server reflexive address from STUN response for this given request. - rtc::SocketAddress srflx_addr; - - rtc::IPAddress server_addr; - - int64_t rtt() { return received_time_ms - sent_time_ms; } - void ProcessResponse(rtc::ArrayView payload); - }; - - // StunProber provides `server_ips` for Requester to probe. For shared - // socket mode, it'll be all the resolved IP addresses. For non-shared mode, - // it'll just be a single address. - Requester(StunProber* prober, - rtc::AsyncPacketSocket* socket, - const std::vector& server_ips); - ~Requester() override; - - Requester(const Requester&) = delete; - Requester& operator=(const Requester&) = delete; - - // There is no callback for SendStunRequest as the underneath socket send is - // expected to be completed immediately. Otherwise, it'll skip this request - // and move to the next one. - void SendStunRequest(); - - void OnStunResponseReceived(rtc::AsyncPacketSocket* socket, - const rtc::ReceivedPacket& packet); - - const std::vector& requests() { return requests_; } - - // Whether this Requester has completed all requests. - bool Done() { - return static_cast(num_request_sent_) == server_ips_.size(); - } - - private: - Request* GetRequestByAddress(const rtc::IPAddress& ip); - - StunProber* prober_; - - // The socket for this session. - std::unique_ptr socket_; - - // Temporary SocketAddress and buffer for RecvFrom. - rtc::SocketAddress addr_; - std::unique_ptr response_packet_; - - std::vector requests_; - std::vector server_ips_; - int16_t num_request_sent_ = 0; - int16_t num_response_received_ = 0; - - webrtc::SequenceChecker& thread_checker_; -}; - -StunProber::Requester::Requester( - StunProber* prober, - rtc::AsyncPacketSocket* socket, - const std::vector& server_ips) - : prober_(prober), - socket_(socket), - response_packet_(new rtc::ByteBufferWriter(nullptr, kMaxUdpBufferSize)), - server_ips_(server_ips), - thread_checker_(prober->thread_checker_) { - socket_->RegisterReceivedPacketCallback( - [&](rtc::AsyncPacketSocket* socket, const rtc::ReceivedPacket& packet) { - OnStunResponseReceived(socket, packet); - }); -} - -StunProber::Requester::~Requester() { - if (socket_) { - socket_->Close(); - } - for (auto* req : requests_) { - if (req) { - delete req; - } - } -} - -void StunProber::Requester::SendStunRequest() { - RTC_DCHECK(thread_checker_.IsCurrent()); - requests_.push_back(new Request()); - Request& request = *(requests_.back()); - // Random transaction ID, STUN_BINDING_REQUEST - cricket::StunMessage message(cricket::STUN_BINDING_REQUEST); - - std::unique_ptr request_packet( - new rtc::ByteBufferWriter(nullptr, kMaxUdpBufferSize)); - if (!message.Write(request_packet.get())) { - prober_->ReportOnFinished(WRITE_FAILED); - return; - } - - auto addr = server_ips_[num_request_sent_]; - request.server_addr = addr.ipaddr(); - - // The write must succeed immediately. Otherwise, the calculating of the STUN - // request timing could become too complicated. Callback is ignored by passing - // empty AsyncCallback. - rtc::PacketOptions options; - int rv = socket_->SendTo(request_packet->Data(), request_packet->Length(), - addr, options); - if (rv < 0) { - prober_->ReportOnFinished(WRITE_FAILED); - return; - } - - request.sent_time_ms = rtc::TimeMillis(); - - num_request_sent_++; - RTC_DCHECK(static_cast(num_request_sent_) <= server_ips_.size()); -} - -void StunProber::Requester::Request::ProcessResponse( - rtc::ArrayView payload) { - int64_t now = rtc::TimeMillis(); - rtc::ByteBufferReader message(payload); - cricket::StunMessage stun_response; - if (!stun_response.Read(&message)) { - // Invalid or incomplete STUN packet. - received_time_ms = 0; - return; - } - - // Get external address of the socket. - const cricket::StunAddressAttribute* addr_attr = - stun_response.GetAddress(cricket::STUN_ATTR_MAPPED_ADDRESS); - if (addr_attr == nullptr) { - // Addresses not available to detect whether or not behind a NAT. - return; - } - - if (addr_attr->family() != cricket::STUN_ADDRESS_IPV4 && - addr_attr->family() != cricket::STUN_ADDRESS_IPV6) { - return; - } - - received_time_ms = now; - - srflx_addr = addr_attr->GetAddress(); -} - -void StunProber::Requester::OnStunResponseReceived( - rtc::AsyncPacketSocket* socket, - const rtc::ReceivedPacket& packet) { - RTC_DCHECK(thread_checker_.IsCurrent()); - RTC_DCHECK(socket_); - Request* request = GetRequestByAddress(packet.source_address().ipaddr()); - if (!request) { - // Something is wrong, finish the test. - prober_->ReportOnFinished(GENERIC_FAILURE); - return; - } - - num_response_received_++; - request->ProcessResponse(packet.payload()); -} - -StunProber::Requester::Request* StunProber::Requester::GetRequestByAddress( - const rtc::IPAddress& ipaddr) { - RTC_DCHECK(thread_checker_.IsCurrent()); - for (auto* request : requests_) { - if (request->server_addr == ipaddr) { - return request; - } - } - - return nullptr; -} - -StunProber::Stats::Stats() = default; - -StunProber::Stats::~Stats() = default; - -StunProber::ObserverAdapter::ObserverAdapter() = default; - -StunProber::ObserverAdapter::~ObserverAdapter() = default; - -void StunProber::ObserverAdapter::OnPrepared(StunProber* stunprober, - Status status) { - if (status == SUCCESS) { - stunprober->Start(this); - } else { - callback_(stunprober, status); - } -} - -void StunProber::ObserverAdapter::OnFinished(StunProber* stunprober, - Status status) { - callback_(stunprober, status); -} - -StunProber::StunProber(rtc::PacketSocketFactory* socket_factory, - rtc::Thread* thread, - std::vector networks) - : interval_ms_(0), - socket_factory_(socket_factory), - thread_(thread), - networks_(std::move(networks)) {} - -StunProber::~StunProber() { - RTC_DCHECK(thread_checker_.IsCurrent()); - for (auto* req : requesters_) { - if (req) { - delete req; - } - } - for (auto* s : sockets_) { - if (s) { - delete s; - } - } -} - -bool StunProber::Start(const std::vector& servers, - bool shared_socket_mode, - int interval_ms, - int num_request_per_ip, - int timeout_ms, - const AsyncCallback callback) { - observer_adapter_.set_callback(callback); - return Prepare(servers, shared_socket_mode, interval_ms, num_request_per_ip, - timeout_ms, &observer_adapter_); -} - -bool StunProber::Prepare(const std::vector& servers, - bool shared_socket_mode, - int interval_ms, - int num_request_per_ip, - int timeout_ms, - StunProber::Observer* observer) { - RTC_DCHECK(thread_checker_.IsCurrent()); - interval_ms_ = interval_ms; - shared_socket_mode_ = shared_socket_mode; - - requests_per_ip_ = num_request_per_ip; - if (requests_per_ip_ == 0 || servers.size() == 0) { - return false; - } - - timeout_ms_ = timeout_ms; - servers_ = servers; - observer_ = observer; - // Remove addresses that are already resolved. - for (auto it = servers_.begin(); it != servers_.end();) { - if (it->ipaddr().family() != AF_UNSPEC) { - all_servers_addrs_.push_back(*it); - it = servers_.erase(it); - } else { - ++it; - } - } - if (servers_.empty()) { - CreateSockets(); - return true; - } - return ResolveServerName(servers_.back()); -} - -bool StunProber::Start(StunProber::Observer* observer) { - observer_ = observer; - if (total_ready_sockets_ != total_socket_required()) { - return false; - } - MaybeScheduleStunRequests(); - return true; -} - -bool StunProber::ResolveServerName(const rtc::SocketAddress& addr) { - RTC_DCHECK(!resolver_); - resolver_ = socket_factory_->CreateAsyncDnsResolver(); - if (!resolver_) { - return false; - } - resolver_->Start(addr, [this] { OnServerResolved(resolver_->result()); }); - return true; -} - -void StunProber::OnSocketReady(rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& addr) { - total_ready_sockets_++; - if (total_ready_sockets_ == total_socket_required()) { - ReportOnPrepared(SUCCESS); - } -} - -void StunProber::OnServerResolved( - const webrtc::AsyncDnsResolverResult& result) { - RTC_DCHECK(thread_checker_.IsCurrent()); - rtc::SocketAddress received_address; - if (result.GetResolvedAddress(AF_INET, &received_address)) { - // Construct an address without the name in it. - rtc::SocketAddress addr(received_address.ipaddr(), received_address.port()); - all_servers_addrs_.push_back(addr); - } - resolver_.reset(); - servers_.pop_back(); - if (servers_.size()) { - if (!ResolveServerName(servers_.back())) { - ReportOnPrepared(RESOLVE_FAILED); - } - return; - } - - if (all_servers_addrs_.size() == 0) { - ReportOnPrepared(RESOLVE_FAILED); - return; - } - - CreateSockets(); -} - -void StunProber::CreateSockets() { - // Dedupe. - std::set addrs(all_servers_addrs_.begin(), - all_servers_addrs_.end()); - all_servers_addrs_.assign(addrs.begin(), addrs.end()); - - // Prepare all the sockets beforehand. All of them will bind to "any" address. - while (sockets_.size() < total_socket_required()) { - std::unique_ptr socket( - socket_factory_->CreateUdpSocket(rtc::SocketAddress(INADDR_ANY, 0), 0, - 0)); - if (!socket) { - ReportOnPrepared(GENERIC_FAILURE); - return; - } - // Chrome and WebRTC behave differently in terms of the state of a socket - // once returned from PacketSocketFactory::CreateUdpSocket. - if (socket->GetState() == rtc::AsyncPacketSocket::STATE_BINDING) { - socket->SignalAddressReady.connect(this, &StunProber::OnSocketReady); - } else { - OnSocketReady(socket.get(), rtc::SocketAddress(INADDR_ANY, 0)); - } - sockets_.push_back(socket.release()); - } -} - -StunProber::Requester* StunProber::CreateRequester() { - RTC_DCHECK(thread_checker_.IsCurrent()); - if (!sockets_.size()) { - return nullptr; - } - StunProber::Requester* requester; - if (shared_socket_mode_) { - requester = new Requester(this, sockets_.back(), all_servers_addrs_); - } else { - std::vector server_ip; - server_ip.push_back( - all_servers_addrs_[(num_request_sent_ % all_servers_addrs_.size())]); - requester = new Requester(this, sockets_.back(), server_ip); - } - - sockets_.pop_back(); - return requester; -} - -bool StunProber::SendNextRequest() { - if (!current_requester_ || current_requester_->Done()) { - current_requester_ = CreateRequester(); - requesters_.push_back(current_requester_); - } - if (!current_requester_) { - return false; - } - current_requester_->SendStunRequest(); - num_request_sent_++; - return true; -} - -bool StunProber::should_send_next_request(int64_t now) { - if (interval_ms_ < THREAD_WAKE_UP_INTERVAL_MS) { - return now >= next_request_time_ms_; - } else { - return (now + (THREAD_WAKE_UP_INTERVAL_MS / 2)) >= next_request_time_ms_; - } -} - -int StunProber::get_wake_up_interval_ms() { - if (interval_ms_ < THREAD_WAKE_UP_INTERVAL_MS) { - return 1; - } else { - return THREAD_WAKE_UP_INTERVAL_MS; - } -} - -void StunProber::MaybeScheduleStunRequests() { - RTC_DCHECK_RUN_ON(thread_); - int64_t now = rtc::TimeMillis(); - - if (Done()) { - thread_->PostDelayedTask( - SafeTask(task_safety_.flag(), [this] { ReportOnFinished(SUCCESS); }), - TimeDelta::Millis(timeout_ms_)); - return; - } - if (should_send_next_request(now)) { - if (!SendNextRequest()) { - ReportOnFinished(GENERIC_FAILURE); - return; - } - next_request_time_ms_ = now + interval_ms_; - } - thread_->PostDelayedTask( - SafeTask(task_safety_.flag(), [this] { MaybeScheduleStunRequests(); }), - TimeDelta::Millis(get_wake_up_interval_ms())); -} - -bool StunProber::GetStats(StunProber::Stats* prob_stats) const { - // No need to be on the same thread. - if (!prob_stats) { - return false; - } - - StunProber::Stats stats; - - int rtt_sum = 0; - int64_t first_sent_time = 0; - int64_t last_sent_time = 0; - NatType nat_type = NATTYPE_INVALID; - - // Track of how many srflx IP that we have seen. - std::set srflx_ips; - - // If we're not receiving any response on a given IP, all requests sent to - // that IP should be ignored as this could just be an DNS error. - std::map num_response_per_server; - std::map num_request_per_server; - - for (auto* requester : requesters_) { - std::map num_response_per_srflx_addr; - for (auto* request : requester->requests()) { - if (request->sent_time_ms <= 0) { - continue; - } - - ++stats.raw_num_request_sent; - IncrementCounterByAddress(&num_request_per_server, request->server_addr); - - if (!first_sent_time) { - first_sent_time = request->sent_time_ms; - } - last_sent_time = request->sent_time_ms; - - if (request->received_time_ms < request->sent_time_ms) { - continue; - } - - IncrementCounterByAddress(&num_response_per_server, request->server_addr); - IncrementCounterByAddress(&num_response_per_srflx_addr, - request->srflx_addr); - rtt_sum += request->rtt(); - stats.srflx_addrs.insert(request->srflx_addr.ToString()); - srflx_ips.insert(request->srflx_addr.ipaddr()); - } - - // If we're using shared mode and seeing >1 srflx addresses for a single - // requester, it's symmetric NAT. - if (shared_socket_mode_ && num_response_per_srflx_addr.size() > 1) { - nat_type = NATTYPE_SYMMETRIC; - } - } - - // We're probably not behind a regular NAT. We have more than 1 distinct - // server reflexive IPs. - if (srflx_ips.size() > 1) { - return false; - } - - int num_sent = 0; - int num_received = 0; - int num_server_ip_with_response = 0; - - for (const auto& kv : num_response_per_server) { - RTC_DCHECK_GT(kv.second, 0); - num_server_ip_with_response++; - num_received += kv.second; - num_sent += num_request_per_server[kv.first]; - } - - // Shared mode is only true if we use the shared socket and there are more - // than 1 responding servers. - stats.shared_socket_mode = - shared_socket_mode_ && (num_server_ip_with_response > 1); - - if (stats.shared_socket_mode && nat_type == NATTYPE_INVALID) { - nat_type = NATTYPE_NON_SYMMETRIC; - } - - // If we could find a local IP matching srflx, we're not behind a NAT. - rtc::SocketAddress srflx_addr; - if (stats.srflx_addrs.size() && - !srflx_addr.FromString(*(stats.srflx_addrs.begin()))) { - return false; - } - for (const auto* net : networks_) { - if (srflx_addr.ipaddr() == net->GetBestIP()) { - nat_type = stunprober::NATTYPE_NONE; - stats.host_ip = net->GetBestIP().ToString(); - break; - } - } - - // Finally, we know we're behind a NAT but can't determine which type it is. - if (nat_type == NATTYPE_INVALID) { - nat_type = NATTYPE_UNKNOWN; - } - - stats.nat_type = nat_type; - stats.num_request_sent = num_sent; - stats.num_response_received = num_received; - stats.target_request_interval_ns = interval_ms_ * 1000; - - if (num_sent) { - stats.success_percent = static_cast(100 * num_received / num_sent); - } - - if (stats.raw_num_request_sent > 1) { - stats.actual_request_interval_ns = - (1000 * (last_sent_time - first_sent_time)) / - (stats.raw_num_request_sent - 1); - } - - if (num_received) { - stats.average_rtt_ms = static_cast((rtt_sum / num_received)); - } - - *prob_stats = stats; - return true; -} - -void StunProber::ReportOnPrepared(StunProber::Status status) { - if (observer_) { - observer_->OnPrepared(this, status); - } -} - -void StunProber::ReportOnFinished(StunProber::Status status) { - if (observer_) { - observer_->OnFinished(this, status); - } -} - -} // namespace stunprober diff --git a/p2p/stunprober/stun_prober.h b/p2p/stunprober/stun_prober.h deleted file mode 100644 index 07f3a17233..0000000000 --- a/p2p/stunprober/stun_prober.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef P2P_STUNPROBER_STUN_PROBER_H_ -#define P2P_STUNPROBER_STUN_PROBER_H_ - -#include -#include -#include -#include - -#include "api/async_dns_resolver.h" -#include "api/sequence_checker.h" -#include "api/task_queue/pending_task_safety_flag.h" -#include "rtc_base/network.h" -#include "rtc_base/socket_address.h" -#include "rtc_base/system/rtc_export.h" -#include "rtc_base/thread.h" - -namespace rtc { -class AsyncPacketSocket; -class PacketSocketFactory; -class Thread; -class NetworkManager; -class AsyncResolverInterface; -} // namespace rtc - -namespace stunprober { - -class StunProber; - -static const int kMaxUdpBufferSize = 1200; - -typedef std::function AsyncCallback; - -enum NatType { - NATTYPE_INVALID, - NATTYPE_NONE, // Not behind a NAT. - NATTYPE_UNKNOWN, // Behind a NAT but type can't be determine. - NATTYPE_SYMMETRIC, // Behind a symmetric NAT. - NATTYPE_NON_SYMMETRIC // Behind a non-symmetric NAT. -}; - -class RTC_EXPORT StunProber : public sigslot::has_slots<> { - public: - enum Status { // Used in UMA_HISTOGRAM_ENUMERATION. - SUCCESS, // Successfully received bytes from the server. - GENERIC_FAILURE, // Generic failure. - RESOLVE_FAILED, // Host resolution failed. - WRITE_FAILED, // Sending a message to the server failed. - READ_FAILED, // Reading the reply from the server failed. - }; - - class Observer { - public: - virtual ~Observer() = default; - virtual void OnPrepared(StunProber* prober, StunProber::Status status) = 0; - virtual void OnFinished(StunProber* prober, StunProber::Status status) = 0; - }; - - struct RTC_EXPORT Stats { - Stats(); - ~Stats(); - - // `raw_num_request_sent` is the total number of requests - // sent. `num_request_sent` is the count of requests against a server where - // we see at least one response. `num_request_sent` is designed to protect - // against DNS resolution failure or the STUN server is not responsive - // which could skew the result. - int raw_num_request_sent = 0; - int num_request_sent = 0; - - int num_response_received = 0; - NatType nat_type = NATTYPE_INVALID; - int average_rtt_ms = -1; - int success_percent = 0; - int target_request_interval_ns = 0; - int actual_request_interval_ns = 0; - - // Also report whether this trial can't be considered truly as shared - // mode. Share mode only makes sense when we have multiple IP resolved and - // successfully probed. - bool shared_socket_mode = false; - - std::string host_ip; - - // If the srflx_addrs has more than 1 element, the NAT is symmetric. - std::set srflx_addrs; - }; - - StunProber(rtc::PacketSocketFactory* socket_factory, - rtc::Thread* thread, - std::vector networks); - ~StunProber() override; - - StunProber(const StunProber&) = delete; - StunProber& operator=(const StunProber&) = delete; - - // Begin performing the probe test against the `servers`. If - // `shared_socket_mode` is false, each request will be done with a new socket. - // Otherwise, a unique socket will be used for a single round of requests - // against all resolved IPs. No single socket will be used against a given IP - // more than once. The interval of requests will be as close to the requested - // inter-probe interval `stun_ta_interval_ms` as possible. After sending out - // the last scheduled request, the probe will wait `timeout_ms` for request - // responses and then call `finish_callback`. `requests_per_ip` indicates how - // many requests should be tried for each resolved IP address. In shared mode, - // (the number of sockets to be created) equals to `requests_per_ip`. In - // non-shared mode, (the number of sockets) equals to requests_per_ip * (the - // number of resolved IP addresses). TODO(guoweis): Remove this once - // everything moved to Prepare() and Run(). - bool Start(const std::vector& servers, - bool shared_socket_mode, - int stun_ta_interval_ms, - int requests_per_ip, - int timeout_ms, - AsyncCallback finish_callback); - - // TODO(guoweis): The combination of Prepare() and Run() are equivalent to the - // Start() above. Remove Start() once everything is migrated. - bool Prepare(const std::vector& servers, - bool shared_socket_mode, - int stun_ta_interval_ms, - int requests_per_ip, - int timeout_ms, - StunProber::Observer* observer); - - // Start to send out the STUN probes. - bool Start(StunProber::Observer* observer); - - // Method to retrieve the Stats once `finish_callback` is invoked. Returning - // false when the result is inconclusive, for example, whether it's behind a - // NAT or not. - bool GetStats(Stats* stats) const; - - int estimated_execution_time() { - return static_cast(requests_per_ip_ * all_servers_addrs_.size() * - interval_ms_); - } - - private: - // A requester tracks the requests and responses from a single socket to many - // STUN servers. - class Requester; - - // TODO(guoweis): Remove this once all dependencies move away from - // AsyncCallback. - class ObserverAdapter : public Observer { - public: - ObserverAdapter(); - ~ObserverAdapter() override; - - void set_callback(AsyncCallback callback) { callback_ = callback; } - void OnPrepared(StunProber* stunprober, Status status) override; - void OnFinished(StunProber* stunprober, Status status) override; - - private: - AsyncCallback callback_; - }; - - bool ResolveServerName(const rtc::SocketAddress& addr); - void OnServerResolved(const webrtc::AsyncDnsResolverResult& resolver); - - void OnSocketReady(rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& addr); - - void CreateSockets(); - - bool Done() { - return num_request_sent_ >= requests_per_ip_ * all_servers_addrs_.size(); - } - - size_t total_socket_required() { - return (shared_socket_mode_ ? 1 : all_servers_addrs_.size()) * - requests_per_ip_; - } - - bool should_send_next_request(int64_t now); - int get_wake_up_interval_ms(); - - bool SendNextRequest(); - - // Will be invoked in 1ms intervals and schedule the next request from the - // `current_requester_` if the time has passed for another request. - void MaybeScheduleStunRequests(); - - void ReportOnPrepared(StunProber::Status status); - void ReportOnFinished(StunProber::Status status); - - Requester* CreateRequester(); - - Requester* current_requester_ = nullptr; - - // The time when the next request should go out. - int64_t next_request_time_ms_ = 0; - - // Total requests sent so far. - uint32_t num_request_sent_ = 0; - - bool shared_socket_mode_ = false; - - // How many requests should be done against each resolved IP. - uint32_t requests_per_ip_ = 0; - - // Milliseconds to pause between each STUN request. - int interval_ms_; - - // Timeout period after the last request is sent. - int timeout_ms_; - - // STUN server name to be resolved. - std::vector servers_; - - // Weak references. - rtc::PacketSocketFactory* socket_factory_; - rtc::Thread* thread_; - - // Accumulate all resolved addresses. - std::vector all_servers_addrs_; - - // The set of STUN probe sockets and their state. - std::vector requesters_; - - webrtc::SequenceChecker thread_checker_; - - // Temporary storage for created sockets. - std::vector sockets_; - // This tracks how many of the sockets are ready. - size_t total_ready_sockets_ = 0; - - Observer* observer_ = nullptr; - // TODO(guoweis): Remove this once all dependencies move away from - // AsyncCallback. - ObserverAdapter observer_adapter_; - - const std::vector networks_; - std::unique_ptr resolver_; - - webrtc::ScopedTaskSafety task_safety_; -}; - -} // namespace stunprober - -#endif // P2P_STUNPROBER_STUN_PROBER_H_ diff --git a/p2p/stunprober/stun_prober_unittest.cc b/p2p/stunprober/stun_prober_unittest.cc deleted file mode 100644 index 1aa2be2844..0000000000 --- a/p2p/stunprober/stun_prober_unittest.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/stunprober/stun_prober.h" - -#include - -#include -#include - -#include "p2p/base/basic_packet_socket_factory.h" -#include "p2p/base/test_stun_server.h" -#include "rtc_base/gunit.h" -#include "rtc_base/ip_address.h" -#include "rtc_base/ssl_adapter.h" -#include "rtc_base/virtual_socket_server.h" -#include "test/gtest.h" - -using stunprober::AsyncCallback; -using stunprober::StunProber; - -namespace stunprober { - -namespace { - -const rtc::SocketAddress kLocalAddr("192.168.0.1", 0); -const rtc::SocketAddress kStunAddr1("1.1.1.1", 3478); -const rtc::SocketAddress kStunAddr2("1.1.1.2", 3478); -const rtc::SocketAddress kFailedStunAddr("1.1.1.3", 3478); -const rtc::SocketAddress kStunMappedAddr("77.77.77.77", 0); - -} // namespace - -class StunProberTest : public ::testing::Test { - public: - StunProberTest() - : ss_(std::make_unique()), - main_(ss_.get()), - result_(StunProber::SUCCESS), - stun_server_1_( - cricket::TestStunServer::Create(ss_.get(), kStunAddr1, main_)), - stun_server_2_( - cricket::TestStunServer::Create(ss_.get(), kStunAddr2, main_)) { - stun_server_1_->set_fake_stun_addr(kStunMappedAddr); - stun_server_2_->set_fake_stun_addr(kStunMappedAddr); - rtc::InitializeSSL(); - } - - static constexpr int pings_per_ip = 3; - - void set_expected_result(int result) { result_ = result; } - - void CreateProber(rtc::PacketSocketFactory* socket_factory, - std::vector networks) { - prober_ = std::make_unique(socket_factory, &main_, - std::move(networks)); - } - - void StartProbing(rtc::PacketSocketFactory* socket_factory, - const std::vector& addrs, - std::vector networks, - bool shared_socket, - uint16_t interval, - uint16_t pings_per_ip) { - CreateProber(socket_factory, networks); - prober_->Start(addrs, shared_socket, interval, pings_per_ip, - 100 /* timeout_ms */, - [this](StunProber* prober, int result) { - StopCallback(prober, result); - }); - } - - void RunProber(bool shared_mode) { - std::vector addrs; - addrs.push_back(kStunAddr1); - addrs.push_back(kStunAddr2); - // Add a non-existing server. This shouldn't pollute the result. - addrs.push_back(kFailedStunAddr); - RunProber(shared_mode, addrs, /* check_results= */ true); - } - - void RunProber(bool shared_mode, - const std::vector& addrs, - bool check_results) { - rtc::Network ipv4_network1("test_eth0", "Test Network Adapter 1", - rtc::IPAddress(0x12345600U), 24); - ipv4_network1.AddIP(rtc::IPAddress(0x12345678)); - std::vector networks; - networks.push_back(&ipv4_network1); - - auto socket_factory = - std::make_unique(ss_.get()); - - // Set up the expected results for verification. - std::set srflx_addresses; - srflx_addresses.insert(kStunMappedAddr.ToString()); - const uint32_t total_pings_tried = - static_cast(pings_per_ip * addrs.size()); - - // The reported total_pings should not count for pings sent to the - // kFailedStunAddr. - const uint32_t total_pings_reported = total_pings_tried - pings_per_ip; - - StartProbing(socket_factory.get(), addrs, std::move(networks), shared_mode, - 3, pings_per_ip); - - WAIT(stopped_, 1000); - - EXPECT_TRUE(prober_->GetStats(&stats_)); - if (check_results) { - EXPECT_EQ(stats_.success_percent, 100); - EXPECT_TRUE(stats_.nat_type > stunprober::NATTYPE_NONE); - EXPECT_EQ(stats_.srflx_addrs, srflx_addresses); - EXPECT_EQ(static_cast(stats_.num_request_sent), - total_pings_reported); - EXPECT_EQ(static_cast(stats_.num_response_received), - total_pings_reported); - } - } - - StunProber* prober() { return prober_.get(); } - StunProber::Stats& stats() { return stats_; } - - private: - void StopCallback(StunProber* prober, int result) { - EXPECT_EQ(result, result_); - stopped_ = true; - } - - std::unique_ptr ss_; - rtc::AutoSocketServerThread main_; - std::unique_ptr prober_; - int result_ = 0; - bool stopped_ = false; - cricket::TestStunServer::StunServerPtr stun_server_1_; - cricket::TestStunServer::StunServerPtr stun_server_2_; - StunProber::Stats stats_; -}; - -TEST_F(StunProberTest, NonSharedMode) { - RunProber(false); -} - -TEST_F(StunProberTest, SharedMode) { - RunProber(true); -} - -TEST_F(StunProberTest, ResolveNonexistentHostname) { - std::vector addrs; - addrs.push_back(kStunAddr1); - // Add a non-existing server by name. This should cause a failed lookup. - addrs.push_back(rtc::SocketAddress("nonexistent.test", 3478)); - RunProber(false, addrs, false); - // One server is pinged - EXPECT_EQ(stats().raw_num_request_sent, pings_per_ip); -} - -TEST_F(StunProberTest, ResolveExistingHostname) { - std::vector addrs; - addrs.push_back(kStunAddr1); - // Add a non-existing server by name. This should cause a failed lookup. - addrs.push_back(rtc::SocketAddress("localhost", 3478)); - RunProber(false, addrs, false); - // Two servers are pinged, only one responds. - // TODO(bugs.webrtc.org/15559): Figure out why this doesn't always work - // EXPECT_EQ(stats().raw_num_request_sent, pings_per_ip * 2); - EXPECT_EQ(stats().num_request_sent, pings_per_ip); -} - -} // namespace stunprober