1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2012 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/turn_port.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <functional>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <utility>
16*d9f75844SAndroid Build Coastguard Worker #include <vector>
17*d9f75844SAndroid Build Coastguard Worker
18*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
19*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/match.h"
20*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
21*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/pending_task_safety_flag.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/transport/stun.h"
24*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/connection.h"
25*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/p2p_constants.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/async_packet_socket.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/byte_order.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
29*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/field_trial_parser.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/net_helpers.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/socket_address.h"
33*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
34*d9f75844SAndroid Build Coastguard Worker
35*d9f75844SAndroid Build Coastguard Worker namespace cricket {
36*d9f75844SAndroid Build Coastguard Worker
37*d9f75844SAndroid Build Coastguard Worker namespace {
38*d9f75844SAndroid Build Coastguard Worker
ResolveTurnHostnameForFamily(const webrtc::FieldTrialsView & field_trials)39*d9f75844SAndroid Build Coastguard Worker bool ResolveTurnHostnameForFamily(const webrtc::FieldTrialsView& field_trials) {
40*d9f75844SAndroid Build Coastguard Worker // Bug fix for TURN hostname resolution on IPv6.
41*d9f75844SAndroid Build Coastguard Worker // Field trial key reserved in bugs.webrtc.org/14334
42*d9f75844SAndroid Build Coastguard Worker static constexpr char field_trial_name[] =
43*d9f75844SAndroid Build Coastguard Worker "WebRTC-IPv6NetworkResolutionFixes";
44*d9f75844SAndroid Build Coastguard Worker if (!field_trials.IsEnabled(field_trial_name)) {
45*d9f75844SAndroid Build Coastguard Worker return false;
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker
48*d9f75844SAndroid Build Coastguard Worker webrtc::FieldTrialParameter<bool> resolve_turn_hostname_for_family(
49*d9f75844SAndroid Build Coastguard Worker "ResolveTurnHostnameForFamily", /*default_value=*/false);
50*d9f75844SAndroid Build Coastguard Worker webrtc::ParseFieldTrial({&resolve_turn_hostname_for_family},
51*d9f75844SAndroid Build Coastguard Worker field_trials.Lookup(field_trial_name));
52*d9f75844SAndroid Build Coastguard Worker return resolve_turn_hostname_for_family;
53*d9f75844SAndroid Build Coastguard Worker }
54*d9f75844SAndroid Build Coastguard Worker
55*d9f75844SAndroid Build Coastguard Worker } // namespace
56*d9f75844SAndroid Build Coastguard Worker
57*d9f75844SAndroid Build Coastguard Worker using ::webrtc::SafeTask;
58*d9f75844SAndroid Build Coastguard Worker using ::webrtc::TaskQueueBase;
59*d9f75844SAndroid Build Coastguard Worker using ::webrtc::TimeDelta;
60*d9f75844SAndroid Build Coastguard Worker
61*d9f75844SAndroid Build Coastguard Worker // TODO(juberti): Move to stun.h when relay messages have been renamed.
62*d9f75844SAndroid Build Coastguard Worker static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
63*d9f75844SAndroid Build Coastguard Worker
64*d9f75844SAndroid Build Coastguard Worker // Attributes in comprehension-optional range,
65*d9f75844SAndroid Build Coastguard Worker // ignored by TURN server that doesn't know about them.
66*d9f75844SAndroid Build Coastguard Worker // https://tools.ietf.org/html/rfc5389#section-18.2
67*d9f75844SAndroid Build Coastguard Worker const int STUN_ATTR_TURN_LOGGING_ID = 0xff05;
68*d9f75844SAndroid Build Coastguard Worker
69*d9f75844SAndroid Build Coastguard Worker // TODO(juberti): Extract to turnmessage.h
70*d9f75844SAndroid Build Coastguard Worker static const int TURN_DEFAULT_PORT = 3478;
71*d9f75844SAndroid Build Coastguard Worker static const int TURN_CHANNEL_NUMBER_START = 0x4000;
72*d9f75844SAndroid Build Coastguard Worker
73*d9f75844SAndroid Build Coastguard Worker static constexpr TimeDelta kTurnPermissionTimeout = TimeDelta::Minutes(5);
74*d9f75844SAndroid Build Coastguard Worker
75*d9f75844SAndroid Build Coastguard Worker static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
76*d9f75844SAndroid Build Coastguard Worker
77*d9f75844SAndroid Build Coastguard Worker // Retry at most twice (i.e. three different ALLOCATE requests) on
78*d9f75844SAndroid Build Coastguard Worker // STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
79*d9f75844SAndroid Build Coastguard Worker static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
80*d9f75844SAndroid Build Coastguard Worker
81*d9f75844SAndroid Build Coastguard Worker static const int TURN_SUCCESS_RESULT_CODE = 0;
82*d9f75844SAndroid Build Coastguard Worker
IsTurnChannelData(uint16_t msg_type)83*d9f75844SAndroid Build Coastguard Worker inline bool IsTurnChannelData(uint16_t msg_type) {
84*d9f75844SAndroid Build Coastguard Worker return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
85*d9f75844SAndroid Build Coastguard Worker }
86*d9f75844SAndroid Build Coastguard Worker
GetRelayPreference(cricket::ProtocolType proto)87*d9f75844SAndroid Build Coastguard Worker static int GetRelayPreference(cricket::ProtocolType proto) {
88*d9f75844SAndroid Build Coastguard Worker switch (proto) {
89*d9f75844SAndroid Build Coastguard Worker case cricket::PROTO_TCP:
90*d9f75844SAndroid Build Coastguard Worker return ICE_TYPE_PREFERENCE_RELAY_TCP;
91*d9f75844SAndroid Build Coastguard Worker case cricket::PROTO_TLS:
92*d9f75844SAndroid Build Coastguard Worker return ICE_TYPE_PREFERENCE_RELAY_TLS;
93*d9f75844SAndroid Build Coastguard Worker default:
94*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(proto == PROTO_UDP);
95*d9f75844SAndroid Build Coastguard Worker return ICE_TYPE_PREFERENCE_RELAY_UDP;
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker }
98*d9f75844SAndroid Build Coastguard Worker
99*d9f75844SAndroid Build Coastguard Worker class TurnAllocateRequest : public StunRequest {
100*d9f75844SAndroid Build Coastguard Worker public:
101*d9f75844SAndroid Build Coastguard Worker explicit TurnAllocateRequest(TurnPort* port);
102*d9f75844SAndroid Build Coastguard Worker void OnSent() override;
103*d9f75844SAndroid Build Coastguard Worker void OnResponse(StunMessage* response) override;
104*d9f75844SAndroid Build Coastguard Worker void OnErrorResponse(StunMessage* response) override;
105*d9f75844SAndroid Build Coastguard Worker void OnTimeout() override;
106*d9f75844SAndroid Build Coastguard Worker
107*d9f75844SAndroid Build Coastguard Worker private:
108*d9f75844SAndroid Build Coastguard Worker // Handles authentication challenge from the server.
109*d9f75844SAndroid Build Coastguard Worker void OnAuthChallenge(StunMessage* response, int code);
110*d9f75844SAndroid Build Coastguard Worker void OnTryAlternate(StunMessage* response, int code);
111*d9f75844SAndroid Build Coastguard Worker void OnUnknownAttribute(StunMessage* response);
112*d9f75844SAndroid Build Coastguard Worker
113*d9f75844SAndroid Build Coastguard Worker TurnPort* port_;
114*d9f75844SAndroid Build Coastguard Worker };
115*d9f75844SAndroid Build Coastguard Worker
116*d9f75844SAndroid Build Coastguard Worker class TurnRefreshRequest : public StunRequest {
117*d9f75844SAndroid Build Coastguard Worker public:
118*d9f75844SAndroid Build Coastguard Worker explicit TurnRefreshRequest(TurnPort* port, int lifetime = -1);
119*d9f75844SAndroid Build Coastguard Worker void OnSent() override;
120*d9f75844SAndroid Build Coastguard Worker void OnResponse(StunMessage* response) override;
121*d9f75844SAndroid Build Coastguard Worker void OnErrorResponse(StunMessage* response) override;
122*d9f75844SAndroid Build Coastguard Worker void OnTimeout() override;
123*d9f75844SAndroid Build Coastguard Worker
124*d9f75844SAndroid Build Coastguard Worker private:
125*d9f75844SAndroid Build Coastguard Worker TurnPort* port_;
126*d9f75844SAndroid Build Coastguard Worker };
127*d9f75844SAndroid Build Coastguard Worker
128*d9f75844SAndroid Build Coastguard Worker class TurnCreatePermissionRequest : public StunRequest {
129*d9f75844SAndroid Build Coastguard Worker public:
130*d9f75844SAndroid Build Coastguard Worker TurnCreatePermissionRequest(TurnPort* port,
131*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry,
132*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& ext_addr);
133*d9f75844SAndroid Build Coastguard Worker ~TurnCreatePermissionRequest() override;
134*d9f75844SAndroid Build Coastguard Worker void OnSent() override;
135*d9f75844SAndroid Build Coastguard Worker void OnResponse(StunMessage* response) override;
136*d9f75844SAndroid Build Coastguard Worker void OnErrorResponse(StunMessage* response) override;
137*d9f75844SAndroid Build Coastguard Worker void OnTimeout() override;
138*d9f75844SAndroid Build Coastguard Worker
139*d9f75844SAndroid Build Coastguard Worker private:
140*d9f75844SAndroid Build Coastguard Worker TurnPort* port_;
141*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry_;
142*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress ext_addr_;
143*d9f75844SAndroid Build Coastguard Worker };
144*d9f75844SAndroid Build Coastguard Worker
145*d9f75844SAndroid Build Coastguard Worker class TurnChannelBindRequest : public StunRequest {
146*d9f75844SAndroid Build Coastguard Worker public:
147*d9f75844SAndroid Build Coastguard Worker TurnChannelBindRequest(TurnPort* port,
148*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry,
149*d9f75844SAndroid Build Coastguard Worker int channel_id,
150*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& ext_addr);
151*d9f75844SAndroid Build Coastguard Worker ~TurnChannelBindRequest() override;
152*d9f75844SAndroid Build Coastguard Worker void OnSent() override;
153*d9f75844SAndroid Build Coastguard Worker void OnResponse(StunMessage* response) override;
154*d9f75844SAndroid Build Coastguard Worker void OnErrorResponse(StunMessage* response) override;
155*d9f75844SAndroid Build Coastguard Worker void OnTimeout() override;
156*d9f75844SAndroid Build Coastguard Worker
157*d9f75844SAndroid Build Coastguard Worker private:
158*d9f75844SAndroid Build Coastguard Worker TurnPort* port_;
159*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry_;
160*d9f75844SAndroid Build Coastguard Worker int channel_id_;
161*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress ext_addr_;
162*d9f75844SAndroid Build Coastguard Worker };
163*d9f75844SAndroid Build Coastguard Worker
164*d9f75844SAndroid Build Coastguard Worker // Manages a "connection" to a remote destination. We will attempt to bring up
165*d9f75844SAndroid Build Coastguard Worker // a channel for this remote destination to reduce the overhead of sending data.
166*d9f75844SAndroid Build Coastguard Worker class TurnEntry : public sigslot::has_slots<> {
167*d9f75844SAndroid Build Coastguard Worker public:
168*d9f75844SAndroid Build Coastguard Worker enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
169*d9f75844SAndroid Build Coastguard Worker TurnEntry(TurnPort* port, Connection* conn, int channel_id);
170*d9f75844SAndroid Build Coastguard Worker ~TurnEntry();
171*d9f75844SAndroid Build Coastguard Worker
port()172*d9f75844SAndroid Build Coastguard Worker TurnPort* port() { return port_; }
173*d9f75844SAndroid Build Coastguard Worker
channel_id() const174*d9f75844SAndroid Build Coastguard Worker int channel_id() const { return channel_id_; }
175*d9f75844SAndroid Build Coastguard Worker // For testing only.
set_channel_id(int channel_id)176*d9f75844SAndroid Build Coastguard Worker void set_channel_id(int channel_id) { channel_id_ = channel_id; }
177*d9f75844SAndroid Build Coastguard Worker
address() const178*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& address() const { return ext_addr_; }
state() const179*d9f75844SAndroid Build Coastguard Worker BindState state() const { return state_; }
180*d9f75844SAndroid Build Coastguard Worker
181*d9f75844SAndroid Build Coastguard Worker // Adds a new connection object to the list of connections that are associated
182*d9f75844SAndroid Build Coastguard Worker // with this entry. If prior to this call there were no connections being
183*d9f75844SAndroid Build Coastguard Worker // tracked (i.e. count goes from 0 -> 1), the internal safety flag is reset
184*d9f75844SAndroid Build Coastguard Worker // which cancels any potential pending deletion tasks.
185*d9f75844SAndroid Build Coastguard Worker void TrackConnection(Connection* conn);
186*d9f75844SAndroid Build Coastguard Worker
187*d9f75844SAndroid Build Coastguard Worker // Removes a connection from the list of tracked connections.
188*d9f75844SAndroid Build Coastguard Worker // * If `conn` was the last connection removed, the function returns a
189*d9f75844SAndroid Build Coastguard Worker // safety flag that's used to schedule the deletion of the entry after a
190*d9f75844SAndroid Build Coastguard Worker // timeout expires. If during this timeout `TrackConnection` is called, the
191*d9f75844SAndroid Build Coastguard Worker // flag will be reset and pending tasks associated with it, cancelled.
192*d9f75844SAndroid Build Coastguard Worker // * If `conn` was not the last connection, the return value will be nullptr.
193*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> UntrackConnection(
194*d9f75844SAndroid Build Coastguard Worker Connection* conn);
195*d9f75844SAndroid Build Coastguard Worker
196*d9f75844SAndroid Build Coastguard Worker // Helper methods to send permission and channel bind requests.
197*d9f75844SAndroid Build Coastguard Worker void SendCreatePermissionRequest(int delay);
198*d9f75844SAndroid Build Coastguard Worker void SendChannelBindRequest(int delay);
199*d9f75844SAndroid Build Coastguard Worker // Sends a packet to the given destination address.
200*d9f75844SAndroid Build Coastguard Worker // This will wrap the packet in STUN if necessary.
201*d9f75844SAndroid Build Coastguard Worker int Send(const void* data,
202*d9f75844SAndroid Build Coastguard Worker size_t size,
203*d9f75844SAndroid Build Coastguard Worker bool payload,
204*d9f75844SAndroid Build Coastguard Worker const rtc::PacketOptions& options);
205*d9f75844SAndroid Build Coastguard Worker
206*d9f75844SAndroid Build Coastguard Worker void OnCreatePermissionSuccess();
207*d9f75844SAndroid Build Coastguard Worker void OnCreatePermissionError(StunMessage* response, int code);
208*d9f75844SAndroid Build Coastguard Worker void OnCreatePermissionTimeout();
209*d9f75844SAndroid Build Coastguard Worker void OnChannelBindSuccess();
210*d9f75844SAndroid Build Coastguard Worker void OnChannelBindError(StunMessage* response, int code);
211*d9f75844SAndroid Build Coastguard Worker void OnChannelBindTimeout();
212*d9f75844SAndroid Build Coastguard Worker // Signal sent when TurnEntry is destroyed.
213*d9f75844SAndroid Build Coastguard Worker webrtc::CallbackList<TurnEntry*> destroyed_callback_list_;
214*d9f75844SAndroid Build Coastguard Worker
215*d9f75844SAndroid Build Coastguard Worker private:
216*d9f75844SAndroid Build Coastguard Worker TurnPort* port_;
217*d9f75844SAndroid Build Coastguard Worker int channel_id_;
218*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress ext_addr_;
219*d9f75844SAndroid Build Coastguard Worker BindState state_;
220*d9f75844SAndroid Build Coastguard Worker // List of associated connection instances to keep track of how many and
221*d9f75844SAndroid Build Coastguard Worker // which connections are associated with this entry. Once this is empty,
222*d9f75844SAndroid Build Coastguard Worker // the entry can be deleted.
223*d9f75844SAndroid Build Coastguard Worker std::vector<Connection*> connections_;
224*d9f75844SAndroid Build Coastguard Worker webrtc::ScopedTaskSafety task_safety_;
225*d9f75844SAndroid Build Coastguard Worker };
226*d9f75844SAndroid Build Coastguard Worker
TurnPort(TaskQueueBase * 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,const webrtc::FieldTrialsView * field_trials)227*d9f75844SAndroid Build Coastguard Worker TurnPort::TurnPort(TaskQueueBase* thread,
228*d9f75844SAndroid Build Coastguard Worker rtc::PacketSocketFactory* factory,
229*d9f75844SAndroid Build Coastguard Worker const rtc::Network* network,
230*d9f75844SAndroid Build Coastguard Worker rtc::AsyncPacketSocket* socket,
231*d9f75844SAndroid Build Coastguard Worker absl::string_view username,
232*d9f75844SAndroid Build Coastguard Worker absl::string_view password,
233*d9f75844SAndroid Build Coastguard Worker const ProtocolAddress& server_address,
234*d9f75844SAndroid Build Coastguard Worker const RelayCredentials& credentials,
235*d9f75844SAndroid Build Coastguard Worker int server_priority,
236*d9f75844SAndroid Build Coastguard Worker const std::vector<std::string>& tls_alpn_protocols,
237*d9f75844SAndroid Build Coastguard Worker const std::vector<std::string>& tls_elliptic_curves,
238*d9f75844SAndroid Build Coastguard Worker webrtc::TurnCustomizer* customizer,
239*d9f75844SAndroid Build Coastguard Worker rtc::SSLCertificateVerifier* tls_cert_verifier,
240*d9f75844SAndroid Build Coastguard Worker const webrtc::FieldTrialsView* field_trials)
241*d9f75844SAndroid Build Coastguard Worker : Port(thread,
242*d9f75844SAndroid Build Coastguard Worker RELAY_PORT_TYPE,
243*d9f75844SAndroid Build Coastguard Worker factory,
244*d9f75844SAndroid Build Coastguard Worker network,
245*d9f75844SAndroid Build Coastguard Worker username,
246*d9f75844SAndroid Build Coastguard Worker password,
247*d9f75844SAndroid Build Coastguard Worker field_trials),
248*d9f75844SAndroid Build Coastguard Worker server_address_(server_address),
249*d9f75844SAndroid Build Coastguard Worker tls_alpn_protocols_(tls_alpn_protocols),
250*d9f75844SAndroid Build Coastguard Worker tls_elliptic_curves_(tls_elliptic_curves),
251*d9f75844SAndroid Build Coastguard Worker tls_cert_verifier_(tls_cert_verifier),
252*d9f75844SAndroid Build Coastguard Worker credentials_(credentials),
253*d9f75844SAndroid Build Coastguard Worker socket_(socket),
254*d9f75844SAndroid Build Coastguard Worker error_(0),
255*d9f75844SAndroid Build Coastguard Worker stun_dscp_value_(rtc::DSCP_NO_CHANGE),
256*d9f75844SAndroid Build Coastguard Worker request_manager_(
257*d9f75844SAndroid Build Coastguard Worker thread,
258*d9f75844SAndroid Build Coastguard Worker [this](const void* data, size_t size, StunRequest* request) {
259*d9f75844SAndroid Build Coastguard Worker OnSendStunPacket(data, size, request);
260*d9f75844SAndroid Build Coastguard Worker }),
261*d9f75844SAndroid Build Coastguard Worker next_channel_number_(TURN_CHANNEL_NUMBER_START),
262*d9f75844SAndroid Build Coastguard Worker state_(STATE_CONNECTING),
263*d9f75844SAndroid Build Coastguard Worker server_priority_(server_priority),
264*d9f75844SAndroid Build Coastguard Worker allocate_mismatch_retries_(0),
265*d9f75844SAndroid Build Coastguard Worker turn_customizer_(customizer) {}
266*d9f75844SAndroid Build Coastguard Worker
TurnPort(TaskQueueBase * 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,const webrtc::FieldTrialsView * field_trials)267*d9f75844SAndroid Build Coastguard Worker TurnPort::TurnPort(TaskQueueBase* thread,
268*d9f75844SAndroid Build Coastguard Worker rtc::PacketSocketFactory* factory,
269*d9f75844SAndroid Build Coastguard Worker const rtc::Network* network,
270*d9f75844SAndroid Build Coastguard Worker uint16_t min_port,
271*d9f75844SAndroid Build Coastguard Worker uint16_t max_port,
272*d9f75844SAndroid Build Coastguard Worker absl::string_view username,
273*d9f75844SAndroid Build Coastguard Worker absl::string_view password,
274*d9f75844SAndroid Build Coastguard Worker const ProtocolAddress& server_address,
275*d9f75844SAndroid Build Coastguard Worker const RelayCredentials& credentials,
276*d9f75844SAndroid Build Coastguard Worker int server_priority,
277*d9f75844SAndroid Build Coastguard Worker const std::vector<std::string>& tls_alpn_protocols,
278*d9f75844SAndroid Build Coastguard Worker const std::vector<std::string>& tls_elliptic_curves,
279*d9f75844SAndroid Build Coastguard Worker webrtc::TurnCustomizer* customizer,
280*d9f75844SAndroid Build Coastguard Worker rtc::SSLCertificateVerifier* tls_cert_verifier,
281*d9f75844SAndroid Build Coastguard Worker const webrtc::FieldTrialsView* field_trials)
282*d9f75844SAndroid Build Coastguard Worker : Port(thread,
283*d9f75844SAndroid Build Coastguard Worker RELAY_PORT_TYPE,
284*d9f75844SAndroid Build Coastguard Worker factory,
285*d9f75844SAndroid Build Coastguard Worker network,
286*d9f75844SAndroid Build Coastguard Worker min_port,
287*d9f75844SAndroid Build Coastguard Worker max_port,
288*d9f75844SAndroid Build Coastguard Worker username,
289*d9f75844SAndroid Build Coastguard Worker password,
290*d9f75844SAndroid Build Coastguard Worker field_trials),
291*d9f75844SAndroid Build Coastguard Worker server_address_(server_address),
292*d9f75844SAndroid Build Coastguard Worker tls_alpn_protocols_(tls_alpn_protocols),
293*d9f75844SAndroid Build Coastguard Worker tls_elliptic_curves_(tls_elliptic_curves),
294*d9f75844SAndroid Build Coastguard Worker tls_cert_verifier_(tls_cert_verifier),
295*d9f75844SAndroid Build Coastguard Worker credentials_(credentials),
296*d9f75844SAndroid Build Coastguard Worker socket_(nullptr),
297*d9f75844SAndroid Build Coastguard Worker error_(0),
298*d9f75844SAndroid Build Coastguard Worker stun_dscp_value_(rtc::DSCP_NO_CHANGE),
299*d9f75844SAndroid Build Coastguard Worker request_manager_(
300*d9f75844SAndroid Build Coastguard Worker thread,
301*d9f75844SAndroid Build Coastguard Worker [this](const void* data, size_t size, StunRequest* request) {
302*d9f75844SAndroid Build Coastguard Worker OnSendStunPacket(data, size, request);
303*d9f75844SAndroid Build Coastguard Worker }),
304*d9f75844SAndroid Build Coastguard Worker next_channel_number_(TURN_CHANNEL_NUMBER_START),
305*d9f75844SAndroid Build Coastguard Worker state_(STATE_CONNECTING),
306*d9f75844SAndroid Build Coastguard Worker server_priority_(server_priority),
307*d9f75844SAndroid Build Coastguard Worker allocate_mismatch_retries_(0),
308*d9f75844SAndroid Build Coastguard Worker turn_customizer_(customizer) {}
309*d9f75844SAndroid Build Coastguard Worker
~TurnPort()310*d9f75844SAndroid Build Coastguard Worker TurnPort::~TurnPort() {
311*d9f75844SAndroid Build Coastguard Worker // TODO(juberti): Should this even be necessary?
312*d9f75844SAndroid Build Coastguard Worker
313*d9f75844SAndroid Build Coastguard Worker // release the allocation by sending a refresh with
314*d9f75844SAndroid Build Coastguard Worker // lifetime 0.
315*d9f75844SAndroid Build Coastguard Worker if (ready()) {
316*d9f75844SAndroid Build Coastguard Worker Release();
317*d9f75844SAndroid Build Coastguard Worker }
318*d9f75844SAndroid Build Coastguard Worker
319*d9f75844SAndroid Build Coastguard Worker entries_.clear();
320*d9f75844SAndroid Build Coastguard Worker
321*d9f75844SAndroid Build Coastguard Worker if (socket_)
322*d9f75844SAndroid Build Coastguard Worker socket_->UnsubscribeClose(this);
323*d9f75844SAndroid Build Coastguard Worker
324*d9f75844SAndroid Build Coastguard Worker if (!SharedSocket()) {
325*d9f75844SAndroid Build Coastguard Worker delete socket_;
326*d9f75844SAndroid Build Coastguard Worker }
327*d9f75844SAndroid Build Coastguard Worker }
328*d9f75844SAndroid Build Coastguard Worker
GetLocalAddress() const329*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress TurnPort::GetLocalAddress() const {
330*d9f75844SAndroid Build Coastguard Worker return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress();
331*d9f75844SAndroid Build Coastguard Worker }
332*d9f75844SAndroid Build Coastguard Worker
GetProtocol() const333*d9f75844SAndroid Build Coastguard Worker ProtocolType TurnPort::GetProtocol() const {
334*d9f75844SAndroid Build Coastguard Worker return server_address_.proto;
335*d9f75844SAndroid Build Coastguard Worker }
336*d9f75844SAndroid Build Coastguard Worker
GetTlsCertPolicy() const337*d9f75844SAndroid Build Coastguard Worker TlsCertPolicy TurnPort::GetTlsCertPolicy() const {
338*d9f75844SAndroid Build Coastguard Worker return tls_cert_policy_;
339*d9f75844SAndroid Build Coastguard Worker }
340*d9f75844SAndroid Build Coastguard Worker
SetTlsCertPolicy(TlsCertPolicy tls_cert_policy)341*d9f75844SAndroid Build Coastguard Worker void TurnPort::SetTlsCertPolicy(TlsCertPolicy tls_cert_policy) {
342*d9f75844SAndroid Build Coastguard Worker tls_cert_policy_ = tls_cert_policy;
343*d9f75844SAndroid Build Coastguard Worker }
344*d9f75844SAndroid Build Coastguard Worker
SetTurnLoggingId(absl::string_view turn_logging_id)345*d9f75844SAndroid Build Coastguard Worker void TurnPort::SetTurnLoggingId(absl::string_view turn_logging_id) {
346*d9f75844SAndroid Build Coastguard Worker turn_logging_id_ = std::string(turn_logging_id);
347*d9f75844SAndroid Build Coastguard Worker }
348*d9f75844SAndroid Build Coastguard Worker
GetTlsAlpnProtocols() const349*d9f75844SAndroid Build Coastguard Worker std::vector<std::string> TurnPort::GetTlsAlpnProtocols() const {
350*d9f75844SAndroid Build Coastguard Worker return tls_alpn_protocols_;
351*d9f75844SAndroid Build Coastguard Worker }
352*d9f75844SAndroid Build Coastguard Worker
GetTlsEllipticCurves() const353*d9f75844SAndroid Build Coastguard Worker std::vector<std::string> TurnPort::GetTlsEllipticCurves() const {
354*d9f75844SAndroid Build Coastguard Worker return tls_elliptic_curves_;
355*d9f75844SAndroid Build Coastguard Worker }
356*d9f75844SAndroid Build Coastguard Worker
PrepareAddress()357*d9f75844SAndroid Build Coastguard Worker void TurnPort::PrepareAddress() {
358*d9f75844SAndroid Build Coastguard Worker if (credentials_.username.empty() || credentials_.password.empty()) {
359*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Allocation can't be started without setting the"
360*d9f75844SAndroid Build Coastguard Worker " TURN server credentials for the user.";
361*d9f75844SAndroid Build Coastguard Worker OnAllocateError(STUN_ERROR_UNAUTHORIZED,
362*d9f75844SAndroid Build Coastguard Worker "Missing TURN server credentials.");
363*d9f75844SAndroid Build Coastguard Worker return;
364*d9f75844SAndroid Build Coastguard Worker }
365*d9f75844SAndroid Build Coastguard Worker
366*d9f75844SAndroid Build Coastguard Worker if (!server_address_.address.port()) {
367*d9f75844SAndroid Build Coastguard Worker // We will set default TURN port, if no port is set in the address.
368*d9f75844SAndroid Build Coastguard Worker server_address_.address.SetPort(TURN_DEFAULT_PORT);
369*d9f75844SAndroid Build Coastguard Worker }
370*d9f75844SAndroid Build Coastguard Worker
371*d9f75844SAndroid Build Coastguard Worker if (!AllowedTurnPort(server_address_.address.port(), &field_trials())) {
372*d9f75844SAndroid Build Coastguard Worker // This can only happen after a 300 ALTERNATE SERVER, since the port can't
373*d9f75844SAndroid Build Coastguard Worker // be created with a disallowed port number.
374*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Attempt to start allocation with disallowed port# "
375*d9f75844SAndroid Build Coastguard Worker << server_address_.address.port();
376*d9f75844SAndroid Build Coastguard Worker OnAllocateError(STUN_ERROR_SERVER_ERROR,
377*d9f75844SAndroid Build Coastguard Worker "Attempt to start allocation to a disallowed port");
378*d9f75844SAndroid Build Coastguard Worker return;
379*d9f75844SAndroid Build Coastguard Worker }
380*d9f75844SAndroid Build Coastguard Worker if (server_address_.address.IsUnresolvedIP()) {
381*d9f75844SAndroid Build Coastguard Worker ResolveTurnAddress(server_address_.address);
382*d9f75844SAndroid Build Coastguard Worker } else {
383*d9f75844SAndroid Build Coastguard Worker // If protocol family of server address doesn't match with local, return.
384*d9f75844SAndroid Build Coastguard Worker if (!IsCompatibleAddress(server_address_.address)) {
385*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "IP address family does not match. server: "
386*d9f75844SAndroid Build Coastguard Worker << server_address_.address.family()
387*d9f75844SAndroid Build Coastguard Worker << " local: " << Network()->GetBestIP().family();
388*d9f75844SAndroid Build Coastguard Worker OnAllocateError(STUN_ERROR_GLOBAL_FAILURE,
389*d9f75844SAndroid Build Coastguard Worker "IP address family does not match.");
390*d9f75844SAndroid Build Coastguard Worker return;
391*d9f75844SAndroid Build Coastguard Worker }
392*d9f75844SAndroid Build Coastguard Worker
393*d9f75844SAndroid Build Coastguard Worker // Insert the current address to prevent redirection pingpong.
394*d9f75844SAndroid Build Coastguard Worker attempted_server_addresses_.insert(server_address_.address);
395*d9f75844SAndroid Build Coastguard Worker
396*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << ToString() << ": Trying to connect to TURN server via "
397*d9f75844SAndroid Build Coastguard Worker << ProtoToString(server_address_.proto) << " @ "
398*d9f75844SAndroid Build Coastguard Worker << server_address_.address.ToSensitiveString();
399*d9f75844SAndroid Build Coastguard Worker if (!CreateTurnClientSocket()) {
400*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to create TURN client socket";
401*d9f75844SAndroid Build Coastguard Worker OnAllocateError(SERVER_NOT_REACHABLE_ERROR,
402*d9f75844SAndroid Build Coastguard Worker "Failed to create TURN client socket.");
403*d9f75844SAndroid Build Coastguard Worker return;
404*d9f75844SAndroid Build Coastguard Worker }
405*d9f75844SAndroid Build Coastguard Worker if (server_address_.proto == PROTO_UDP) {
406*d9f75844SAndroid Build Coastguard Worker // If its UDP, send AllocateRequest now.
407*d9f75844SAndroid Build Coastguard Worker // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
408*d9f75844SAndroid Build Coastguard Worker SendRequest(new TurnAllocateRequest(this), 0);
409*d9f75844SAndroid Build Coastguard Worker }
410*d9f75844SAndroid Build Coastguard Worker }
411*d9f75844SAndroid Build Coastguard Worker }
412*d9f75844SAndroid Build Coastguard Worker
CreateTurnClientSocket()413*d9f75844SAndroid Build Coastguard Worker bool TurnPort::CreateTurnClientSocket() {
414*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!socket_ || SharedSocket());
415*d9f75844SAndroid Build Coastguard Worker
416*d9f75844SAndroid Build Coastguard Worker if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
417*d9f75844SAndroid Build Coastguard Worker socket_ = socket_factory()->CreateUdpSocket(
418*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress(Network()->GetBestIP(), 0), min_port(), max_port());
419*d9f75844SAndroid Build Coastguard Worker } else if (server_address_.proto == PROTO_TCP ||
420*d9f75844SAndroid Build Coastguard Worker server_address_.proto == PROTO_TLS) {
421*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!SharedSocket());
422*d9f75844SAndroid Build Coastguard Worker int opts = rtc::PacketSocketFactory::OPT_STUN;
423*d9f75844SAndroid Build Coastguard Worker
424*d9f75844SAndroid Build Coastguard Worker // Apply server address TLS and insecure bits to options.
425*d9f75844SAndroid Build Coastguard Worker if (server_address_.proto == PROTO_TLS) {
426*d9f75844SAndroid Build Coastguard Worker if (tls_cert_policy_ ==
427*d9f75844SAndroid Build Coastguard Worker TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) {
428*d9f75844SAndroid Build Coastguard Worker opts |= rtc::PacketSocketFactory::OPT_TLS_INSECURE;
429*d9f75844SAndroid Build Coastguard Worker } else {
430*d9f75844SAndroid Build Coastguard Worker opts |= rtc::PacketSocketFactory::OPT_TLS;
431*d9f75844SAndroid Build Coastguard Worker }
432*d9f75844SAndroid Build Coastguard Worker }
433*d9f75844SAndroid Build Coastguard Worker
434*d9f75844SAndroid Build Coastguard Worker rtc::PacketSocketTcpOptions tcp_options;
435*d9f75844SAndroid Build Coastguard Worker tcp_options.opts = opts;
436*d9f75844SAndroid Build Coastguard Worker tcp_options.tls_alpn_protocols = tls_alpn_protocols_;
437*d9f75844SAndroid Build Coastguard Worker tcp_options.tls_elliptic_curves = tls_elliptic_curves_;
438*d9f75844SAndroid Build Coastguard Worker tcp_options.tls_cert_verifier = tls_cert_verifier_;
439*d9f75844SAndroid Build Coastguard Worker socket_ = socket_factory()->CreateClientTcpSocket(
440*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress(Network()->GetBestIP(), 0), server_address_.address,
441*d9f75844SAndroid Build Coastguard Worker proxy(), user_agent(), tcp_options);
442*d9f75844SAndroid Build Coastguard Worker }
443*d9f75844SAndroid Build Coastguard Worker
444*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
445*d9f75844SAndroid Build Coastguard Worker error_ = SOCKET_ERROR;
446*d9f75844SAndroid Build Coastguard Worker return false;
447*d9f75844SAndroid Build Coastguard Worker }
448*d9f75844SAndroid Build Coastguard Worker
449*d9f75844SAndroid Build Coastguard Worker // Apply options if any.
450*d9f75844SAndroid Build Coastguard Worker for (SocketOptionsMap::iterator iter = socket_options_.begin();
451*d9f75844SAndroid Build Coastguard Worker iter != socket_options_.end(); ++iter) {
452*d9f75844SAndroid Build Coastguard Worker socket_->SetOption(iter->first, iter->second);
453*d9f75844SAndroid Build Coastguard Worker }
454*d9f75844SAndroid Build Coastguard Worker
455*d9f75844SAndroid Build Coastguard Worker if (!SharedSocket()) {
456*d9f75844SAndroid Build Coastguard Worker // If socket is shared, AllocationSequence will receive the packet.
457*d9f75844SAndroid Build Coastguard Worker socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
458*d9f75844SAndroid Build Coastguard Worker }
459*d9f75844SAndroid Build Coastguard Worker
460*d9f75844SAndroid Build Coastguard Worker socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
461*d9f75844SAndroid Build Coastguard Worker
462*d9f75844SAndroid Build Coastguard Worker socket_->SignalSentPacket.connect(this, &TurnPort::OnSentPacket);
463*d9f75844SAndroid Build Coastguard Worker
464*d9f75844SAndroid Build Coastguard Worker // TCP port is ready to send stun requests after the socket is connected,
465*d9f75844SAndroid Build Coastguard Worker // while UDP port is ready to do so once the socket is created.
466*d9f75844SAndroid Build Coastguard Worker if (server_address_.proto == PROTO_TCP ||
467*d9f75844SAndroid Build Coastguard Worker server_address_.proto == PROTO_TLS) {
468*d9f75844SAndroid Build Coastguard Worker socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
469*d9f75844SAndroid Build Coastguard Worker socket_->SubscribeClose(this, [this](rtc::AsyncPacketSocket* s, int err) {
470*d9f75844SAndroid Build Coastguard Worker OnSocketClose(s, err);
471*d9f75844SAndroid Build Coastguard Worker });
472*d9f75844SAndroid Build Coastguard Worker } else {
473*d9f75844SAndroid Build Coastguard Worker state_ = STATE_CONNECTED;
474*d9f75844SAndroid Build Coastguard Worker }
475*d9f75844SAndroid Build Coastguard Worker return true;
476*d9f75844SAndroid Build Coastguard Worker }
477*d9f75844SAndroid Build Coastguard Worker
OnSocketConnect(rtc::AsyncPacketSocket * socket)478*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
479*d9f75844SAndroid Build Coastguard Worker // This slot should only be invoked if we're using a connection-oriented
480*d9f75844SAndroid Build Coastguard Worker // protocol.
481*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(server_address_.proto == PROTO_TCP ||
482*d9f75844SAndroid Build Coastguard Worker server_address_.proto == PROTO_TLS);
483*d9f75844SAndroid Build Coastguard Worker
484*d9f75844SAndroid Build Coastguard Worker // Do not use this port if the socket bound to an address not associated with
485*d9f75844SAndroid Build Coastguard Worker // the desired network interface. This is seen in Chrome, where TCP sockets
486*d9f75844SAndroid Build Coastguard Worker // cannot be given a binding address, and the platform is expected to pick
487*d9f75844SAndroid Build Coastguard Worker // the correct local address.
488*d9f75844SAndroid Build Coastguard Worker //
489*d9f75844SAndroid Build Coastguard Worker // However, there are two situations in which we allow the bound address to
490*d9f75844SAndroid Build Coastguard Worker // not be one of the addresses of the requested interface:
491*d9f75844SAndroid Build Coastguard Worker // 1. The bound address is the loopback address. This happens when a proxy
492*d9f75844SAndroid Build Coastguard Worker // forces TCP to bind to only the localhost address (see issue 3927).
493*d9f75844SAndroid Build Coastguard Worker // 2. The bound address is the "any address". This happens when
494*d9f75844SAndroid Build Coastguard Worker // multiple_routes is disabled (see issue 4780).
495*d9f75844SAndroid Build Coastguard Worker //
496*d9f75844SAndroid Build Coastguard Worker // Note that, aside from minor differences in log statements, this logic is
497*d9f75844SAndroid Build Coastguard Worker // identical to that in TcpPort.
498*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& socket_address = socket->GetLocalAddress();
499*d9f75844SAndroid Build Coastguard Worker if (absl::c_none_of(Network()->GetIPs(),
500*d9f75844SAndroid Build Coastguard Worker [socket_address](const rtc::InterfaceAddress& addr) {
501*d9f75844SAndroid Build Coastguard Worker return socket_address.ipaddr() == addr;
502*d9f75844SAndroid Build Coastguard Worker })) {
503*d9f75844SAndroid Build Coastguard Worker if (socket->GetLocalAddress().IsLoopbackIP()) {
504*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Socket is bound to the address:"
505*d9f75844SAndroid Build Coastguard Worker << socket_address.ipaddr().ToSensitiveString()
506*d9f75844SAndroid Build Coastguard Worker << ", rather than an address associated with network:"
507*d9f75844SAndroid Build Coastguard Worker << Network()->ToString()
508*d9f75844SAndroid Build Coastguard Worker << ". Still allowing it since it's localhost.";
509*d9f75844SAndroid Build Coastguard Worker } else if (IPIsAny(Network()->GetBestIP())) {
510*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
511*d9f75844SAndroid Build Coastguard Worker << "Socket is bound to the address:"
512*d9f75844SAndroid Build Coastguard Worker << socket_address.ipaddr().ToSensitiveString()
513*d9f75844SAndroid Build Coastguard Worker << ", rather than an address associated with network:"
514*d9f75844SAndroid Build Coastguard Worker << Network()->ToString()
515*d9f75844SAndroid Build Coastguard Worker << ". Still allowing it since it's the 'any' address"
516*d9f75844SAndroid Build Coastguard Worker ", possibly caused by multiple_routes being disabled.";
517*d9f75844SAndroid Build Coastguard Worker } else {
518*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Socket is bound to the address:"
519*d9f75844SAndroid Build Coastguard Worker << socket_address.ipaddr().ToSensitiveString()
520*d9f75844SAndroid Build Coastguard Worker << ", rather than an address associated with network:"
521*d9f75844SAndroid Build Coastguard Worker << Network()->ToString() << ". Discarding TURN port.";
522*d9f75844SAndroid Build Coastguard Worker OnAllocateError(
523*d9f75844SAndroid Build Coastguard Worker STUN_ERROR_GLOBAL_FAILURE,
524*d9f75844SAndroid Build Coastguard Worker "Address not associated with the desired network interface.");
525*d9f75844SAndroid Build Coastguard Worker return;
526*d9f75844SAndroid Build Coastguard Worker }
527*d9f75844SAndroid Build Coastguard Worker }
528*d9f75844SAndroid Build Coastguard Worker
529*d9f75844SAndroid Build Coastguard Worker state_ = STATE_CONNECTED; // It is ready to send stun requests.
530*d9f75844SAndroid Build Coastguard Worker if (server_address_.address.IsUnresolvedIP()) {
531*d9f75844SAndroid Build Coastguard Worker server_address_.address = socket_->GetRemoteAddress();
532*d9f75844SAndroid Build Coastguard Worker }
533*d9f75844SAndroid Build Coastguard Worker
534*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "TurnPort connected to "
535*d9f75844SAndroid Build Coastguard Worker << socket->GetRemoteAddress().ToSensitiveString()
536*d9f75844SAndroid Build Coastguard Worker << " using tcp.";
537*d9f75844SAndroid Build Coastguard Worker SendRequest(new TurnAllocateRequest(this), 0);
538*d9f75844SAndroid Build Coastguard Worker }
539*d9f75844SAndroid Build Coastguard Worker
OnSocketClose(rtc::AsyncPacketSocket * socket,int error)540*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
541*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
542*d9f75844SAndroid Build Coastguard Worker << ": Connection with server failed with error: "
543*d9f75844SAndroid Build Coastguard Worker << error;
544*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(socket == socket_);
545*d9f75844SAndroid Build Coastguard Worker Close();
546*d9f75844SAndroid Build Coastguard Worker }
547*d9f75844SAndroid Build Coastguard Worker
OnAllocateMismatch()548*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnAllocateMismatch() {
549*d9f75844SAndroid Build Coastguard Worker if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
550*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString() << ": Giving up on the port after "
551*d9f75844SAndroid Build Coastguard Worker << allocate_mismatch_retries_
552*d9f75844SAndroid Build Coastguard Worker << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
553*d9f75844SAndroid Build Coastguard Worker OnAllocateError(STUN_ERROR_ALLOCATION_MISMATCH,
554*d9f75844SAndroid Build Coastguard Worker "Maximum retries reached for allocation mismatch.");
555*d9f75844SAndroid Build Coastguard Worker return;
556*d9f75844SAndroid Build Coastguard Worker }
557*d9f75844SAndroid Build Coastguard Worker
558*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << ToString()
559*d9f75844SAndroid Build Coastguard Worker << ": Allocating a new socket after "
560*d9f75844SAndroid Build Coastguard Worker "STUN_ERROR_ALLOCATION_MISMATCH, retry: "
561*d9f75844SAndroid Build Coastguard Worker << allocate_mismatch_retries_ + 1;
562*d9f75844SAndroid Build Coastguard Worker
563*d9f75844SAndroid Build Coastguard Worker socket_->UnsubscribeClose(this);
564*d9f75844SAndroid Build Coastguard Worker
565*d9f75844SAndroid Build Coastguard Worker if (SharedSocket()) {
566*d9f75844SAndroid Build Coastguard Worker ResetSharedSocket();
567*d9f75844SAndroid Build Coastguard Worker } else {
568*d9f75844SAndroid Build Coastguard Worker delete socket_;
569*d9f75844SAndroid Build Coastguard Worker }
570*d9f75844SAndroid Build Coastguard Worker socket_ = nullptr;
571*d9f75844SAndroid Build Coastguard Worker
572*d9f75844SAndroid Build Coastguard Worker ResetNonce();
573*d9f75844SAndroid Build Coastguard Worker PrepareAddress();
574*d9f75844SAndroid Build Coastguard Worker ++allocate_mismatch_retries_;
575*d9f75844SAndroid Build Coastguard Worker }
576*d9f75844SAndroid Build Coastguard Worker
CreateConnection(const Candidate & remote_candidate,CandidateOrigin origin)577*d9f75844SAndroid Build Coastguard Worker Connection* TurnPort::CreateConnection(const Candidate& remote_candidate,
578*d9f75844SAndroid Build Coastguard Worker CandidateOrigin origin) {
579*d9f75844SAndroid Build Coastguard Worker // TURN-UDP can only connect to UDP candidates.
580*d9f75844SAndroid Build Coastguard Worker if (!SupportsProtocol(remote_candidate.protocol())) {
581*d9f75844SAndroid Build Coastguard Worker return nullptr;
582*d9f75844SAndroid Build Coastguard Worker }
583*d9f75844SAndroid Build Coastguard Worker
584*d9f75844SAndroid Build Coastguard Worker if (state_ == STATE_DISCONNECTED || state_ == STATE_RECEIVEONLY) {
585*d9f75844SAndroid Build Coastguard Worker return nullptr;
586*d9f75844SAndroid Build Coastguard Worker }
587*d9f75844SAndroid Build Coastguard Worker
588*d9f75844SAndroid Build Coastguard Worker // If the remote endpoint signaled us an mDNS candidate, we do not form a pair
589*d9f75844SAndroid Build Coastguard Worker // with the relay candidate to avoid IP leakage in the CreatePermission
590*d9f75844SAndroid Build Coastguard Worker // request.
591*d9f75844SAndroid Build Coastguard Worker if (absl::EndsWith(remote_candidate.address().hostname(), LOCAL_TLD)) {
592*d9f75844SAndroid Build Coastguard Worker return nullptr;
593*d9f75844SAndroid Build Coastguard Worker }
594*d9f75844SAndroid Build Coastguard Worker
595*d9f75844SAndroid Build Coastguard Worker // A TURN port will have two candidates, STUN and TURN. STUN may not
596*d9f75844SAndroid Build Coastguard Worker // present in all cases. If present stun candidate will be added first
597*d9f75844SAndroid Build Coastguard Worker // and TURN candidate later.
598*d9f75844SAndroid Build Coastguard Worker for (size_t index = 0; index < Candidates().size(); ++index) {
599*d9f75844SAndroid Build Coastguard Worker const Candidate& local_candidate = Candidates()[index];
600*d9f75844SAndroid Build Coastguard Worker if (local_candidate.type() == RELAY_PORT_TYPE &&
601*d9f75844SAndroid Build Coastguard Worker local_candidate.address().family() ==
602*d9f75844SAndroid Build Coastguard Worker remote_candidate.address().family()) {
603*d9f75844SAndroid Build Coastguard Worker ProxyConnection* conn =
604*d9f75844SAndroid Build Coastguard Worker new ProxyConnection(NewWeakPtr(), index, remote_candidate);
605*d9f75844SAndroid Build Coastguard Worker // Create an entry, if needed, so we can get our permissions set up
606*d9f75844SAndroid Build Coastguard Worker // correctly.
607*d9f75844SAndroid Build Coastguard Worker if (CreateOrRefreshEntry(conn, next_channel_number_)) {
608*d9f75844SAndroid Build Coastguard Worker next_channel_number_++;
609*d9f75844SAndroid Build Coastguard Worker }
610*d9f75844SAndroid Build Coastguard Worker AddOrReplaceConnection(conn);
611*d9f75844SAndroid Build Coastguard Worker return conn;
612*d9f75844SAndroid Build Coastguard Worker }
613*d9f75844SAndroid Build Coastguard Worker }
614*d9f75844SAndroid Build Coastguard Worker return nullptr;
615*d9f75844SAndroid Build Coastguard Worker }
616*d9f75844SAndroid Build Coastguard Worker
FailAndPruneConnection(const rtc::SocketAddress & address)617*d9f75844SAndroid Build Coastguard Worker bool TurnPort::FailAndPruneConnection(const rtc::SocketAddress& address) {
618*d9f75844SAndroid Build Coastguard Worker Connection* conn = GetConnection(address);
619*d9f75844SAndroid Build Coastguard Worker if (conn != nullptr) {
620*d9f75844SAndroid Build Coastguard Worker conn->FailAndPrune();
621*d9f75844SAndroid Build Coastguard Worker return true;
622*d9f75844SAndroid Build Coastguard Worker }
623*d9f75844SAndroid Build Coastguard Worker return false;
624*d9f75844SAndroid Build Coastguard Worker }
625*d9f75844SAndroid Build Coastguard Worker
SetOption(rtc::Socket::Option opt,int value)626*d9f75844SAndroid Build Coastguard Worker int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
627*d9f75844SAndroid Build Coastguard Worker // Remember the last requested DSCP value, for STUN traffic.
628*d9f75844SAndroid Build Coastguard Worker if (opt == rtc::Socket::OPT_DSCP)
629*d9f75844SAndroid Build Coastguard Worker stun_dscp_value_ = static_cast<rtc::DiffServCodePoint>(value);
630*d9f75844SAndroid Build Coastguard Worker
631*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
632*d9f75844SAndroid Build Coastguard Worker // If socket is not created yet, these options will be applied during socket
633*d9f75844SAndroid Build Coastguard Worker // creation.
634*d9f75844SAndroid Build Coastguard Worker socket_options_[opt] = value;
635*d9f75844SAndroid Build Coastguard Worker return 0;
636*d9f75844SAndroid Build Coastguard Worker }
637*d9f75844SAndroid Build Coastguard Worker return socket_->SetOption(opt, value);
638*d9f75844SAndroid Build Coastguard Worker }
639*d9f75844SAndroid Build Coastguard Worker
GetOption(rtc::Socket::Option opt,int * value)640*d9f75844SAndroid Build Coastguard Worker int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
641*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
642*d9f75844SAndroid Build Coastguard Worker SocketOptionsMap::const_iterator it = socket_options_.find(opt);
643*d9f75844SAndroid Build Coastguard Worker if (it == socket_options_.end()) {
644*d9f75844SAndroid Build Coastguard Worker return -1;
645*d9f75844SAndroid Build Coastguard Worker }
646*d9f75844SAndroid Build Coastguard Worker *value = it->second;
647*d9f75844SAndroid Build Coastguard Worker return 0;
648*d9f75844SAndroid Build Coastguard Worker }
649*d9f75844SAndroid Build Coastguard Worker
650*d9f75844SAndroid Build Coastguard Worker return socket_->GetOption(opt, value);
651*d9f75844SAndroid Build Coastguard Worker }
652*d9f75844SAndroid Build Coastguard Worker
GetError()653*d9f75844SAndroid Build Coastguard Worker int TurnPort::GetError() {
654*d9f75844SAndroid Build Coastguard Worker return error_;
655*d9f75844SAndroid Build Coastguard Worker }
656*d9f75844SAndroid Build Coastguard Worker
SendTo(const void * data,size_t size,const rtc::SocketAddress & addr,const rtc::PacketOptions & options,bool payload)657*d9f75844SAndroid Build Coastguard Worker int TurnPort::SendTo(const void* data,
658*d9f75844SAndroid Build Coastguard Worker size_t size,
659*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& addr,
660*d9f75844SAndroid Build Coastguard Worker const rtc::PacketOptions& options,
661*d9f75844SAndroid Build Coastguard Worker bool payload) {
662*d9f75844SAndroid Build Coastguard Worker // Try to find an entry for this specific address; we should have one.
663*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry = FindEntry(addr);
664*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(entry);
665*d9f75844SAndroid Build Coastguard Worker
666*d9f75844SAndroid Build Coastguard Worker if (!ready()) {
667*d9f75844SAndroid Build Coastguard Worker error_ = ENOTCONN;
668*d9f75844SAndroid Build Coastguard Worker return SOCKET_ERROR;
669*d9f75844SAndroid Build Coastguard Worker }
670*d9f75844SAndroid Build Coastguard Worker
671*d9f75844SAndroid Build Coastguard Worker // Send the actual contents to the server using the usual mechanism.
672*d9f75844SAndroid Build Coastguard Worker rtc::PacketOptions modified_options(options);
673*d9f75844SAndroid Build Coastguard Worker CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
674*d9f75844SAndroid Build Coastguard Worker int sent = entry->Send(data, size, payload, modified_options);
675*d9f75844SAndroid Build Coastguard Worker if (sent <= 0) {
676*d9f75844SAndroid Build Coastguard Worker error_ = socket_->GetError();
677*d9f75844SAndroid Build Coastguard Worker return SOCKET_ERROR;
678*d9f75844SAndroid Build Coastguard Worker }
679*d9f75844SAndroid Build Coastguard Worker
680*d9f75844SAndroid Build Coastguard Worker // The caller of the function is expecting the number of user data bytes,
681*d9f75844SAndroid Build Coastguard Worker // rather than the size of the packet.
682*d9f75844SAndroid Build Coastguard Worker return static_cast<int>(size);
683*d9f75844SAndroid Build Coastguard Worker }
684*d9f75844SAndroid Build Coastguard Worker
CanHandleIncomingPacketsFrom(const rtc::SocketAddress & addr) const685*d9f75844SAndroid Build Coastguard Worker bool TurnPort::CanHandleIncomingPacketsFrom(
686*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& addr) const {
687*d9f75844SAndroid Build Coastguard Worker return server_address_.address == addr;
688*d9f75844SAndroid Build Coastguard Worker }
689*d9f75844SAndroid Build Coastguard Worker
HandleIncomingPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & remote_addr,int64_t packet_time_us)690*d9f75844SAndroid Build Coastguard Worker bool TurnPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
691*d9f75844SAndroid Build Coastguard Worker const char* data,
692*d9f75844SAndroid Build Coastguard Worker size_t size,
693*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& remote_addr,
694*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_us) {
695*d9f75844SAndroid Build Coastguard Worker if (socket != socket_) {
696*d9f75844SAndroid Build Coastguard Worker // The packet was received on a shared socket after we've allocated a new
697*d9f75844SAndroid Build Coastguard Worker // socket for this TURN port.
698*d9f75844SAndroid Build Coastguard Worker return false;
699*d9f75844SAndroid Build Coastguard Worker }
700*d9f75844SAndroid Build Coastguard Worker
701*d9f75844SAndroid Build Coastguard Worker // This is to guard against a STUN response from previous server after
702*d9f75844SAndroid Build Coastguard Worker // alternative server redirection. TODO(guoweis): add a unit test for this
703*d9f75844SAndroid Build Coastguard Worker // race condition.
704*d9f75844SAndroid Build Coastguard Worker if (remote_addr != server_address_.address) {
705*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
706*d9f75844SAndroid Build Coastguard Worker << ": Discarding TURN message from unknown address: "
707*d9f75844SAndroid Build Coastguard Worker << remote_addr.ToSensitiveString()
708*d9f75844SAndroid Build Coastguard Worker << " server_address_: "
709*d9f75844SAndroid Build Coastguard Worker << server_address_.address.ToSensitiveString();
710*d9f75844SAndroid Build Coastguard Worker return false;
711*d9f75844SAndroid Build Coastguard Worker }
712*d9f75844SAndroid Build Coastguard Worker
713*d9f75844SAndroid Build Coastguard Worker // The message must be at least the size of a channel header.
714*d9f75844SAndroid Build Coastguard Worker if (size < TURN_CHANNEL_HEADER_SIZE) {
715*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
716*d9f75844SAndroid Build Coastguard Worker << ": Received TURN message that was too short";
717*d9f75844SAndroid Build Coastguard Worker return false;
718*d9f75844SAndroid Build Coastguard Worker }
719*d9f75844SAndroid Build Coastguard Worker
720*d9f75844SAndroid Build Coastguard Worker if (state_ == STATE_DISCONNECTED) {
721*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
722*d9f75844SAndroid Build Coastguard Worker << ToString()
723*d9f75844SAndroid Build Coastguard Worker << ": Received TURN message while the TURN port is disconnected";
724*d9f75844SAndroid Build Coastguard Worker return false;
725*d9f75844SAndroid Build Coastguard Worker }
726*d9f75844SAndroid Build Coastguard Worker
727*d9f75844SAndroid Build Coastguard Worker // Check the message type, to see if is a Channel Data message.
728*d9f75844SAndroid Build Coastguard Worker // The message will either be channel data, a TURN data indication, or
729*d9f75844SAndroid Build Coastguard Worker // a response to a previous request.
730*d9f75844SAndroid Build Coastguard Worker uint16_t msg_type = rtc::GetBE16(data);
731*d9f75844SAndroid Build Coastguard Worker if (IsTurnChannelData(msg_type)) {
732*d9f75844SAndroid Build Coastguard Worker HandleChannelData(msg_type, data, size, packet_time_us);
733*d9f75844SAndroid Build Coastguard Worker return true;
734*d9f75844SAndroid Build Coastguard Worker }
735*d9f75844SAndroid Build Coastguard Worker
736*d9f75844SAndroid Build Coastguard Worker if (msg_type == TURN_DATA_INDICATION) {
737*d9f75844SAndroid Build Coastguard Worker HandleDataIndication(data, size, packet_time_us);
738*d9f75844SAndroid Build Coastguard Worker return true;
739*d9f75844SAndroid Build Coastguard Worker }
740*d9f75844SAndroid Build Coastguard Worker
741*d9f75844SAndroid Build Coastguard Worker if (SharedSocket() && (msg_type == STUN_BINDING_RESPONSE ||
742*d9f75844SAndroid Build Coastguard Worker msg_type == STUN_BINDING_ERROR_RESPONSE)) {
743*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE)
744*d9f75844SAndroid Build Coastguard Worker << ToString()
745*d9f75844SAndroid Build Coastguard Worker << ": Ignoring STUN binding response message on shared socket.";
746*d9f75844SAndroid Build Coastguard Worker return false;
747*d9f75844SAndroid Build Coastguard Worker }
748*d9f75844SAndroid Build Coastguard Worker
749*d9f75844SAndroid Build Coastguard Worker request_manager_.CheckResponse(data, size);
750*d9f75844SAndroid Build Coastguard Worker
751*d9f75844SAndroid Build Coastguard Worker return true;
752*d9f75844SAndroid Build Coastguard Worker }
753*d9f75844SAndroid Build Coastguard Worker
OnReadPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & remote_addr,const int64_t & packet_time_us)754*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
755*d9f75844SAndroid Build Coastguard Worker const char* data,
756*d9f75844SAndroid Build Coastguard Worker size_t size,
757*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& remote_addr,
758*d9f75844SAndroid Build Coastguard Worker const int64_t& packet_time_us) {
759*d9f75844SAndroid Build Coastguard Worker HandleIncomingPacket(socket, data, size, remote_addr, packet_time_us);
760*d9f75844SAndroid Build Coastguard Worker }
761*d9f75844SAndroid Build Coastguard Worker
OnSentPacket(rtc::AsyncPacketSocket * socket,const rtc::SentPacket & sent_packet)762*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
763*d9f75844SAndroid Build Coastguard Worker const rtc::SentPacket& sent_packet) {
764*d9f75844SAndroid Build Coastguard Worker PortInterface::SignalSentPacket(sent_packet);
765*d9f75844SAndroid Build Coastguard Worker }
766*d9f75844SAndroid Build Coastguard Worker
OnReadyToSend(rtc::AsyncPacketSocket * socket)767*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
768*d9f75844SAndroid Build Coastguard Worker if (ready()) {
769*d9f75844SAndroid Build Coastguard Worker Port::OnReadyToSend();
770*d9f75844SAndroid Build Coastguard Worker }
771*d9f75844SAndroid Build Coastguard Worker }
772*d9f75844SAndroid Build Coastguard Worker
SupportsProtocol(absl::string_view protocol) const773*d9f75844SAndroid Build Coastguard Worker bool TurnPort::SupportsProtocol(absl::string_view protocol) const {
774*d9f75844SAndroid Build Coastguard Worker // Turn port only connects to UDP candidates.
775*d9f75844SAndroid Build Coastguard Worker return protocol == UDP_PROTOCOL_NAME;
776*d9f75844SAndroid Build Coastguard Worker }
777*d9f75844SAndroid Build Coastguard Worker
778*d9f75844SAndroid Build Coastguard Worker // Update current server address port with the alternate server address port.
SetAlternateServer(const rtc::SocketAddress & address)779*d9f75844SAndroid Build Coastguard Worker bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
780*d9f75844SAndroid Build Coastguard Worker // Check if we have seen this address before and reject if we did.
781*d9f75844SAndroid Build Coastguard Worker AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
782*d9f75844SAndroid Build Coastguard Worker if (iter != attempted_server_addresses_.end()) {
783*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString() << ": Redirection to ["
784*d9f75844SAndroid Build Coastguard Worker << address.ToSensitiveString()
785*d9f75844SAndroid Build Coastguard Worker << "] ignored, allocation failed.";
786*d9f75844SAndroid Build Coastguard Worker return false;
787*d9f75844SAndroid Build Coastguard Worker }
788*d9f75844SAndroid Build Coastguard Worker
789*d9f75844SAndroid Build Coastguard Worker // If protocol family of server address doesn't match with local, return.
790*d9f75844SAndroid Build Coastguard Worker if (!IsCompatibleAddress(address)) {
791*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Server IP address family does not match with "
792*d9f75844SAndroid Build Coastguard Worker "local host address family type";
793*d9f75844SAndroid Build Coastguard Worker return false;
794*d9f75844SAndroid Build Coastguard Worker }
795*d9f75844SAndroid Build Coastguard Worker
796*d9f75844SAndroid Build Coastguard Worker // Block redirects to a loopback address.
797*d9f75844SAndroid Build Coastguard Worker // See: https://bugs.chromium.org/p/chromium/issues/detail?id=649118
798*d9f75844SAndroid Build Coastguard Worker if (address.IsLoopbackIP()) {
799*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
800*d9f75844SAndroid Build Coastguard Worker << ": Blocking attempted redirect to loopback address.";
801*d9f75844SAndroid Build Coastguard Worker return false;
802*d9f75844SAndroid Build Coastguard Worker }
803*d9f75844SAndroid Build Coastguard Worker
804*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << ToString() << ": Redirecting from TURN server ["
805*d9f75844SAndroid Build Coastguard Worker << server_address_.address.ToSensitiveString()
806*d9f75844SAndroid Build Coastguard Worker << "] to TURN server [" << address.ToSensitiveString()
807*d9f75844SAndroid Build Coastguard Worker << "]";
808*d9f75844SAndroid Build Coastguard Worker server_address_ = ProtocolAddress(address, server_address_.proto);
809*d9f75844SAndroid Build Coastguard Worker
810*d9f75844SAndroid Build Coastguard Worker // Insert the current address to prevent redirection pingpong.
811*d9f75844SAndroid Build Coastguard Worker attempted_server_addresses_.insert(server_address_.address);
812*d9f75844SAndroid Build Coastguard Worker return true;
813*d9f75844SAndroid Build Coastguard Worker }
814*d9f75844SAndroid Build Coastguard Worker
ResolveTurnAddress(const rtc::SocketAddress & address)815*d9f75844SAndroid Build Coastguard Worker void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
816*d9f75844SAndroid Build Coastguard Worker if (resolver_)
817*d9f75844SAndroid Build Coastguard Worker return;
818*d9f75844SAndroid Build Coastguard Worker
819*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << ToString() << ": Starting TURN host lookup for "
820*d9f75844SAndroid Build Coastguard Worker << address.ToSensitiveString();
821*d9f75844SAndroid Build Coastguard Worker resolver_ = socket_factory()->CreateAsyncDnsResolver();
822*d9f75844SAndroid Build Coastguard Worker auto callback = [this] {
823*d9f75844SAndroid Build Coastguard Worker // If DNS resolve is failed when trying to connect to the server using TCP,
824*d9f75844SAndroid Build Coastguard Worker // one of the reason could be due to DNS queries blocked by firewall.
825*d9f75844SAndroid Build Coastguard Worker // In such cases we will try to connect to the server with hostname,
826*d9f75844SAndroid Build Coastguard Worker // assuming socket layer will resolve the hostname through a HTTP proxy (if
827*d9f75844SAndroid Build Coastguard Worker // any).
828*d9f75844SAndroid Build Coastguard Worker auto& result = resolver_->result();
829*d9f75844SAndroid Build Coastguard Worker if (result.GetError() != 0 && (server_address_.proto == PROTO_TCP ||
830*d9f75844SAndroid Build Coastguard Worker server_address_.proto == PROTO_TLS)) {
831*d9f75844SAndroid Build Coastguard Worker if (!CreateTurnClientSocket()) {
832*d9f75844SAndroid Build Coastguard Worker OnAllocateError(SERVER_NOT_REACHABLE_ERROR,
833*d9f75844SAndroid Build Coastguard Worker "TURN host lookup received error.");
834*d9f75844SAndroid Build Coastguard Worker }
835*d9f75844SAndroid Build Coastguard Worker return;
836*d9f75844SAndroid Build Coastguard Worker }
837*d9f75844SAndroid Build Coastguard Worker
838*d9f75844SAndroid Build Coastguard Worker // Copy the original server address in `resolved_address`. For TLS based
839*d9f75844SAndroid Build Coastguard Worker // sockets we need hostname along with resolved address.
840*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress resolved_address = server_address_.address;
841*d9f75844SAndroid Build Coastguard Worker if (result.GetError() != 0 ||
842*d9f75844SAndroid Build Coastguard Worker !result.GetResolvedAddress(Network()->GetBestIP().family(),
843*d9f75844SAndroid Build Coastguard Worker &resolved_address)) {
844*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString() << ": TURN host lookup received error "
845*d9f75844SAndroid Build Coastguard Worker << result.GetError();
846*d9f75844SAndroid Build Coastguard Worker error_ = result.GetError();
847*d9f75844SAndroid Build Coastguard Worker OnAllocateError(SERVER_NOT_REACHABLE_ERROR,
848*d9f75844SAndroid Build Coastguard Worker "TURN host lookup received error.");
849*d9f75844SAndroid Build Coastguard Worker return;
850*d9f75844SAndroid Build Coastguard Worker }
851*d9f75844SAndroid Build Coastguard Worker server_address_.address = resolved_address;
852*d9f75844SAndroid Build Coastguard Worker PrepareAddress();
853*d9f75844SAndroid Build Coastguard Worker };
854*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/14733): remove duplicate resolution with STUN port.
855*d9f75844SAndroid Build Coastguard Worker if (ResolveTurnHostnameForFamily(field_trials())) {
856*d9f75844SAndroid Build Coastguard Worker resolver_->Start(address, Network()->family(), std::move(callback));
857*d9f75844SAndroid Build Coastguard Worker } else {
858*d9f75844SAndroid Build Coastguard Worker resolver_->Start(address, std::move(callback));
859*d9f75844SAndroid Build Coastguard Worker }
860*d9f75844SAndroid Build Coastguard Worker }
861*d9f75844SAndroid Build Coastguard Worker
OnSendStunPacket(const void * data,size_t size,StunRequest * request)862*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnSendStunPacket(const void* data,
863*d9f75844SAndroid Build Coastguard Worker size_t size,
864*d9f75844SAndroid Build Coastguard Worker StunRequest* request) {
865*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(connected());
866*d9f75844SAndroid Build Coastguard Worker rtc::PacketOptions options(StunDscpValue());
867*d9f75844SAndroid Build Coastguard Worker options.info_signaled_after_sent.packet_type = rtc::PacketType::kTurnMessage;
868*d9f75844SAndroid Build Coastguard Worker CopyPortInformationToPacketInfo(&options.info_signaled_after_sent);
869*d9f75844SAndroid Build Coastguard Worker if (Send(data, size, options) < 0) {
870*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << ToString() << ": Failed to send TURN message, error: "
871*d9f75844SAndroid Build Coastguard Worker << socket_->GetError();
872*d9f75844SAndroid Build Coastguard Worker }
873*d9f75844SAndroid Build Coastguard Worker }
874*d9f75844SAndroid Build Coastguard Worker
OnStunAddress(const rtc::SocketAddress & address)875*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
876*d9f75844SAndroid Build Coastguard Worker // STUN Port will discover STUN candidate, as it's supplied with first TURN
877*d9f75844SAndroid Build Coastguard Worker // server address.
878*d9f75844SAndroid Build Coastguard Worker // Why not using this address? - P2PTransportChannel will start creating
879*d9f75844SAndroid Build Coastguard Worker // connections after first candidate, which means it could start creating the
880*d9f75844SAndroid Build Coastguard Worker // connections before TURN candidate added. For that to handle, we need to
881*d9f75844SAndroid Build Coastguard Worker // supply STUN candidate from this port to UDPPort, and TurnPort should have
882*d9f75844SAndroid Build Coastguard Worker // handle to UDPPort to pass back the address.
883*d9f75844SAndroid Build Coastguard Worker }
884*d9f75844SAndroid Build Coastguard Worker
OnAllocateSuccess(const rtc::SocketAddress & address,const rtc::SocketAddress & stun_address)885*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
886*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& stun_address) {
887*d9f75844SAndroid Build Coastguard Worker state_ = STATE_READY;
888*d9f75844SAndroid Build Coastguard Worker
889*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress related_address = stun_address;
890*d9f75844SAndroid Build Coastguard Worker
891*d9f75844SAndroid Build Coastguard Worker // For relayed candidate, Base is the candidate itself.
892*d9f75844SAndroid Build Coastguard Worker AddAddress(address, // Candidate address.
893*d9f75844SAndroid Build Coastguard Worker address, // Base address.
894*d9f75844SAndroid Build Coastguard Worker related_address, // Related address.
895*d9f75844SAndroid Build Coastguard Worker UDP_PROTOCOL_NAME,
896*d9f75844SAndroid Build Coastguard Worker ProtoToString(server_address_.proto), // The first hop protocol.
897*d9f75844SAndroid Build Coastguard Worker "", // TCP candidate type, empty for turn candidates.
898*d9f75844SAndroid Build Coastguard Worker RELAY_PORT_TYPE, GetRelayPreference(server_address_.proto),
899*d9f75844SAndroid Build Coastguard Worker server_priority_, ReconstructedServerUrl(), true);
900*d9f75844SAndroid Build Coastguard Worker }
901*d9f75844SAndroid Build Coastguard Worker
OnAllocateError(int error_code,absl::string_view reason)902*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnAllocateError(int error_code, absl::string_view reason) {
903*d9f75844SAndroid Build Coastguard Worker // We will send SignalPortError asynchronously as this can be sent during
904*d9f75844SAndroid Build Coastguard Worker // port initialization. This way it will not be blocking other port
905*d9f75844SAndroid Build Coastguard Worker // creation.
906*d9f75844SAndroid Build Coastguard Worker thread()->PostTask(
907*d9f75844SAndroid Build Coastguard Worker SafeTask(task_safety_.flag(), [this] { SignalPortError(this); }));
908*d9f75844SAndroid Build Coastguard Worker std::string address = GetLocalAddress().HostAsSensitiveURIString();
909*d9f75844SAndroid Build Coastguard Worker int port = GetLocalAddress().port();
910*d9f75844SAndroid Build Coastguard Worker if (server_address_.proto == PROTO_TCP &&
911*d9f75844SAndroid Build Coastguard Worker server_address_.address.IsPrivateIP()) {
912*d9f75844SAndroid Build Coastguard Worker address.clear();
913*d9f75844SAndroid Build Coastguard Worker port = 0;
914*d9f75844SAndroid Build Coastguard Worker }
915*d9f75844SAndroid Build Coastguard Worker SignalCandidateError(
916*d9f75844SAndroid Build Coastguard Worker this, IceCandidateErrorEvent(address, port, ReconstructedServerUrl(),
917*d9f75844SAndroid Build Coastguard Worker error_code, reason));
918*d9f75844SAndroid Build Coastguard Worker }
919*d9f75844SAndroid Build Coastguard Worker
OnRefreshError()920*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnRefreshError() {
921*d9f75844SAndroid Build Coastguard Worker // Need to clear the requests asynchronously because otherwise, the refresh
922*d9f75844SAndroid Build Coastguard Worker // request may be deleted twice: once at the end of the message processing
923*d9f75844SAndroid Build Coastguard Worker // and the other in HandleRefreshError().
924*d9f75844SAndroid Build Coastguard Worker thread()->PostTask(
925*d9f75844SAndroid Build Coastguard Worker SafeTask(task_safety_.flag(), [this] { HandleRefreshError(); }));
926*d9f75844SAndroid Build Coastguard Worker }
927*d9f75844SAndroid Build Coastguard Worker
HandleRefreshError()928*d9f75844SAndroid Build Coastguard Worker void TurnPort::HandleRefreshError() {
929*d9f75844SAndroid Build Coastguard Worker request_manager_.Clear();
930*d9f75844SAndroid Build Coastguard Worker state_ = STATE_RECEIVEONLY;
931*d9f75844SAndroid Build Coastguard Worker // Fail and prune all connections; stop sending data.
932*d9f75844SAndroid Build Coastguard Worker for (auto kv : connections()) {
933*d9f75844SAndroid Build Coastguard Worker kv.second->FailAndPrune();
934*d9f75844SAndroid Build Coastguard Worker }
935*d9f75844SAndroid Build Coastguard Worker }
936*d9f75844SAndroid Build Coastguard Worker
Release()937*d9f75844SAndroid Build Coastguard Worker void TurnPort::Release() {
938*d9f75844SAndroid Build Coastguard Worker // Remove any pending refresh requests.
939*d9f75844SAndroid Build Coastguard Worker request_manager_.Clear();
940*d9f75844SAndroid Build Coastguard Worker
941*d9f75844SAndroid Build Coastguard Worker // Send refresh with lifetime 0.
942*d9f75844SAndroid Build Coastguard Worker TurnRefreshRequest* req = new TurnRefreshRequest(this, 0);
943*d9f75844SAndroid Build Coastguard Worker SendRequest(req, 0);
944*d9f75844SAndroid Build Coastguard Worker
945*d9f75844SAndroid Build Coastguard Worker state_ = STATE_RECEIVEONLY;
946*d9f75844SAndroid Build Coastguard Worker }
947*d9f75844SAndroid Build Coastguard Worker
Close()948*d9f75844SAndroid Build Coastguard Worker void TurnPort::Close() {
949*d9f75844SAndroid Build Coastguard Worker if (!ready()) {
950*d9f75844SAndroid Build Coastguard Worker OnAllocateError(SERVER_NOT_REACHABLE_ERROR, "");
951*d9f75844SAndroid Build Coastguard Worker }
952*d9f75844SAndroid Build Coastguard Worker request_manager_.Clear();
953*d9f75844SAndroid Build Coastguard Worker // Stop the port from creating new connections.
954*d9f75844SAndroid Build Coastguard Worker state_ = STATE_DISCONNECTED;
955*d9f75844SAndroid Build Coastguard Worker // Delete all existing connections; stop sending data.
956*d9f75844SAndroid Build Coastguard Worker DestroyAllConnections();
957*d9f75844SAndroid Build Coastguard Worker if (callbacks_for_test_) {
958*d9f75844SAndroid Build Coastguard Worker callbacks_for_test_->OnTurnPortClosed();
959*d9f75844SAndroid Build Coastguard Worker }
960*d9f75844SAndroid Build Coastguard Worker }
961*d9f75844SAndroid Build Coastguard Worker
StunDscpValue() const962*d9f75844SAndroid Build Coastguard Worker rtc::DiffServCodePoint TurnPort::StunDscpValue() const {
963*d9f75844SAndroid Build Coastguard Worker return stun_dscp_value_;
964*d9f75844SAndroid Build Coastguard Worker }
965*d9f75844SAndroid Build Coastguard Worker
966*d9f75844SAndroid Build Coastguard Worker // static
AllowedTurnPort(int port,const webrtc::FieldTrialsView * field_trials)967*d9f75844SAndroid Build Coastguard Worker bool TurnPort::AllowedTurnPort(int port,
968*d9f75844SAndroid Build Coastguard Worker const webrtc::FieldTrialsView* field_trials) {
969*d9f75844SAndroid Build Coastguard Worker // Port 53, 80 and 443 are used for existing deployments.
970*d9f75844SAndroid Build Coastguard Worker // Ports above 1024 are assumed to be OK to use.
971*d9f75844SAndroid Build Coastguard Worker if (port == 53 || port == 80 || port == 443 || port >= 1024) {
972*d9f75844SAndroid Build Coastguard Worker return true;
973*d9f75844SAndroid Build Coastguard Worker }
974*d9f75844SAndroid Build Coastguard Worker // Allow any port if relevant field trial is set. This allows disabling the
975*d9f75844SAndroid Build Coastguard Worker // check.
976*d9f75844SAndroid Build Coastguard Worker if (field_trials && field_trials->IsEnabled("WebRTC-Turn-AllowSystemPorts")) {
977*d9f75844SAndroid Build Coastguard Worker return true;
978*d9f75844SAndroid Build Coastguard Worker }
979*d9f75844SAndroid Build Coastguard Worker return false;
980*d9f75844SAndroid Build Coastguard Worker }
981*d9f75844SAndroid Build Coastguard Worker
TryAlternateServer()982*d9f75844SAndroid Build Coastguard Worker void TurnPort::TryAlternateServer() {
983*d9f75844SAndroid Build Coastguard Worker if (server_address().proto == PROTO_UDP) {
984*d9f75844SAndroid Build Coastguard Worker // Send another allocate request to alternate server, with the received
985*d9f75844SAndroid Build Coastguard Worker // realm and nonce values.
986*d9f75844SAndroid Build Coastguard Worker SendRequest(new TurnAllocateRequest(this), 0);
987*d9f75844SAndroid Build Coastguard Worker } else {
988*d9f75844SAndroid Build Coastguard Worker // Since it's TCP, we have to delete the connected socket and reconnect
989*d9f75844SAndroid Build Coastguard Worker // with the alternate server. PrepareAddress will send stun binding once
990*d9f75844SAndroid Build Coastguard Worker // the new socket is connected.
991*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(server_address().proto == PROTO_TCP ||
992*d9f75844SAndroid Build Coastguard Worker server_address().proto == PROTO_TLS);
993*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!SharedSocket());
994*d9f75844SAndroid Build Coastguard Worker delete socket_;
995*d9f75844SAndroid Build Coastguard Worker socket_ = nullptr;
996*d9f75844SAndroid Build Coastguard Worker PrepareAddress();
997*d9f75844SAndroid Build Coastguard Worker }
998*d9f75844SAndroid Build Coastguard Worker }
999*d9f75844SAndroid Build Coastguard Worker
OnAllocateRequestTimeout()1000*d9f75844SAndroid Build Coastguard Worker void TurnPort::OnAllocateRequestTimeout() {
1001*d9f75844SAndroid Build Coastguard Worker OnAllocateError(SERVER_NOT_REACHABLE_ERROR,
1002*d9f75844SAndroid Build Coastguard Worker "TURN allocate request timed out.");
1003*d9f75844SAndroid Build Coastguard Worker }
1004*d9f75844SAndroid Build Coastguard Worker
HandleDataIndication(const char * data,size_t size,int64_t packet_time_us)1005*d9f75844SAndroid Build Coastguard Worker void TurnPort::HandleDataIndication(const char* data,
1006*d9f75844SAndroid Build Coastguard Worker size_t size,
1007*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_us) {
1008*d9f75844SAndroid Build Coastguard Worker // Read in the message, and process according to RFC5766, Section 10.4.
1009*d9f75844SAndroid Build Coastguard Worker rtc::ByteBufferReader buf(data, size);
1010*d9f75844SAndroid Build Coastguard Worker TurnMessage msg;
1011*d9f75844SAndroid Build Coastguard Worker if (!msg.Read(&buf)) {
1012*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1013*d9f75844SAndroid Build Coastguard Worker << ": Received invalid TURN data indication";
1014*d9f75844SAndroid Build Coastguard Worker return;
1015*d9f75844SAndroid Build Coastguard Worker }
1016*d9f75844SAndroid Build Coastguard Worker
1017*d9f75844SAndroid Build Coastguard Worker // Check mandatory attributes.
1018*d9f75844SAndroid Build Coastguard Worker const StunAddressAttribute* addr_attr =
1019*d9f75844SAndroid Build Coastguard Worker msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
1020*d9f75844SAndroid Build Coastguard Worker if (!addr_attr) {
1021*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1022*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
1023*d9f75844SAndroid Build Coastguard Worker "in data indication.";
1024*d9f75844SAndroid Build Coastguard Worker return;
1025*d9f75844SAndroid Build Coastguard Worker }
1026*d9f75844SAndroid Build Coastguard Worker
1027*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
1028*d9f75844SAndroid Build Coastguard Worker if (!data_attr) {
1029*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1030*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_DATA attribute in "
1031*d9f75844SAndroid Build Coastguard Worker "data indication.";
1032*d9f75844SAndroid Build Coastguard Worker return;
1033*d9f75844SAndroid Build Coastguard Worker }
1034*d9f75844SAndroid Build Coastguard Worker
1035*d9f75844SAndroid Build Coastguard Worker // Log a warning if the data didn't come from an address that we think we have
1036*d9f75844SAndroid Build Coastguard Worker // a permission for.
1037*d9f75844SAndroid Build Coastguard Worker rtc::SocketAddress ext_addr(addr_attr->GetAddress());
1038*d9f75844SAndroid Build Coastguard Worker if (!HasPermission(ext_addr.ipaddr())) {
1039*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1040*d9f75844SAndroid Build Coastguard Worker << ": Received TURN data indication with unknown "
1041*d9f75844SAndroid Build Coastguard Worker "peer address, addr: "
1042*d9f75844SAndroid Build Coastguard Worker << ext_addr.ToSensitiveString();
1043*d9f75844SAndroid Build Coastguard Worker }
1044*d9f75844SAndroid Build Coastguard Worker
1045*d9f75844SAndroid Build Coastguard Worker DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr, PROTO_UDP,
1046*d9f75844SAndroid Build Coastguard Worker packet_time_us);
1047*d9f75844SAndroid Build Coastguard Worker }
1048*d9f75844SAndroid Build Coastguard Worker
HandleChannelData(int channel_id,const char * data,size_t size,int64_t packet_time_us)1049*d9f75844SAndroid Build Coastguard Worker void TurnPort::HandleChannelData(int channel_id,
1050*d9f75844SAndroid Build Coastguard Worker const char* data,
1051*d9f75844SAndroid Build Coastguard Worker size_t size,
1052*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_us) {
1053*d9f75844SAndroid Build Coastguard Worker // Read the message, and process according to RFC5766, Section 11.6.
1054*d9f75844SAndroid Build Coastguard Worker // 0 1 2 3
1055*d9f75844SAndroid Build Coastguard Worker // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1056*d9f75844SAndroid Build Coastguard Worker // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1057*d9f75844SAndroid Build Coastguard Worker // | Channel Number | Length |
1058*d9f75844SAndroid Build Coastguard Worker // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1059*d9f75844SAndroid Build Coastguard Worker // | |
1060*d9f75844SAndroid Build Coastguard Worker // / Application Data /
1061*d9f75844SAndroid Build Coastguard Worker // / /
1062*d9f75844SAndroid Build Coastguard Worker // | |
1063*d9f75844SAndroid Build Coastguard Worker // | +-------------------------------+
1064*d9f75844SAndroid Build Coastguard Worker // | |
1065*d9f75844SAndroid Build Coastguard Worker // +-------------------------------+
1066*d9f75844SAndroid Build Coastguard Worker
1067*d9f75844SAndroid Build Coastguard Worker // Extract header fields from the message.
1068*d9f75844SAndroid Build Coastguard Worker uint16_t len = rtc::GetBE16(data + 2);
1069*d9f75844SAndroid Build Coastguard Worker if (len > size - TURN_CHANNEL_HEADER_SIZE) {
1070*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1071*d9f75844SAndroid Build Coastguard Worker << ": Received TURN channel data message with "
1072*d9f75844SAndroid Build Coastguard Worker "incorrect length, len: "
1073*d9f75844SAndroid Build Coastguard Worker << len;
1074*d9f75844SAndroid Build Coastguard Worker return;
1075*d9f75844SAndroid Build Coastguard Worker }
1076*d9f75844SAndroid Build Coastguard Worker // Allowing messages larger than `len`, as ChannelData can be padded.
1077*d9f75844SAndroid Build Coastguard Worker
1078*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry = FindEntry(channel_id);
1079*d9f75844SAndroid Build Coastguard Worker if (!entry) {
1080*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1081*d9f75844SAndroid Build Coastguard Worker << ": Received TURN channel data message for invalid "
1082*d9f75844SAndroid Build Coastguard Worker "channel, channel_id: "
1083*d9f75844SAndroid Build Coastguard Worker << channel_id;
1084*d9f75844SAndroid Build Coastguard Worker return;
1085*d9f75844SAndroid Build Coastguard Worker }
1086*d9f75844SAndroid Build Coastguard Worker
1087*d9f75844SAndroid Build Coastguard Worker DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
1088*d9f75844SAndroid Build Coastguard Worker PROTO_UDP, packet_time_us);
1089*d9f75844SAndroid Build Coastguard Worker }
1090*d9f75844SAndroid Build Coastguard Worker
DispatchPacket(const char * data,size_t size,const rtc::SocketAddress & remote_addr,ProtocolType proto,int64_t packet_time_us)1091*d9f75844SAndroid Build Coastguard Worker void TurnPort::DispatchPacket(const char* data,
1092*d9f75844SAndroid Build Coastguard Worker size_t size,
1093*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& remote_addr,
1094*d9f75844SAndroid Build Coastguard Worker ProtocolType proto,
1095*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_us) {
1096*d9f75844SAndroid Build Coastguard Worker if (Connection* conn = GetConnection(remote_addr)) {
1097*d9f75844SAndroid Build Coastguard Worker conn->OnReadPacket(data, size, packet_time_us);
1098*d9f75844SAndroid Build Coastguard Worker } else {
1099*d9f75844SAndroid Build Coastguard Worker Port::OnReadPacket(data, size, remote_addr, proto);
1100*d9f75844SAndroid Build Coastguard Worker }
1101*d9f75844SAndroid Build Coastguard Worker }
1102*d9f75844SAndroid Build Coastguard Worker
ScheduleRefresh(uint32_t lifetime)1103*d9f75844SAndroid Build Coastguard Worker bool TurnPort::ScheduleRefresh(uint32_t lifetime) {
1104*d9f75844SAndroid Build Coastguard Worker // Lifetime is in seconds, delay is in milliseconds.
1105*d9f75844SAndroid Build Coastguard Worker int delay = 1 * 60 * 1000;
1106*d9f75844SAndroid Build Coastguard Worker
1107*d9f75844SAndroid Build Coastguard Worker // Cutoff lifetime bigger than 1h.
1108*d9f75844SAndroid Build Coastguard Worker constexpr uint32_t max_lifetime = 60 * 60;
1109*d9f75844SAndroid Build Coastguard Worker
1110*d9f75844SAndroid Build Coastguard Worker if (lifetime < 2 * 60) {
1111*d9f75844SAndroid Build Coastguard Worker // The RFC does not mention a lower limit on lifetime.
1112*d9f75844SAndroid Build Coastguard Worker // So if server sends a value less than 2 minutes, we schedule a refresh
1113*d9f75844SAndroid Build Coastguard Worker // for half lifetime.
1114*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1115*d9f75844SAndroid Build Coastguard Worker << ": Received response with short lifetime: "
1116*d9f75844SAndroid Build Coastguard Worker << lifetime << " seconds.";
1117*d9f75844SAndroid Build Coastguard Worker delay = (lifetime * 1000) / 2;
1118*d9f75844SAndroid Build Coastguard Worker } else if (lifetime > max_lifetime) {
1119*d9f75844SAndroid Build Coastguard Worker // Make 1 hour largest delay, and then we schedule a refresh for one minute
1120*d9f75844SAndroid Build Coastguard Worker // less than max lifetime.
1121*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << ToString()
1122*d9f75844SAndroid Build Coastguard Worker << ": Received response with long lifetime: "
1123*d9f75844SAndroid Build Coastguard Worker << lifetime << " seconds.";
1124*d9f75844SAndroid Build Coastguard Worker delay = (max_lifetime - 60) * 1000;
1125*d9f75844SAndroid Build Coastguard Worker } else {
1126*d9f75844SAndroid Build Coastguard Worker // Normal case,
1127*d9f75844SAndroid Build Coastguard Worker // we schedule a refresh for one minute less than requested lifetime.
1128*d9f75844SAndroid Build Coastguard Worker delay = (lifetime - 60) * 1000;
1129*d9f75844SAndroid Build Coastguard Worker }
1130*d9f75844SAndroid Build Coastguard Worker
1131*d9f75844SAndroid Build Coastguard Worker SendRequest(new TurnRefreshRequest(this), delay);
1132*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << ToString() << ": Scheduled refresh in " << delay << "ms.";
1133*d9f75844SAndroid Build Coastguard Worker return true;
1134*d9f75844SAndroid Build Coastguard Worker }
1135*d9f75844SAndroid Build Coastguard Worker
SendRequest(StunRequest * req,int delay)1136*d9f75844SAndroid Build Coastguard Worker void TurnPort::SendRequest(StunRequest* req, int delay) {
1137*d9f75844SAndroid Build Coastguard Worker request_manager_.SendDelayed(req, delay);
1138*d9f75844SAndroid Build Coastguard Worker }
1139*d9f75844SAndroid Build Coastguard Worker
AddRequestAuthInfo(StunMessage * msg)1140*d9f75844SAndroid Build Coastguard Worker void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
1141*d9f75844SAndroid Build Coastguard Worker // If we've gotten the necessary data from the server, add it to our request.
1142*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!hash_.empty());
1143*d9f75844SAndroid Build Coastguard Worker msg->AddAttribute(std::make_unique<StunByteStringAttribute>(
1144*d9f75844SAndroid Build Coastguard Worker STUN_ATTR_USERNAME, credentials_.username));
1145*d9f75844SAndroid Build Coastguard Worker msg->AddAttribute(
1146*d9f75844SAndroid Build Coastguard Worker std::make_unique<StunByteStringAttribute>(STUN_ATTR_REALM, realm_));
1147*d9f75844SAndroid Build Coastguard Worker msg->AddAttribute(
1148*d9f75844SAndroid Build Coastguard Worker std::make_unique<StunByteStringAttribute>(STUN_ATTR_NONCE, nonce_));
1149*d9f75844SAndroid Build Coastguard Worker const bool success = msg->AddMessageIntegrity(hash());
1150*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(success);
1151*d9f75844SAndroid Build Coastguard Worker }
1152*d9f75844SAndroid Build Coastguard Worker
Send(const void * data,size_t len,const rtc::PacketOptions & options)1153*d9f75844SAndroid Build Coastguard Worker int TurnPort::Send(const void* data,
1154*d9f75844SAndroid Build Coastguard Worker size_t len,
1155*d9f75844SAndroid Build Coastguard Worker const rtc::PacketOptions& options) {
1156*d9f75844SAndroid Build Coastguard Worker return socket_->SendTo(data, len, server_address_.address, options);
1157*d9f75844SAndroid Build Coastguard Worker }
1158*d9f75844SAndroid Build Coastguard Worker
UpdateHash()1159*d9f75844SAndroid Build Coastguard Worker void TurnPort::UpdateHash() {
1160*d9f75844SAndroid Build Coastguard Worker const bool success = ComputeStunCredentialHash(credentials_.username, realm_,
1161*d9f75844SAndroid Build Coastguard Worker credentials_.password, &hash_);
1162*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(success);
1163*d9f75844SAndroid Build Coastguard Worker }
1164*d9f75844SAndroid Build Coastguard Worker
UpdateNonce(StunMessage * response)1165*d9f75844SAndroid Build Coastguard Worker bool TurnPort::UpdateNonce(StunMessage* response) {
1166*d9f75844SAndroid Build Coastguard Worker // When stale nonce error received, we should update
1167*d9f75844SAndroid Build Coastguard Worker // hash and store realm and nonce.
1168*d9f75844SAndroid Build Coastguard Worker // Check the mandatory attributes.
1169*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* realm_attr =
1170*d9f75844SAndroid Build Coastguard Worker response->GetByteString(STUN_ATTR_REALM);
1171*d9f75844SAndroid Build Coastguard Worker if (!realm_attr) {
1172*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
1173*d9f75844SAndroid Build Coastguard Worker "stale nonce error response.";
1174*d9f75844SAndroid Build Coastguard Worker return false;
1175*d9f75844SAndroid Build Coastguard Worker }
1176*d9f75844SAndroid Build Coastguard Worker set_realm(realm_attr->string_view());
1177*d9f75844SAndroid Build Coastguard Worker
1178*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* nonce_attr =
1179*d9f75844SAndroid Build Coastguard Worker response->GetByteString(STUN_ATTR_NONCE);
1180*d9f75844SAndroid Build Coastguard Worker if (!nonce_attr) {
1181*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
1182*d9f75844SAndroid Build Coastguard Worker "stale nonce error response.";
1183*d9f75844SAndroid Build Coastguard Worker return false;
1184*d9f75844SAndroid Build Coastguard Worker }
1185*d9f75844SAndroid Build Coastguard Worker set_nonce(nonce_attr->string_view());
1186*d9f75844SAndroid Build Coastguard Worker return true;
1187*d9f75844SAndroid Build Coastguard Worker }
1188*d9f75844SAndroid Build Coastguard Worker
ResetNonce()1189*d9f75844SAndroid Build Coastguard Worker void TurnPort::ResetNonce() {
1190*d9f75844SAndroid Build Coastguard Worker hash_.clear();
1191*d9f75844SAndroid Build Coastguard Worker nonce_.clear();
1192*d9f75844SAndroid Build Coastguard Worker realm_.clear();
1193*d9f75844SAndroid Build Coastguard Worker }
1194*d9f75844SAndroid Build Coastguard Worker
HasPermission(const rtc::IPAddress & ipaddr) const1195*d9f75844SAndroid Build Coastguard Worker bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
1196*d9f75844SAndroid Build Coastguard Worker return absl::c_any_of(entries_, [&ipaddr](const auto& e) {
1197*d9f75844SAndroid Build Coastguard Worker return e->address().ipaddr() == ipaddr;
1198*d9f75844SAndroid Build Coastguard Worker });
1199*d9f75844SAndroid Build Coastguard Worker }
1200*d9f75844SAndroid Build Coastguard Worker
FindEntry(const rtc::SocketAddress & addr) const1201*d9f75844SAndroid Build Coastguard Worker TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
1202*d9f75844SAndroid Build Coastguard Worker auto it = absl::c_find_if(
1203*d9f75844SAndroid Build Coastguard Worker entries_, [&addr](const auto& e) { return e->address() == addr; });
1204*d9f75844SAndroid Build Coastguard Worker return (it != entries_.end()) ? it->get() : nullptr;
1205*d9f75844SAndroid Build Coastguard Worker }
1206*d9f75844SAndroid Build Coastguard Worker
FindEntry(int channel_id) const1207*d9f75844SAndroid Build Coastguard Worker TurnEntry* TurnPort::FindEntry(int channel_id) const {
1208*d9f75844SAndroid Build Coastguard Worker auto it = absl::c_find_if(entries_, [&channel_id](const auto& e) {
1209*d9f75844SAndroid Build Coastguard Worker return e->channel_id() == channel_id;
1210*d9f75844SAndroid Build Coastguard Worker });
1211*d9f75844SAndroid Build Coastguard Worker return (it != entries_.end()) ? it->get() : nullptr;
1212*d9f75844SAndroid Build Coastguard Worker }
1213*d9f75844SAndroid Build Coastguard Worker
CreateOrRefreshEntry(Connection * conn,int channel_number)1214*d9f75844SAndroid Build Coastguard Worker bool TurnPort::CreateOrRefreshEntry(Connection* conn, int channel_number) {
1215*d9f75844SAndroid Build Coastguard Worker const Candidate& remote_candidate = conn->remote_candidate();
1216*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry = FindEntry(remote_candidate.address());
1217*d9f75844SAndroid Build Coastguard Worker if (entry == nullptr) {
1218*d9f75844SAndroid Build Coastguard Worker entries_.push_back(std::make_unique<TurnEntry>(this, conn, channel_number));
1219*d9f75844SAndroid Build Coastguard Worker return true;
1220*d9f75844SAndroid Build Coastguard Worker }
1221*d9f75844SAndroid Build Coastguard Worker
1222*d9f75844SAndroid Build Coastguard Worker // Associate this connection object with an existing entry. If the entry
1223*d9f75844SAndroid Build Coastguard Worker // has been scheduled for deletion, this will cancel that task.
1224*d9f75844SAndroid Build Coastguard Worker entry->TrackConnection(conn);
1225*d9f75844SAndroid Build Coastguard Worker
1226*d9f75844SAndroid Build Coastguard Worker return false;
1227*d9f75844SAndroid Build Coastguard Worker }
1228*d9f75844SAndroid Build Coastguard Worker
HandleConnectionDestroyed(Connection * conn)1229*d9f75844SAndroid Build Coastguard Worker void TurnPort::HandleConnectionDestroyed(Connection* conn) {
1230*d9f75844SAndroid Build Coastguard Worker // Schedule an event to destroy TurnEntry for the connection, which is
1231*d9f75844SAndroid Build Coastguard Worker // being destroyed.
1232*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& remote_address = conn->remote_candidate().address();
1233*d9f75844SAndroid Build Coastguard Worker // We should always have an entry for this connection.
1234*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry = FindEntry(remote_address);
1235*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> flag =
1236*d9f75844SAndroid Build Coastguard Worker entry->UntrackConnection(conn);
1237*d9f75844SAndroid Build Coastguard Worker if (flag) {
1238*d9f75844SAndroid Build Coastguard Worker // An assumption here is that the lifetime flag for the entry, is within
1239*d9f75844SAndroid Build Coastguard Worker // the lifetime scope of `task_safety_` and therefore use of `this` is safe.
1240*d9f75844SAndroid Build Coastguard Worker // If an entry gets reused (associated with a new connection) while this
1241*d9f75844SAndroid Build Coastguard Worker // task is pending, the entry will reset the safety flag, thus cancel this
1242*d9f75844SAndroid Build Coastguard Worker // task.
1243*d9f75844SAndroid Build Coastguard Worker thread()->PostDelayedTask(SafeTask(flag,
1244*d9f75844SAndroid Build Coastguard Worker [this, entry] {
1245*d9f75844SAndroid Build Coastguard Worker entries_.erase(absl::c_find_if(
1246*d9f75844SAndroid Build Coastguard Worker entries_, [entry](const auto& e) {
1247*d9f75844SAndroid Build Coastguard Worker return e.get() == entry;
1248*d9f75844SAndroid Build Coastguard Worker }));
1249*d9f75844SAndroid Build Coastguard Worker }),
1250*d9f75844SAndroid Build Coastguard Worker kTurnPermissionTimeout);
1251*d9f75844SAndroid Build Coastguard Worker }
1252*d9f75844SAndroid Build Coastguard Worker }
1253*d9f75844SAndroid Build Coastguard Worker
SetCallbacksForTest(CallbacksForTest * callbacks)1254*d9f75844SAndroid Build Coastguard Worker void TurnPort::SetCallbacksForTest(CallbacksForTest* callbacks) {
1255*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!callbacks_for_test_);
1256*d9f75844SAndroid Build Coastguard Worker callbacks_for_test_ = callbacks;
1257*d9f75844SAndroid Build Coastguard Worker }
1258*d9f75844SAndroid Build Coastguard Worker
SetEntryChannelId(const rtc::SocketAddress & address,int channel_id)1259*d9f75844SAndroid Build Coastguard Worker bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address,
1260*d9f75844SAndroid Build Coastguard Worker int channel_id) {
1261*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry = FindEntry(address);
1262*d9f75844SAndroid Build Coastguard Worker if (!entry) {
1263*d9f75844SAndroid Build Coastguard Worker return false;
1264*d9f75844SAndroid Build Coastguard Worker }
1265*d9f75844SAndroid Build Coastguard Worker entry->set_channel_id(channel_id);
1266*d9f75844SAndroid Build Coastguard Worker return true;
1267*d9f75844SAndroid Build Coastguard Worker }
1268*d9f75844SAndroid Build Coastguard Worker
ReconstructedServerUrl()1269*d9f75844SAndroid Build Coastguard Worker std::string TurnPort::ReconstructedServerUrl() {
1270*d9f75844SAndroid Build Coastguard Worker // draft-petithuguenin-behave-turn-uris-01
1271*d9f75844SAndroid Build Coastguard Worker // turnURI = scheme ":" turn-host [ ":" turn-port ]
1272*d9f75844SAndroid Build Coastguard Worker // [ "?transport=" transport ]
1273*d9f75844SAndroid Build Coastguard Worker // scheme = "turn" / "turns"
1274*d9f75844SAndroid Build Coastguard Worker // transport = "udp" / "tcp" / transport-ext
1275*d9f75844SAndroid Build Coastguard Worker // transport-ext = 1*unreserved
1276*d9f75844SAndroid Build Coastguard Worker // turn-host = IP-literal / IPv4address / reg-name
1277*d9f75844SAndroid Build Coastguard Worker // turn-port = *DIGIT
1278*d9f75844SAndroid Build Coastguard Worker std::string scheme = "turn";
1279*d9f75844SAndroid Build Coastguard Worker std::string transport = "tcp";
1280*d9f75844SAndroid Build Coastguard Worker switch (server_address_.proto) {
1281*d9f75844SAndroid Build Coastguard Worker case PROTO_SSLTCP:
1282*d9f75844SAndroid Build Coastguard Worker case PROTO_TLS:
1283*d9f75844SAndroid Build Coastguard Worker scheme = "turns";
1284*d9f75844SAndroid Build Coastguard Worker break;
1285*d9f75844SAndroid Build Coastguard Worker case PROTO_UDP:
1286*d9f75844SAndroid Build Coastguard Worker transport = "udp";
1287*d9f75844SAndroid Build Coastguard Worker break;
1288*d9f75844SAndroid Build Coastguard Worker case PROTO_TCP:
1289*d9f75844SAndroid Build Coastguard Worker break;
1290*d9f75844SAndroid Build Coastguard Worker }
1291*d9f75844SAndroid Build Coastguard Worker rtc::StringBuilder url;
1292*d9f75844SAndroid Build Coastguard Worker url << scheme << ":" << server_address_.address.hostname() << ":"
1293*d9f75844SAndroid Build Coastguard Worker << server_address_.address.port() << "?transport=" << transport;
1294*d9f75844SAndroid Build Coastguard Worker return url.Release();
1295*d9f75844SAndroid Build Coastguard Worker }
1296*d9f75844SAndroid Build Coastguard Worker
TurnCustomizerMaybeModifyOutgoingStunMessage(StunMessage * message)1297*d9f75844SAndroid Build Coastguard Worker void TurnPort::TurnCustomizerMaybeModifyOutgoingStunMessage(
1298*d9f75844SAndroid Build Coastguard Worker StunMessage* message) {
1299*d9f75844SAndroid Build Coastguard Worker if (turn_customizer_ == nullptr) {
1300*d9f75844SAndroid Build Coastguard Worker return;
1301*d9f75844SAndroid Build Coastguard Worker }
1302*d9f75844SAndroid Build Coastguard Worker
1303*d9f75844SAndroid Build Coastguard Worker turn_customizer_->MaybeModifyOutgoingStunMessage(this, message);
1304*d9f75844SAndroid Build Coastguard Worker }
1305*d9f75844SAndroid Build Coastguard Worker
TurnCustomizerAllowChannelData(const void * data,size_t size,bool payload)1306*d9f75844SAndroid Build Coastguard Worker bool TurnPort::TurnCustomizerAllowChannelData(const void* data,
1307*d9f75844SAndroid Build Coastguard Worker size_t size,
1308*d9f75844SAndroid Build Coastguard Worker bool payload) {
1309*d9f75844SAndroid Build Coastguard Worker if (turn_customizer_ == nullptr) {
1310*d9f75844SAndroid Build Coastguard Worker return true;
1311*d9f75844SAndroid Build Coastguard Worker }
1312*d9f75844SAndroid Build Coastguard Worker
1313*d9f75844SAndroid Build Coastguard Worker return turn_customizer_->AllowChannelData(this, data, size, payload);
1314*d9f75844SAndroid Build Coastguard Worker }
1315*d9f75844SAndroid Build Coastguard Worker
MaybeAddTurnLoggingId(StunMessage * msg)1316*d9f75844SAndroid Build Coastguard Worker void TurnPort::MaybeAddTurnLoggingId(StunMessage* msg) {
1317*d9f75844SAndroid Build Coastguard Worker if (!turn_logging_id_.empty()) {
1318*d9f75844SAndroid Build Coastguard Worker msg->AddAttribute(std::make_unique<StunByteStringAttribute>(
1319*d9f75844SAndroid Build Coastguard Worker STUN_ATTR_TURN_LOGGING_ID, turn_logging_id_));
1320*d9f75844SAndroid Build Coastguard Worker }
1321*d9f75844SAndroid Build Coastguard Worker }
1322*d9f75844SAndroid Build Coastguard Worker
TurnAllocateRequest(TurnPort * port)1323*d9f75844SAndroid Build Coastguard Worker TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
1324*d9f75844SAndroid Build Coastguard Worker : StunRequest(port->request_manager(),
1325*d9f75844SAndroid Build Coastguard Worker std::make_unique<TurnMessage>(TURN_ALLOCATE_REQUEST)),
1326*d9f75844SAndroid Build Coastguard Worker port_(port) {
1327*d9f75844SAndroid Build Coastguard Worker StunMessage* message = mutable_msg();
1328*d9f75844SAndroid Build Coastguard Worker // Create the request as indicated in RFC 5766, Section 6.1.
1329*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(message->type(), TURN_ALLOCATE_REQUEST);
1330*d9f75844SAndroid Build Coastguard Worker auto transport_attr =
1331*d9f75844SAndroid Build Coastguard Worker StunAttribute::CreateUInt32(STUN_ATTR_REQUESTED_TRANSPORT);
1332*d9f75844SAndroid Build Coastguard Worker transport_attr->SetValue(IPPROTO_UDP << 24);
1333*d9f75844SAndroid Build Coastguard Worker message->AddAttribute(std::move(transport_attr));
1334*d9f75844SAndroid Build Coastguard Worker if (!port_->hash().empty()) {
1335*d9f75844SAndroid Build Coastguard Worker port_->AddRequestAuthInfo(message);
1336*d9f75844SAndroid Build Coastguard Worker }
1337*d9f75844SAndroid Build Coastguard Worker port_->MaybeAddTurnLoggingId(message);
1338*d9f75844SAndroid Build Coastguard Worker port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message);
1339*d9f75844SAndroid Build Coastguard Worker }
1340*d9f75844SAndroid Build Coastguard Worker
OnSent()1341*d9f75844SAndroid Build Coastguard Worker void TurnAllocateRequest::OnSent() {
1342*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString() << ": TURN allocate request sent, id="
1343*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1344*d9f75844SAndroid Build Coastguard Worker StunRequest::OnSent();
1345*d9f75844SAndroid Build Coastguard Worker }
1346*d9f75844SAndroid Build Coastguard Worker
OnResponse(StunMessage * response)1347*d9f75844SAndroid Build Coastguard Worker void TurnAllocateRequest::OnResponse(StunMessage* response) {
1348*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1349*d9f75844SAndroid Build Coastguard Worker << ": TURN allocate requested successfully, id="
1350*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id())
1351*d9f75844SAndroid Build Coastguard Worker << ", code=0" // Makes logging easier to parse.
1352*d9f75844SAndroid Build Coastguard Worker ", rtt="
1353*d9f75844SAndroid Build Coastguard Worker << Elapsed();
1354*d9f75844SAndroid Build Coastguard Worker
1355*d9f75844SAndroid Build Coastguard Worker // Check mandatory attributes as indicated in RFC5766, Section 6.3.
1356*d9f75844SAndroid Build Coastguard Worker const StunAddressAttribute* mapped_attr =
1357*d9f75844SAndroid Build Coastguard Worker response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1358*d9f75844SAndroid Build Coastguard Worker if (!mapped_attr) {
1359*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1360*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
1361*d9f75844SAndroid Build Coastguard Worker "attribute in allocate success response";
1362*d9f75844SAndroid Build Coastguard Worker return;
1363*d9f75844SAndroid Build Coastguard Worker }
1364*d9f75844SAndroid Build Coastguard Worker // Using XOR-Mapped-Address for stun.
1365*d9f75844SAndroid Build Coastguard Worker port_->OnStunAddress(mapped_attr->GetAddress());
1366*d9f75844SAndroid Build Coastguard Worker
1367*d9f75844SAndroid Build Coastguard Worker const StunAddressAttribute* relayed_attr =
1368*d9f75844SAndroid Build Coastguard Worker response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
1369*d9f75844SAndroid Build Coastguard Worker if (!relayed_attr) {
1370*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1371*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
1372*d9f75844SAndroid Build Coastguard Worker "attribute in allocate success response";
1373*d9f75844SAndroid Build Coastguard Worker return;
1374*d9f75844SAndroid Build Coastguard Worker }
1375*d9f75844SAndroid Build Coastguard Worker
1376*d9f75844SAndroid Build Coastguard Worker const StunUInt32Attribute* lifetime_attr =
1377*d9f75844SAndroid Build Coastguard Worker response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1378*d9f75844SAndroid Build Coastguard Worker if (!lifetime_attr) {
1379*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1380*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_TURN_LIFETIME attribute in "
1381*d9f75844SAndroid Build Coastguard Worker "allocate success response";
1382*d9f75844SAndroid Build Coastguard Worker return;
1383*d9f75844SAndroid Build Coastguard Worker }
1384*d9f75844SAndroid Build Coastguard Worker // Notify the port the allocate succeeded, and schedule a refresh request.
1385*d9f75844SAndroid Build Coastguard Worker port_->OnAllocateSuccess(relayed_attr->GetAddress(),
1386*d9f75844SAndroid Build Coastguard Worker mapped_attr->GetAddress());
1387*d9f75844SAndroid Build Coastguard Worker port_->ScheduleRefresh(lifetime_attr->value());
1388*d9f75844SAndroid Build Coastguard Worker }
1389*d9f75844SAndroid Build Coastguard Worker
OnErrorResponse(StunMessage * response)1390*d9f75844SAndroid Build Coastguard Worker void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
1391*d9f75844SAndroid Build Coastguard Worker // Process error response according to RFC5766, Section 6.4.
1392*d9f75844SAndroid Build Coastguard Worker int error_code = response->GetErrorCodeValue();
1393*d9f75844SAndroid Build Coastguard Worker
1394*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1395*d9f75844SAndroid Build Coastguard Worker << ": Received TURN allocate error response, id="
1396*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id()) << ", code=" << error_code
1397*d9f75844SAndroid Build Coastguard Worker << ", rtt=" << Elapsed();
1398*d9f75844SAndroid Build Coastguard Worker
1399*d9f75844SAndroid Build Coastguard Worker switch (error_code) {
1400*d9f75844SAndroid Build Coastguard Worker case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
1401*d9f75844SAndroid Build Coastguard Worker OnAuthChallenge(response, error_code);
1402*d9f75844SAndroid Build Coastguard Worker break;
1403*d9f75844SAndroid Build Coastguard Worker case STUN_ERROR_TRY_ALTERNATE:
1404*d9f75844SAndroid Build Coastguard Worker OnTryAlternate(response, error_code);
1405*d9f75844SAndroid Build Coastguard Worker break;
1406*d9f75844SAndroid Build Coastguard Worker case STUN_ERROR_ALLOCATION_MISMATCH: {
1407*d9f75844SAndroid Build Coastguard Worker // We must handle this error async because trying to delete the socket in
1408*d9f75844SAndroid Build Coastguard Worker // OnErrorResponse will cause a deadlock on the socket.
1409*d9f75844SAndroid Build Coastguard Worker TurnPort* port = port_;
1410*d9f75844SAndroid Build Coastguard Worker port->thread()->PostTask(SafeTask(
1411*d9f75844SAndroid Build Coastguard Worker port->task_safety_.flag(), [port] { port->OnAllocateMismatch(); }));
1412*d9f75844SAndroid Build Coastguard Worker } break;
1413*d9f75844SAndroid Build Coastguard Worker default:
1414*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1415*d9f75844SAndroid Build Coastguard Worker << ": Received TURN allocate error response, id="
1416*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id()) << ", code=" << error_code
1417*d9f75844SAndroid Build Coastguard Worker << ", rtt=" << Elapsed();
1418*d9f75844SAndroid Build Coastguard Worker const StunErrorCodeAttribute* attr = response->GetErrorCode();
1419*d9f75844SAndroid Build Coastguard Worker port_->OnAllocateError(error_code, attr ? attr->reason() : "");
1420*d9f75844SAndroid Build Coastguard Worker }
1421*d9f75844SAndroid Build Coastguard Worker }
1422*d9f75844SAndroid Build Coastguard Worker
OnTimeout()1423*d9f75844SAndroid Build Coastguard Worker void TurnAllocateRequest::OnTimeout() {
1424*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString() << ": TURN allocate request "
1425*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id()) << " timeout";
1426*d9f75844SAndroid Build Coastguard Worker port_->OnAllocateRequestTimeout();
1427*d9f75844SAndroid Build Coastguard Worker }
1428*d9f75844SAndroid Build Coastguard Worker
OnAuthChallenge(StunMessage * response,int code)1429*d9f75844SAndroid Build Coastguard Worker void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
1430*d9f75844SAndroid Build Coastguard Worker // If we failed to authenticate even after we sent our credentials, fail hard.
1431*d9f75844SAndroid Build Coastguard Worker if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
1432*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1433*d9f75844SAndroid Build Coastguard Worker << ": Failed to authenticate with the server "
1434*d9f75844SAndroid Build Coastguard Worker "after challenge.";
1435*d9f75844SAndroid Build Coastguard Worker const StunErrorCodeAttribute* attr = response->GetErrorCode();
1436*d9f75844SAndroid Build Coastguard Worker port_->OnAllocateError(STUN_ERROR_UNAUTHORIZED, attr ? attr->reason() : "");
1437*d9f75844SAndroid Build Coastguard Worker return;
1438*d9f75844SAndroid Build Coastguard Worker }
1439*d9f75844SAndroid Build Coastguard Worker
1440*d9f75844SAndroid Build Coastguard Worker // Check the mandatory attributes.
1441*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* realm_attr =
1442*d9f75844SAndroid Build Coastguard Worker response->GetByteString(STUN_ATTR_REALM);
1443*d9f75844SAndroid Build Coastguard Worker if (!realm_attr) {
1444*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1445*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_REALM attribute in "
1446*d9f75844SAndroid Build Coastguard Worker "allocate unauthorized response.";
1447*d9f75844SAndroid Build Coastguard Worker return;
1448*d9f75844SAndroid Build Coastguard Worker }
1449*d9f75844SAndroid Build Coastguard Worker port_->set_realm(realm_attr->string_view());
1450*d9f75844SAndroid Build Coastguard Worker
1451*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* nonce_attr =
1452*d9f75844SAndroid Build Coastguard Worker response->GetByteString(STUN_ATTR_NONCE);
1453*d9f75844SAndroid Build Coastguard Worker if (!nonce_attr) {
1454*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1455*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_NONCE attribute in "
1456*d9f75844SAndroid Build Coastguard Worker "allocate unauthorized response.";
1457*d9f75844SAndroid Build Coastguard Worker return;
1458*d9f75844SAndroid Build Coastguard Worker }
1459*d9f75844SAndroid Build Coastguard Worker port_->set_nonce(nonce_attr->string_view());
1460*d9f75844SAndroid Build Coastguard Worker
1461*d9f75844SAndroid Build Coastguard Worker // Send another allocate request, with the received realm and nonce values.
1462*d9f75844SAndroid Build Coastguard Worker port_->SendRequest(new TurnAllocateRequest(port_), 0);
1463*d9f75844SAndroid Build Coastguard Worker }
1464*d9f75844SAndroid Build Coastguard Worker
OnTryAlternate(StunMessage * response,int code)1465*d9f75844SAndroid Build Coastguard Worker void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
1466*d9f75844SAndroid Build Coastguard Worker // According to RFC 5389 section 11, there are use cases where
1467*d9f75844SAndroid Build Coastguard Worker // authentication of response is not possible, we're not validating
1468*d9f75844SAndroid Build Coastguard Worker // message integrity.
1469*d9f75844SAndroid Build Coastguard Worker const StunErrorCodeAttribute* error_code_attr = response->GetErrorCode();
1470*d9f75844SAndroid Build Coastguard Worker // Get the alternate server address attribute value.
1471*d9f75844SAndroid Build Coastguard Worker const StunAddressAttribute* alternate_server_attr =
1472*d9f75844SAndroid Build Coastguard Worker response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1473*d9f75844SAndroid Build Coastguard Worker if (!alternate_server_attr) {
1474*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1475*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_ALTERNATE_SERVER "
1476*d9f75844SAndroid Build Coastguard Worker "attribute in try alternate error response";
1477*d9f75844SAndroid Build Coastguard Worker port_->OnAllocateError(STUN_ERROR_TRY_ALTERNATE,
1478*d9f75844SAndroid Build Coastguard Worker error_code_attr ? error_code_attr->reason() : "");
1479*d9f75844SAndroid Build Coastguard Worker return;
1480*d9f75844SAndroid Build Coastguard Worker }
1481*d9f75844SAndroid Build Coastguard Worker if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1482*d9f75844SAndroid Build Coastguard Worker port_->OnAllocateError(STUN_ERROR_TRY_ALTERNATE,
1483*d9f75844SAndroid Build Coastguard Worker error_code_attr ? error_code_attr->reason() : "");
1484*d9f75844SAndroid Build Coastguard Worker return;
1485*d9f75844SAndroid Build Coastguard Worker }
1486*d9f75844SAndroid Build Coastguard Worker
1487*d9f75844SAndroid Build Coastguard Worker // Check the attributes.
1488*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* realm_attr =
1489*d9f75844SAndroid Build Coastguard Worker response->GetByteString(STUN_ATTR_REALM);
1490*d9f75844SAndroid Build Coastguard Worker if (realm_attr) {
1491*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1492*d9f75844SAndroid Build Coastguard Worker << ": Applying STUN_ATTR_REALM attribute in "
1493*d9f75844SAndroid Build Coastguard Worker "try alternate error response.";
1494*d9f75844SAndroid Build Coastguard Worker port_->set_realm(realm_attr->string_view());
1495*d9f75844SAndroid Build Coastguard Worker }
1496*d9f75844SAndroid Build Coastguard Worker
1497*d9f75844SAndroid Build Coastguard Worker const StunByteStringAttribute* nonce_attr =
1498*d9f75844SAndroid Build Coastguard Worker response->GetByteString(STUN_ATTR_NONCE);
1499*d9f75844SAndroid Build Coastguard Worker if (nonce_attr) {
1500*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1501*d9f75844SAndroid Build Coastguard Worker << ": Applying STUN_ATTR_NONCE attribute in "
1502*d9f75844SAndroid Build Coastguard Worker "try alternate error response.";
1503*d9f75844SAndroid Build Coastguard Worker port_->set_nonce(nonce_attr->string_view());
1504*d9f75844SAndroid Build Coastguard Worker }
1505*d9f75844SAndroid Build Coastguard Worker
1506*d9f75844SAndroid Build Coastguard Worker // For TCP, we can't close the original Tcp socket during handling a 300 as
1507*d9f75844SAndroid Build Coastguard Worker // we're still inside that socket's event handler. Doing so will cause
1508*d9f75844SAndroid Build Coastguard Worker // deadlock.
1509*d9f75844SAndroid Build Coastguard Worker TurnPort* port = port_;
1510*d9f75844SAndroid Build Coastguard Worker port->thread()->PostTask(SafeTask(port->task_safety_.flag(),
1511*d9f75844SAndroid Build Coastguard Worker [port] { port->TryAlternateServer(); }));
1512*d9f75844SAndroid Build Coastguard Worker }
1513*d9f75844SAndroid Build Coastguard Worker
TurnRefreshRequest(TurnPort * port,int lifetime)1514*d9f75844SAndroid Build Coastguard Worker TurnRefreshRequest::TurnRefreshRequest(TurnPort* port, int lifetime /*= -1*/)
1515*d9f75844SAndroid Build Coastguard Worker : StunRequest(port->request_manager(),
1516*d9f75844SAndroid Build Coastguard Worker std::make_unique<TurnMessage>(TURN_REFRESH_REQUEST)),
1517*d9f75844SAndroid Build Coastguard Worker port_(port) {
1518*d9f75844SAndroid Build Coastguard Worker StunMessage* message = mutable_msg();
1519*d9f75844SAndroid Build Coastguard Worker // Create the request as indicated in RFC 5766, Section 7.1.
1520*d9f75844SAndroid Build Coastguard Worker // No attributes need to be included.
1521*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(message->type(), TURN_REFRESH_REQUEST);
1522*d9f75844SAndroid Build Coastguard Worker if (lifetime > -1) {
1523*d9f75844SAndroid Build Coastguard Worker message->AddAttribute(
1524*d9f75844SAndroid Build Coastguard Worker std::make_unique<StunUInt32Attribute>(STUN_ATTR_LIFETIME, lifetime));
1525*d9f75844SAndroid Build Coastguard Worker }
1526*d9f75844SAndroid Build Coastguard Worker
1527*d9f75844SAndroid Build Coastguard Worker port_->AddRequestAuthInfo(message);
1528*d9f75844SAndroid Build Coastguard Worker port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message);
1529*d9f75844SAndroid Build Coastguard Worker }
1530*d9f75844SAndroid Build Coastguard Worker
OnSent()1531*d9f75844SAndroid Build Coastguard Worker void TurnRefreshRequest::OnSent() {
1532*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString() << ": TURN refresh request sent, id="
1533*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1534*d9f75844SAndroid Build Coastguard Worker StunRequest::OnSent();
1535*d9f75844SAndroid Build Coastguard Worker }
1536*d9f75844SAndroid Build Coastguard Worker
OnResponse(StunMessage * response)1537*d9f75844SAndroid Build Coastguard Worker void TurnRefreshRequest::OnResponse(StunMessage* response) {
1538*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1539*d9f75844SAndroid Build Coastguard Worker << ": TURN refresh requested successfully, id="
1540*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id())
1541*d9f75844SAndroid Build Coastguard Worker << ", code=0" // Makes logging easier to parse.
1542*d9f75844SAndroid Build Coastguard Worker ", rtt="
1543*d9f75844SAndroid Build Coastguard Worker << Elapsed();
1544*d9f75844SAndroid Build Coastguard Worker
1545*d9f75844SAndroid Build Coastguard Worker // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1546*d9f75844SAndroid Build Coastguard Worker const StunUInt32Attribute* lifetime_attr =
1547*d9f75844SAndroid Build Coastguard Worker response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1548*d9f75844SAndroid Build Coastguard Worker if (!lifetime_attr) {
1549*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1550*d9f75844SAndroid Build Coastguard Worker << ": Missing STUN_ATTR_TURN_LIFETIME attribute in "
1551*d9f75844SAndroid Build Coastguard Worker "refresh success response.";
1552*d9f75844SAndroid Build Coastguard Worker return;
1553*d9f75844SAndroid Build Coastguard Worker }
1554*d9f75844SAndroid Build Coastguard Worker
1555*d9f75844SAndroid Build Coastguard Worker if (lifetime_attr->value() > 0) {
1556*d9f75844SAndroid Build Coastguard Worker // Schedule a refresh based on the returned lifetime value.
1557*d9f75844SAndroid Build Coastguard Worker port_->ScheduleRefresh(lifetime_attr->value());
1558*d9f75844SAndroid Build Coastguard Worker } else {
1559*d9f75844SAndroid Build Coastguard Worker // If we scheduled a refresh with lifetime 0, we're releasing this
1560*d9f75844SAndroid Build Coastguard Worker // allocation; see TurnPort::Release.
1561*d9f75844SAndroid Build Coastguard Worker TurnPort* port = port_;
1562*d9f75844SAndroid Build Coastguard Worker port->thread()->PostTask(
1563*d9f75844SAndroid Build Coastguard Worker SafeTask(port->task_safety_.flag(), [port] { port->Close(); }));
1564*d9f75844SAndroid Build Coastguard Worker }
1565*d9f75844SAndroid Build Coastguard Worker
1566*d9f75844SAndroid Build Coastguard Worker if (port_->callbacks_for_test_) {
1567*d9f75844SAndroid Build Coastguard Worker port_->callbacks_for_test_->OnTurnRefreshResult(TURN_SUCCESS_RESULT_CODE);
1568*d9f75844SAndroid Build Coastguard Worker }
1569*d9f75844SAndroid Build Coastguard Worker }
1570*d9f75844SAndroid Build Coastguard Worker
OnErrorResponse(StunMessage * response)1571*d9f75844SAndroid Build Coastguard Worker void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
1572*d9f75844SAndroid Build Coastguard Worker int error_code = response->GetErrorCodeValue();
1573*d9f75844SAndroid Build Coastguard Worker
1574*d9f75844SAndroid Build Coastguard Worker if (error_code == STUN_ERROR_STALE_NONCE) {
1575*d9f75844SAndroid Build Coastguard Worker if (port_->UpdateNonce(response)) {
1576*d9f75844SAndroid Build Coastguard Worker // Send RefreshRequest immediately.
1577*d9f75844SAndroid Build Coastguard Worker port_->SendRequest(new TurnRefreshRequest(port_), 0);
1578*d9f75844SAndroid Build Coastguard Worker }
1579*d9f75844SAndroid Build Coastguard Worker } else {
1580*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1581*d9f75844SAndroid Build Coastguard Worker << ": Received TURN refresh error response, id="
1582*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id()) << ", code=" << error_code
1583*d9f75844SAndroid Build Coastguard Worker << ", rtt=" << Elapsed();
1584*d9f75844SAndroid Build Coastguard Worker port_->OnRefreshError();
1585*d9f75844SAndroid Build Coastguard Worker if (port_->callbacks_for_test_) {
1586*d9f75844SAndroid Build Coastguard Worker port_->callbacks_for_test_->OnTurnRefreshResult(error_code);
1587*d9f75844SAndroid Build Coastguard Worker }
1588*d9f75844SAndroid Build Coastguard Worker }
1589*d9f75844SAndroid Build Coastguard Worker }
1590*d9f75844SAndroid Build Coastguard Worker
OnTimeout()1591*d9f75844SAndroid Build Coastguard Worker void TurnRefreshRequest::OnTimeout() {
1592*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString() << ": TURN refresh timeout "
1593*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1594*d9f75844SAndroid Build Coastguard Worker port_->OnRefreshError();
1595*d9f75844SAndroid Build Coastguard Worker }
1596*d9f75844SAndroid Build Coastguard Worker
TurnCreatePermissionRequest(TurnPort * port,TurnEntry * entry,const rtc::SocketAddress & ext_addr)1597*d9f75844SAndroid Build Coastguard Worker TurnCreatePermissionRequest::TurnCreatePermissionRequest(
1598*d9f75844SAndroid Build Coastguard Worker TurnPort* port,
1599*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry,
1600*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& ext_addr)
1601*d9f75844SAndroid Build Coastguard Worker : StunRequest(
1602*d9f75844SAndroid Build Coastguard Worker port->request_manager(),
1603*d9f75844SAndroid Build Coastguard Worker std::make_unique<TurnMessage>(TURN_CREATE_PERMISSION_REQUEST)),
1604*d9f75844SAndroid Build Coastguard Worker port_(port),
1605*d9f75844SAndroid Build Coastguard Worker entry_(entry),
1606*d9f75844SAndroid Build Coastguard Worker ext_addr_(ext_addr) {
1607*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(entry_);
1608*d9f75844SAndroid Build Coastguard Worker entry_->destroyed_callback_list_.AddReceiver(this, [this](TurnEntry* entry) {
1609*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(entry_ == entry);
1610*d9f75844SAndroid Build Coastguard Worker entry_ = nullptr;
1611*d9f75844SAndroid Build Coastguard Worker });
1612*d9f75844SAndroid Build Coastguard Worker StunMessage* message = mutable_msg();
1613*d9f75844SAndroid Build Coastguard Worker // Create the request as indicated in RFC5766, Section 9.1.
1614*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(message->type(), TURN_CREATE_PERMISSION_REQUEST);
1615*d9f75844SAndroid Build Coastguard Worker message->AddAttribute(std::make_unique<StunXorAddressAttribute>(
1616*d9f75844SAndroid Build Coastguard Worker STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
1617*d9f75844SAndroid Build Coastguard Worker port_->AddRequestAuthInfo(message);
1618*d9f75844SAndroid Build Coastguard Worker port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message);
1619*d9f75844SAndroid Build Coastguard Worker }
1620*d9f75844SAndroid Build Coastguard Worker
~TurnCreatePermissionRequest()1621*d9f75844SAndroid Build Coastguard Worker TurnCreatePermissionRequest::~TurnCreatePermissionRequest() {
1622*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1623*d9f75844SAndroid Build Coastguard Worker entry_->destroyed_callback_list_.RemoveReceivers(this);
1624*d9f75844SAndroid Build Coastguard Worker }
1625*d9f75844SAndroid Build Coastguard Worker }
1626*d9f75844SAndroid Build Coastguard Worker
OnSent()1627*d9f75844SAndroid Build Coastguard Worker void TurnCreatePermissionRequest::OnSent() {
1628*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1629*d9f75844SAndroid Build Coastguard Worker << ": TURN create permission request sent, id="
1630*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1631*d9f75844SAndroid Build Coastguard Worker StunRequest::OnSent();
1632*d9f75844SAndroid Build Coastguard Worker }
1633*d9f75844SAndroid Build Coastguard Worker
OnResponse(StunMessage * response)1634*d9f75844SAndroid Build Coastguard Worker void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
1635*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1636*d9f75844SAndroid Build Coastguard Worker << ": TURN permission requested successfully, id="
1637*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id())
1638*d9f75844SAndroid Build Coastguard Worker << ", code=0" // Makes logging easier to parse.
1639*d9f75844SAndroid Build Coastguard Worker ", rtt="
1640*d9f75844SAndroid Build Coastguard Worker << Elapsed();
1641*d9f75844SAndroid Build Coastguard Worker
1642*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1643*d9f75844SAndroid Build Coastguard Worker entry_->OnCreatePermissionSuccess();
1644*d9f75844SAndroid Build Coastguard Worker }
1645*d9f75844SAndroid Build Coastguard Worker }
1646*d9f75844SAndroid Build Coastguard Worker
OnErrorResponse(StunMessage * response)1647*d9f75844SAndroid Build Coastguard Worker void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
1648*d9f75844SAndroid Build Coastguard Worker int error_code = response->GetErrorCodeValue();
1649*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1650*d9f75844SAndroid Build Coastguard Worker << ": Received TURN create permission error response, id="
1651*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id()) << ", code=" << error_code
1652*d9f75844SAndroid Build Coastguard Worker << ", rtt=" << Elapsed();
1653*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1654*d9f75844SAndroid Build Coastguard Worker entry_->OnCreatePermissionError(response, error_code);
1655*d9f75844SAndroid Build Coastguard Worker }
1656*d9f75844SAndroid Build Coastguard Worker }
1657*d9f75844SAndroid Build Coastguard Worker
OnTimeout()1658*d9f75844SAndroid Build Coastguard Worker void TurnCreatePermissionRequest::OnTimeout() {
1659*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1660*d9f75844SAndroid Build Coastguard Worker << ": TURN create permission timeout "
1661*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1662*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1663*d9f75844SAndroid Build Coastguard Worker entry_->OnCreatePermissionTimeout();
1664*d9f75844SAndroid Build Coastguard Worker }
1665*d9f75844SAndroid Build Coastguard Worker }
1666*d9f75844SAndroid Build Coastguard Worker
TurnChannelBindRequest(TurnPort * port,TurnEntry * entry,int channel_id,const rtc::SocketAddress & ext_addr)1667*d9f75844SAndroid Build Coastguard Worker TurnChannelBindRequest::TurnChannelBindRequest(
1668*d9f75844SAndroid Build Coastguard Worker TurnPort* port,
1669*d9f75844SAndroid Build Coastguard Worker TurnEntry* entry,
1670*d9f75844SAndroid Build Coastguard Worker int channel_id,
1671*d9f75844SAndroid Build Coastguard Worker const rtc::SocketAddress& ext_addr)
1672*d9f75844SAndroid Build Coastguard Worker : StunRequest(port->request_manager(),
1673*d9f75844SAndroid Build Coastguard Worker std::make_unique<TurnMessage>(TURN_CHANNEL_BIND_REQUEST)),
1674*d9f75844SAndroid Build Coastguard Worker port_(port),
1675*d9f75844SAndroid Build Coastguard Worker entry_(entry),
1676*d9f75844SAndroid Build Coastguard Worker channel_id_(channel_id),
1677*d9f75844SAndroid Build Coastguard Worker ext_addr_(ext_addr) {
1678*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(entry_);
1679*d9f75844SAndroid Build Coastguard Worker entry_->destroyed_callback_list_.AddReceiver(this, [this](TurnEntry* entry) {
1680*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(entry_ == entry);
1681*d9f75844SAndroid Build Coastguard Worker entry_ = nullptr;
1682*d9f75844SAndroid Build Coastguard Worker });
1683*d9f75844SAndroid Build Coastguard Worker StunMessage* message = mutable_msg();
1684*d9f75844SAndroid Build Coastguard Worker // Create the request as indicated in RFC5766, Section 11.1.
1685*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(message->type(), TURN_CHANNEL_BIND_REQUEST);
1686*d9f75844SAndroid Build Coastguard Worker message->AddAttribute(std::make_unique<StunUInt32Attribute>(
1687*d9f75844SAndroid Build Coastguard Worker STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16));
1688*d9f75844SAndroid Build Coastguard Worker message->AddAttribute(std::make_unique<StunXorAddressAttribute>(
1689*d9f75844SAndroid Build Coastguard Worker STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
1690*d9f75844SAndroid Build Coastguard Worker port_->AddRequestAuthInfo(message);
1691*d9f75844SAndroid Build Coastguard Worker port_->TurnCustomizerMaybeModifyOutgoingStunMessage(message);
1692*d9f75844SAndroid Build Coastguard Worker }
1693*d9f75844SAndroid Build Coastguard Worker
~TurnChannelBindRequest()1694*d9f75844SAndroid Build Coastguard Worker TurnChannelBindRequest::~TurnChannelBindRequest() {
1695*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1696*d9f75844SAndroid Build Coastguard Worker entry_->destroyed_callback_list_.RemoveReceivers(this);
1697*d9f75844SAndroid Build Coastguard Worker }
1698*d9f75844SAndroid Build Coastguard Worker }
1699*d9f75844SAndroid Build Coastguard Worker
OnSent()1700*d9f75844SAndroid Build Coastguard Worker void TurnChannelBindRequest::OnSent() {
1701*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1702*d9f75844SAndroid Build Coastguard Worker << ": TURN channel bind request sent, id="
1703*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1704*d9f75844SAndroid Build Coastguard Worker StunRequest::OnSent();
1705*d9f75844SAndroid Build Coastguard Worker }
1706*d9f75844SAndroid Build Coastguard Worker
OnResponse(StunMessage * response)1707*d9f75844SAndroid Build Coastguard Worker void TurnChannelBindRequest::OnResponse(StunMessage* response) {
1708*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1709*d9f75844SAndroid Build Coastguard Worker << ": TURN channel bind requested successfully, id="
1710*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id())
1711*d9f75844SAndroid Build Coastguard Worker << ", code=0" // Makes logging easier to parse.
1712*d9f75844SAndroid Build Coastguard Worker ", rtt="
1713*d9f75844SAndroid Build Coastguard Worker << Elapsed();
1714*d9f75844SAndroid Build Coastguard Worker
1715*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1716*d9f75844SAndroid Build Coastguard Worker entry_->OnChannelBindSuccess();
1717*d9f75844SAndroid Build Coastguard Worker // Refresh the channel binding just under the permission timeout
1718*d9f75844SAndroid Build Coastguard Worker // threshold. The channel binding has a longer lifetime, but
1719*d9f75844SAndroid Build Coastguard Worker // this is the easiest way to keep both the channel and the
1720*d9f75844SAndroid Build Coastguard Worker // permission from expiring.
1721*d9f75844SAndroid Build Coastguard Worker TimeDelta delay = kTurnPermissionTimeout - TimeDelta::Minutes(1);
1722*d9f75844SAndroid Build Coastguard Worker entry_->SendChannelBindRequest(delay.ms());
1723*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString() << ": Scheduled channel bind in "
1724*d9f75844SAndroid Build Coastguard Worker << delay.ms() << "ms.";
1725*d9f75844SAndroid Build Coastguard Worker }
1726*d9f75844SAndroid Build Coastguard Worker }
1727*d9f75844SAndroid Build Coastguard Worker
OnErrorResponse(StunMessage * response)1728*d9f75844SAndroid Build Coastguard Worker void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
1729*d9f75844SAndroid Build Coastguard Worker int error_code = response->GetErrorCodeValue();
1730*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString()
1731*d9f75844SAndroid Build Coastguard Worker << ": Received TURN channel bind error response, id="
1732*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id()) << ", code=" << error_code
1733*d9f75844SAndroid Build Coastguard Worker << ", rtt=" << Elapsed();
1734*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1735*d9f75844SAndroid Build Coastguard Worker entry_->OnChannelBindError(response, error_code);
1736*d9f75844SAndroid Build Coastguard Worker }
1737*d9f75844SAndroid Build Coastguard Worker }
1738*d9f75844SAndroid Build Coastguard Worker
OnTimeout()1739*d9f75844SAndroid Build Coastguard Worker void TurnChannelBindRequest::OnTimeout() {
1740*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << port_->ToString() << ": TURN channel bind timeout "
1741*d9f75844SAndroid Build Coastguard Worker << rtc::hex_encode(id());
1742*d9f75844SAndroid Build Coastguard Worker if (entry_) {
1743*d9f75844SAndroid Build Coastguard Worker entry_->OnChannelBindTimeout();
1744*d9f75844SAndroid Build Coastguard Worker }
1745*d9f75844SAndroid Build Coastguard Worker }
1746*d9f75844SAndroid Build Coastguard Worker
TurnEntry(TurnPort * port,Connection * conn,int channel_id)1747*d9f75844SAndroid Build Coastguard Worker TurnEntry::TurnEntry(TurnPort* port, Connection* conn, int channel_id)
1748*d9f75844SAndroid Build Coastguard Worker : port_(port),
1749*d9f75844SAndroid Build Coastguard Worker channel_id_(channel_id),
1750*d9f75844SAndroid Build Coastguard Worker ext_addr_(conn->remote_candidate().address()),
1751*d9f75844SAndroid Build Coastguard Worker state_(STATE_UNBOUND),
1752*d9f75844SAndroid Build Coastguard Worker connections_({conn}) {
1753*d9f75844SAndroid Build Coastguard Worker // Creating permission for `ext_addr_`.
1754*d9f75844SAndroid Build Coastguard Worker SendCreatePermissionRequest(0);
1755*d9f75844SAndroid Build Coastguard Worker }
1756*d9f75844SAndroid Build Coastguard Worker
~TurnEntry()1757*d9f75844SAndroid Build Coastguard Worker TurnEntry::~TurnEntry() {
1758*d9f75844SAndroid Build Coastguard Worker destroyed_callback_list_.Send(this);
1759*d9f75844SAndroid Build Coastguard Worker }
1760*d9f75844SAndroid Build Coastguard Worker
TrackConnection(Connection * conn)1761*d9f75844SAndroid Build Coastguard Worker void TurnEntry::TrackConnection(Connection* conn) {
1762*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(absl::c_find(connections_, conn) == connections_.end());
1763*d9f75844SAndroid Build Coastguard Worker if (connections_.empty()) {
1764*d9f75844SAndroid Build Coastguard Worker task_safety_.reset();
1765*d9f75844SAndroid Build Coastguard Worker }
1766*d9f75844SAndroid Build Coastguard Worker connections_.push_back(conn);
1767*d9f75844SAndroid Build Coastguard Worker }
1768*d9f75844SAndroid Build Coastguard Worker
UntrackConnection(Connection * conn)1769*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> TurnEntry::UntrackConnection(
1770*d9f75844SAndroid Build Coastguard Worker Connection* conn) {
1771*d9f75844SAndroid Build Coastguard Worker connections_.erase(absl::c_find(connections_, conn));
1772*d9f75844SAndroid Build Coastguard Worker return connections_.empty() ? task_safety_.flag() : nullptr;
1773*d9f75844SAndroid Build Coastguard Worker }
1774*d9f75844SAndroid Build Coastguard Worker
SendCreatePermissionRequest(int delay)1775*d9f75844SAndroid Build Coastguard Worker void TurnEntry::SendCreatePermissionRequest(int delay) {
1776*d9f75844SAndroid Build Coastguard Worker port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
1777*d9f75844SAndroid Build Coastguard Worker delay);
1778*d9f75844SAndroid Build Coastguard Worker }
1779*d9f75844SAndroid Build Coastguard Worker
SendChannelBindRequest(int delay)1780*d9f75844SAndroid Build Coastguard Worker void TurnEntry::SendChannelBindRequest(int delay) {
1781*d9f75844SAndroid Build Coastguard Worker port_->SendRequest(
1782*d9f75844SAndroid Build Coastguard Worker new TurnChannelBindRequest(port_, this, channel_id_, ext_addr_), delay);
1783*d9f75844SAndroid Build Coastguard Worker }
1784*d9f75844SAndroid Build Coastguard Worker
Send(const void * data,size_t size,bool payload,const rtc::PacketOptions & options)1785*d9f75844SAndroid Build Coastguard Worker int TurnEntry::Send(const void* data,
1786*d9f75844SAndroid Build Coastguard Worker size_t size,
1787*d9f75844SAndroid Build Coastguard Worker bool payload,
1788*d9f75844SAndroid Build Coastguard Worker const rtc::PacketOptions& options) {
1789*d9f75844SAndroid Build Coastguard Worker rtc::ByteBufferWriter buf;
1790*d9f75844SAndroid Build Coastguard Worker if (state_ != STATE_BOUND ||
1791*d9f75844SAndroid Build Coastguard Worker !port_->TurnCustomizerAllowChannelData(data, size, payload)) {
1792*d9f75844SAndroid Build Coastguard Worker // If we haven't bound the channel yet, we have to use a Send Indication.
1793*d9f75844SAndroid Build Coastguard Worker // The turn_customizer_ can also make us use Send Indication.
1794*d9f75844SAndroid Build Coastguard Worker TurnMessage msg(TURN_SEND_INDICATION);
1795*d9f75844SAndroid Build Coastguard Worker msg.AddAttribute(std::make_unique<StunXorAddressAttribute>(
1796*d9f75844SAndroid Build Coastguard Worker STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
1797*d9f75844SAndroid Build Coastguard Worker msg.AddAttribute(
1798*d9f75844SAndroid Build Coastguard Worker std::make_unique<StunByteStringAttribute>(STUN_ATTR_DATA, data, size));
1799*d9f75844SAndroid Build Coastguard Worker
1800*d9f75844SAndroid Build Coastguard Worker port_->TurnCustomizerMaybeModifyOutgoingStunMessage(&msg);
1801*d9f75844SAndroid Build Coastguard Worker
1802*d9f75844SAndroid Build Coastguard Worker const bool success = msg.Write(&buf);
1803*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(success);
1804*d9f75844SAndroid Build Coastguard Worker
1805*d9f75844SAndroid Build Coastguard Worker // If we're sending real data, request a channel bind that we can use later.
1806*d9f75844SAndroid Build Coastguard Worker if (state_ == STATE_UNBOUND && payload) {
1807*d9f75844SAndroid Build Coastguard Worker SendChannelBindRequest(0);
1808*d9f75844SAndroid Build Coastguard Worker state_ = STATE_BINDING;
1809*d9f75844SAndroid Build Coastguard Worker }
1810*d9f75844SAndroid Build Coastguard Worker } else {
1811*d9f75844SAndroid Build Coastguard Worker // If the channel is bound, we can send the data as a Channel Message.
1812*d9f75844SAndroid Build Coastguard Worker buf.WriteUInt16(channel_id_);
1813*d9f75844SAndroid Build Coastguard Worker buf.WriteUInt16(static_cast<uint16_t>(size));
1814*d9f75844SAndroid Build Coastguard Worker buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1815*d9f75844SAndroid Build Coastguard Worker }
1816*d9f75844SAndroid Build Coastguard Worker rtc::PacketOptions modified_options(options);
1817*d9f75844SAndroid Build Coastguard Worker modified_options.info_signaled_after_sent.turn_overhead_bytes =
1818*d9f75844SAndroid Build Coastguard Worker buf.Length() - size;
1819*d9f75844SAndroid Build Coastguard Worker return port_->Send(buf.Data(), buf.Length(), modified_options);
1820*d9f75844SAndroid Build Coastguard Worker }
1821*d9f75844SAndroid Build Coastguard Worker
OnCreatePermissionSuccess()1822*d9f75844SAndroid Build Coastguard Worker void TurnEntry::OnCreatePermissionSuccess() {
1823*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString() << ": Create permission for "
1824*d9f75844SAndroid Build Coastguard Worker << ext_addr_.ToSensitiveString() << " succeeded";
1825*d9f75844SAndroid Build Coastguard Worker if (port_->callbacks_for_test_) {
1826*d9f75844SAndroid Build Coastguard Worker port_->callbacks_for_test_->OnTurnCreatePermissionResult(
1827*d9f75844SAndroid Build Coastguard Worker TURN_SUCCESS_RESULT_CODE);
1828*d9f75844SAndroid Build Coastguard Worker }
1829*d9f75844SAndroid Build Coastguard Worker
1830*d9f75844SAndroid Build Coastguard Worker // If `state_` is STATE_BOUND, the permission will be refreshed
1831*d9f75844SAndroid Build Coastguard Worker // by ChannelBindRequest.
1832*d9f75844SAndroid Build Coastguard Worker if (state_ != STATE_BOUND) {
1833*d9f75844SAndroid Build Coastguard Worker // Refresh the permission request about 1 minute before the permission
1834*d9f75844SAndroid Build Coastguard Worker // times out.
1835*d9f75844SAndroid Build Coastguard Worker TimeDelta delay = kTurnPermissionTimeout - TimeDelta::Minutes(1);
1836*d9f75844SAndroid Build Coastguard Worker SendCreatePermissionRequest(delay.ms());
1837*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString()
1838*d9f75844SAndroid Build Coastguard Worker << ": Scheduled create-permission-request in "
1839*d9f75844SAndroid Build Coastguard Worker << delay.ms() << "ms.";
1840*d9f75844SAndroid Build Coastguard Worker }
1841*d9f75844SAndroid Build Coastguard Worker }
1842*d9f75844SAndroid Build Coastguard Worker
OnCreatePermissionError(StunMessage * response,int code)1843*d9f75844SAndroid Build Coastguard Worker void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
1844*d9f75844SAndroid Build Coastguard Worker if (code == STUN_ERROR_STALE_NONCE) {
1845*d9f75844SAndroid Build Coastguard Worker if (port_->UpdateNonce(response)) {
1846*d9f75844SAndroid Build Coastguard Worker SendCreatePermissionRequest(0);
1847*d9f75844SAndroid Build Coastguard Worker }
1848*d9f75844SAndroid Build Coastguard Worker } else {
1849*d9f75844SAndroid Build Coastguard Worker bool found = port_->FailAndPruneConnection(ext_addr_);
1850*d9f75844SAndroid Build Coastguard Worker if (found) {
1851*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Received TURN CreatePermission error response, "
1852*d9f75844SAndroid Build Coastguard Worker "code="
1853*d9f75844SAndroid Build Coastguard Worker << code << "; pruned connection.";
1854*d9f75844SAndroid Build Coastguard Worker }
1855*d9f75844SAndroid Build Coastguard Worker }
1856*d9f75844SAndroid Build Coastguard Worker if (port_->callbacks_for_test_) {
1857*d9f75844SAndroid Build Coastguard Worker port_->callbacks_for_test_->OnTurnCreatePermissionResult(code);
1858*d9f75844SAndroid Build Coastguard Worker }
1859*d9f75844SAndroid Build Coastguard Worker }
1860*d9f75844SAndroid Build Coastguard Worker
OnCreatePermissionTimeout()1861*d9f75844SAndroid Build Coastguard Worker void TurnEntry::OnCreatePermissionTimeout() {
1862*d9f75844SAndroid Build Coastguard Worker port_->FailAndPruneConnection(ext_addr_);
1863*d9f75844SAndroid Build Coastguard Worker }
1864*d9f75844SAndroid Build Coastguard Worker
OnChannelBindSuccess()1865*d9f75844SAndroid Build Coastguard Worker void TurnEntry::OnChannelBindSuccess() {
1866*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << port_->ToString() << ": Successful channel bind for "
1867*d9f75844SAndroid Build Coastguard Worker << ext_addr_.ToSensitiveString();
1868*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(state_ == STATE_BINDING || state_ == STATE_BOUND);
1869*d9f75844SAndroid Build Coastguard Worker state_ = STATE_BOUND;
1870*d9f75844SAndroid Build Coastguard Worker }
1871*d9f75844SAndroid Build Coastguard Worker
OnChannelBindError(StunMessage * response,int code)1872*d9f75844SAndroid Build Coastguard Worker void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
1873*d9f75844SAndroid Build Coastguard Worker // If the channel bind fails due to errors other than STATE_NONCE,
1874*d9f75844SAndroid Build Coastguard Worker // we will fail and prune the connection and rely on ICE restart to
1875*d9f75844SAndroid Build Coastguard Worker // re-establish a new connection if needed.
1876*d9f75844SAndroid Build Coastguard Worker if (code == STUN_ERROR_STALE_NONCE) {
1877*d9f75844SAndroid Build Coastguard Worker if (port_->UpdateNonce(response)) {
1878*d9f75844SAndroid Build Coastguard Worker // Send channel bind request with fresh nonce.
1879*d9f75844SAndroid Build Coastguard Worker SendChannelBindRequest(0);
1880*d9f75844SAndroid Build Coastguard Worker }
1881*d9f75844SAndroid Build Coastguard Worker } else {
1882*d9f75844SAndroid Build Coastguard Worker state_ = STATE_UNBOUND;
1883*d9f75844SAndroid Build Coastguard Worker port_->FailAndPruneConnection(ext_addr_);
1884*d9f75844SAndroid Build Coastguard Worker }
1885*d9f75844SAndroid Build Coastguard Worker }
OnChannelBindTimeout()1886*d9f75844SAndroid Build Coastguard Worker void TurnEntry::OnChannelBindTimeout() {
1887*d9f75844SAndroid Build Coastguard Worker state_ = STATE_UNBOUND;
1888*d9f75844SAndroid Build Coastguard Worker port_->FailAndPruneConnection(ext_addr_);
1889*d9f75844SAndroid Build Coastguard Worker }
1890*d9f75844SAndroid Build Coastguard Worker } // namespace cricket
1891