diff options
Diffstat (limited to 'third_party/libwebrtc/p2p/base/turn_port.h')
-rw-r--r-- | third_party/libwebrtc/p2p/base/turn_port.h | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/third_party/libwebrtc/p2p/base/turn_port.h b/third_party/libwebrtc/p2p/base/turn_port.h new file mode 100644 index 0000000000..e33f75e947 --- /dev/null +++ b/third_party/libwebrtc/p2p/base/turn_port.h @@ -0,0 +1,390 @@ +/* + * Copyright 2012 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_BASE_TURN_PORT_H_ +#define P2P_BASE_TURN_PORT_H_ + +#include <stdio.h> + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "api/async_dns_resolver.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "p2p/base/port.h" +#include "p2p/client/basic_port_allocator.h" +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/ssl_certificate.h" + +namespace webrtc { +class TurnCustomizer; +} + +namespace cricket { + +const int kMaxTurnUsernameLength = 509; // RFC 8489 section 14.3 + +extern const int STUN_ATTR_TURN_LOGGING_ID; +extern const char TURN_PORT_TYPE[]; +class TurnAllocateRequest; +class TurnEntry; + +class TurnPort : public Port { + public: + enum PortState { + STATE_CONNECTING, // Initial state, cannot send any packets. + STATE_CONNECTED, // Socket connected, ready to send stun requests. + STATE_READY, // Received allocate success, can send any packets. + STATE_RECEIVEONLY, // Had REFRESH_REQUEST error, cannot send any packets. + STATE_DISCONNECTED, // TCP connection died, cannot send/receive any + // packets. + }; + + static bool Validate(const CreateRelayPortArgs& args) { + // Do basic parameter validation. + if (args.config->credentials.username.size() > kMaxTurnUsernameLength) { + RTC_LOG(LS_ERROR) << "Attempt to use TURN with a too long username " + << "of length " + << args.config->credentials.username.size(); + return false; + } + // Do not connect to low-numbered ports. The default STUN port is 3478. + if (!AllowedTurnPort(args.server_address->address.port(), + args.field_trials)) { + RTC_LOG(LS_ERROR) << "Attempt to use TURN to connect to port " + << args.server_address->address.port(); + return false; + } + return true; + } + + // Create a TURN port using the shared UDP socket, `socket`. + static std::unique_ptr<TurnPort> Create(const CreateRelayPortArgs& args, + rtc::AsyncPacketSocket* socket) { + if (!Validate(args)) { + return nullptr; + } + // Using `new` to access a non-public constructor. + return absl::WrapUnique( + new TurnPort(args.network_thread, args.socket_factory, args.network, + socket, args.username, args.password, *args.server_address, + args.config->credentials, args.config->priority, + args.config->tls_alpn_protocols, + args.config->tls_elliptic_curves, args.turn_customizer, + args.config->tls_cert_verifier, args.field_trials)); + } + + // Create a TURN port that will use a new socket, bound to `network` and + // using a port in the range between `min_port` and `max_port`. + static std::unique_ptr<TurnPort> Create(const CreateRelayPortArgs& args, + int min_port, + int max_port) { + if (!Validate(args)) { + return nullptr; + } + // Using `new` to access a non-public constructor. + return absl::WrapUnique( + new TurnPort(args.network_thread, args.socket_factory, args.network, + min_port, max_port, args.username, args.password, + *args.server_address, args.config->credentials, + args.config->priority, args.config->tls_alpn_protocols, + args.config->tls_elliptic_curves, args.turn_customizer, + args.config->tls_cert_verifier, args.field_trials)); + } + + ~TurnPort() override; + + const ProtocolAddress& server_address() const { return server_address_; } + // Returns an empty address if the local address has not been assigned. + rtc::SocketAddress GetLocalAddress() const; + + bool ready() const { return state_ == STATE_READY; } + bool connected() const { + return state_ == STATE_READY || state_ == STATE_CONNECTED; + } + const RelayCredentials& credentials() const { return credentials_; } + + ProtocolType GetProtocol() const override; + + virtual TlsCertPolicy GetTlsCertPolicy() const; + virtual void SetTlsCertPolicy(TlsCertPolicy tls_cert_policy); + + void SetTurnLoggingId(absl::string_view turn_logging_id); + + virtual std::vector<std::string> GetTlsAlpnProtocols() const; + virtual std::vector<std::string> GetTlsEllipticCurves() const; + + // Release a TURN allocation by sending a refresh with lifetime 0. + // Sets state to STATE_RECEIVEONLY. + void Release(); + + void PrepareAddress() override; + Connection* CreateConnection(const Candidate& c, + PortInterface::CandidateOrigin origin) override; + int SendTo(const void* data, + size_t size, + const rtc::SocketAddress& addr, + const rtc::PacketOptions& options, + bool payload) override; + int SetOption(rtc::Socket::Option opt, int value) override; + int GetOption(rtc::Socket::Option opt, int* value) override; + int GetError() override; + + bool HandleIncomingPacket(rtc::AsyncPacketSocket* socket, + const char* data, + size_t size, + const rtc::SocketAddress& remote_addr, + int64_t packet_time_us) override; + bool CanHandleIncomingPacketsFrom( + const rtc::SocketAddress& addr) const override; + virtual void OnReadPacket(rtc::AsyncPacketSocket* socket, + const char* data, + size_t size, + const rtc::SocketAddress& remote_addr, + const int64_t& packet_time_us); + + void OnSentPacket(rtc::AsyncPacketSocket* socket, + const rtc::SentPacket& sent_packet) override; + virtual void OnReadyToSend(rtc::AsyncPacketSocket* socket); + bool SupportsProtocol(absl::string_view protocol) const override; + + void OnSocketConnect(rtc::AsyncPacketSocket* socket); + void OnSocketClose(rtc::AsyncPacketSocket* socket, int error); + + const std::string& hash() const { return hash_; } + const std::string& nonce() const { return nonce_; } + + int error() const { return error_; } + + void OnAllocateMismatch(); + + rtc::AsyncPacketSocket* socket() const { return socket_; } + StunRequestManager& request_manager() { return request_manager_; } + + // Signal with resolved server address. + // Parameters are port, server address and resolved server address. + // This signal will be sent only if server address is resolved successfully. + sigslot:: + signal3<TurnPort*, const rtc::SocketAddress&, const rtc::SocketAddress&> + SignalResolvedServerAddress; + + // Signal when TurnPort is closed, + // e.g remote socket closed (TCP) + // or receiveing a REFRESH response with lifetime 0. + sigslot::signal1<TurnPort*> SignalTurnPortClosed; + + // All public methods/signals below are for testing only. + sigslot::signal2<TurnPort*, int> SignalTurnRefreshResult; + sigslot::signal3<TurnPort*, const rtc::SocketAddress&, int> + SignalCreatePermissionResult; + + bool HasRequests() { return !request_manager_.empty(); } + void set_credentials(const RelayCredentials& credentials) { + credentials_ = credentials; + } + // Finds the turn entry with `address` and sets its channel id. + // Returns true if the entry is found. + bool SetEntryChannelId(const rtc::SocketAddress& address, int channel_id); + + void HandleConnectionDestroyed(Connection* conn) override; + + void CloseForTest() { Close(); } + + protected: + TurnPort(rtc::Thread* thread, + rtc::PacketSocketFactory* factory, + const rtc::Network* network, + rtc::AsyncPacketSocket* socket, + absl::string_view username, + absl::string_view password, + const ProtocolAddress& server_address, + const RelayCredentials& credentials, + int server_priority, + const std::vector<std::string>& tls_alpn_protocols, + const std::vector<std::string>& tls_elliptic_curves, + webrtc::TurnCustomizer* customizer, + rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr, + const webrtc::FieldTrialsView* field_trials = nullptr); + + TurnPort(rtc::Thread* thread, + rtc::PacketSocketFactory* factory, + const rtc::Network* network, + uint16_t min_port, + uint16_t max_port, + absl::string_view username, + absl::string_view password, + const ProtocolAddress& server_address, + const RelayCredentials& credentials, + int server_priority, + const std::vector<std::string>& tls_alpn_protocols, + const std::vector<std::string>& tls_elliptic_curves, + webrtc::TurnCustomizer* customizer, + rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr, + const webrtc::FieldTrialsView* field_trials = nullptr); + + // NOTE: This method needs to be accessible for StunPort + // return true if entry was created (i.e channel_number consumed). + bool CreateOrRefreshEntry(const rtc::SocketAddress& addr, int channel_number); + + bool CreateOrRefreshEntry(const rtc::SocketAddress& addr, + int channel_number, + absl::string_view remote_ufrag); + + rtc::DiffServCodePoint StunDscpValue() const override; + + // Shuts down the turn port, frees requests and deletes connections. + void Close(); + + private: + enum { + MSG_ALLOCATE_ERROR = MSG_FIRST_AVAILABLE, + MSG_ALLOCATE_MISMATCH, + MSG_TRY_ALTERNATE_SERVER, + MSG_REFRESH_ERROR, + MSG_ALLOCATION_RELEASED + }; + + typedef std::list<TurnEntry*> EntryList; + typedef std::map<rtc::Socket::Option, int> SocketOptionsMap; + typedef std::set<rtc::SocketAddress> AttemptedServerSet; + + static bool AllowedTurnPort(int port, + const webrtc::FieldTrialsView* field_trials); + void OnMessage(rtc::Message* pmsg) override; + + bool CreateTurnClientSocket(); + + void set_nonce(absl::string_view nonce) { nonce_ = std::string(nonce); } + void set_realm(absl::string_view realm) { + if (realm != realm_) { + realm_ = std::string(realm); + UpdateHash(); + } + } + + void OnRefreshError(); + void HandleRefreshError(); + bool SetAlternateServer(const rtc::SocketAddress& address); + void ResolveTurnAddress(const rtc::SocketAddress& address); + void OnResolveResult(rtc::AsyncResolverInterface* resolver); + + void AddRequestAuthInfo(StunMessage* msg); + void OnSendStunPacket(const void* data, size_t size, StunRequest* request); + // Stun address from allocate success response. + // Currently used only for testing. + void OnStunAddress(const rtc::SocketAddress& address); + void OnAllocateSuccess(const rtc::SocketAddress& address, + const rtc::SocketAddress& stun_address); + void OnAllocateError(int error_code, absl::string_view reason); + void OnAllocateRequestTimeout(); + + void HandleDataIndication(const char* data, + size_t size, + int64_t packet_time_us); + void HandleChannelData(int channel_id, + const char* data, + size_t size, + int64_t packet_time_us); + void DispatchPacket(const char* data, + size_t size, + const rtc::SocketAddress& remote_addr, + ProtocolType proto, + int64_t packet_time_us); + + bool ScheduleRefresh(uint32_t lifetime); + void SendRequest(StunRequest* request, int delay); + int Send(const void* data, size_t size, const rtc::PacketOptions& options); + void UpdateHash(); + bool UpdateNonce(StunMessage* response); + void ResetNonce(); + + bool HasPermission(const rtc::IPAddress& ipaddr) const; + TurnEntry* FindEntry(const rtc::SocketAddress& address) const; + TurnEntry* FindEntry(int channel_id) const; + bool EntryExists(TurnEntry* e); + void DestroyEntry(TurnEntry* entry); + // Destroys the entry only if `timestamp` matches the destruction timestamp + // in `entry`. + void DestroyEntryIfNotCancelled(TurnEntry* entry, int64_t timestamp); + + // Marks the connection with remote address `address` failed and + // pruned (a.k.a. write-timed-out). Returns true if a connection is found. + bool FailAndPruneConnection(const rtc::SocketAddress& address); + + // Reconstruct the URL of the server which the candidate is gathered from. + std::string ReconstructedServerUrl(); + + void MaybeAddTurnLoggingId(StunMessage* message); + + void TurnCustomizerMaybeModifyOutgoingStunMessage(StunMessage* message); + bool TurnCustomizerAllowChannelData(const void* data, + size_t size, + bool payload); + + ProtocolAddress server_address_; + TlsCertPolicy tls_cert_policy_ = TlsCertPolicy::TLS_CERT_POLICY_SECURE; + std::vector<std::string> tls_alpn_protocols_; + std::vector<std::string> tls_elliptic_curves_; + rtc::SSLCertificateVerifier* tls_cert_verifier_; + RelayCredentials credentials_; + AttemptedServerSet attempted_server_addresses_; + + rtc::AsyncPacketSocket* socket_; + SocketOptionsMap socket_options_; + std::unique_ptr<webrtc::AsyncDnsResolverInterface> resolver_; + int error_; + rtc::DiffServCodePoint stun_dscp_value_; + + StunRequestManager request_manager_; + std::string realm_; // From 401/438 response message. + std::string nonce_; // From 401/438 response message. + std::string hash_; // Digest of username:realm:password + + int next_channel_number_; + EntryList entries_; + + PortState state_; + // By default the value will be set to 0. This value will be used in + // calculating the candidate priority. + int server_priority_; + + // The number of retries made due to allocate mismatch error. + size_t allocate_mismatch_retries_; + + // Optional TurnCustomizer that can modify outgoing messages. Once set, this + // must outlive the TurnPort's lifetime. + webrtc::TurnCustomizer* turn_customizer_ = nullptr; + + // Optional TurnLoggingId. + // An identifier set by application that is added to TURN_ALLOCATE_REQUEST + // and can be used to match client/backend logs. + // TODO(jonaso): This should really be initialized in constructor, + // but that is currently so terrible. Fix once constructor is changed + // to be more easy to work with. + std::string turn_logging_id_; + + webrtc::ScopedTaskSafety task_safety_; + + friend class TurnEntry; + friend class TurnAllocateRequest; + friend class TurnRefreshRequest; + friend class TurnCreatePermissionRequest; + friend class TurnChannelBindRequest; +}; + +} // namespace cricket + +#endif // P2P_BASE_TURN_PORT_H_ |