blob: 71a0311d2a714031d45a94ebdb0edee71c61ac61 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/p2p/base/turnport.h"
12
deadbeef5c3c1042017-08-04 15:01:57 -070013#include <algorithm>
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000014#include <functional>
15
zsteinf42cc9d2017-03-27 16:17:19 -070016#include "webrtc/p2p/base/common.h"
17#include "webrtc/p2p/base/stun.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020018#include "webrtc/rtc_base/asyncpacketsocket.h"
19#include "webrtc/rtc_base/byteorder.h"
20#include "webrtc/rtc_base/checks.h"
21#include "webrtc/rtc_base/logging.h"
22#include "webrtc/rtc_base/nethelpers.h"
23#include "webrtc/rtc_base/ptr_util.h"
24#include "webrtc/rtc_base/socketaddress.h"
25#include "webrtc/rtc_base/stringencode.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000026
27namespace cricket {
28
29// TODO(juberti): Move to stun.h when relay messages have been renamed.
30static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
31
32// TODO(juberti): Extract to turnmessage.h
33static const int TURN_DEFAULT_PORT = 3478;
34static const int TURN_CHANNEL_NUMBER_START = 0x4000;
35static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
36
37static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
38
39// Retry at most twice (i.e. three different ALLOCATE requests) on
40// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
41static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
42
Honghai Zhangf67c5482015-12-11 15:16:54 -080043static const int TURN_SUCCESS_RESULT_CODE = 0;
44
Peter Boström0c4e06b2015-10-07 12:23:21 +020045inline bool IsTurnChannelData(uint16_t msg_type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000046 return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
47}
48
hnsl277b2502016-12-13 05:17:23 -080049static int GetRelayPreference(cricket::ProtocolType proto) {
50 switch (proto) {
51 case cricket::PROTO_TCP:
52 return ICE_TYPE_PREFERENCE_RELAY_TCP;
53 case cricket::PROTO_TLS:
54 return ICE_TYPE_PREFERENCE_RELAY_TLS;
55 default:
56 RTC_DCHECK(proto == PROTO_UDP);
57 return ICE_TYPE_PREFERENCE_RELAY_UDP;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000058 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059}
60
61class TurnAllocateRequest : public StunRequest {
62 public:
63 explicit TurnAllocateRequest(TurnPort* port);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070064 void Prepare(StunMessage* request) override;
65 void OnSent() override;
66 void OnResponse(StunMessage* response) override;
67 void OnErrorResponse(StunMessage* response) override;
68 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000069
70 private:
71 // Handles authentication challenge from the server.
72 void OnAuthChallenge(StunMessage* response, int code);
73 void OnTryAlternate(StunMessage* response, int code);
74 void OnUnknownAttribute(StunMessage* response);
75
76 TurnPort* port_;
77};
78
79class TurnRefreshRequest : public StunRequest {
80 public:
81 explicit TurnRefreshRequest(TurnPort* port);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070082 void Prepare(StunMessage* request) override;
83 void OnSent() override;
84 void OnResponse(StunMessage* response) override;
85 void OnErrorResponse(StunMessage* response) override;
86 void OnTimeout() override;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000087 void set_lifetime(int lifetime) { lifetime_ = lifetime; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000088
89 private:
90 TurnPort* port_;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000091 int lifetime_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000092};
93
94class TurnCreatePermissionRequest : public StunRequest,
95 public sigslot::has_slots<> {
96 public:
97 TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
98 const rtc::SocketAddress& ext_addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070099 void Prepare(StunMessage* request) override;
100 void OnSent() override;
101 void OnResponse(StunMessage* response) override;
102 void OnErrorResponse(StunMessage* response) override;
103 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000104
105 private:
106 void OnEntryDestroyed(TurnEntry* entry);
107
108 TurnPort* port_;
109 TurnEntry* entry_;
110 rtc::SocketAddress ext_addr_;
111};
112
113class TurnChannelBindRequest : public StunRequest,
114 public sigslot::has_slots<> {
115 public:
116 TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
117 const rtc::SocketAddress& ext_addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700118 void Prepare(StunMessage* request) override;
119 void OnSent() override;
120 void OnResponse(StunMessage* response) override;
121 void OnErrorResponse(StunMessage* response) override;
122 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000123
124 private:
125 void OnEntryDestroyed(TurnEntry* entry);
126
127 TurnPort* port_;
128 TurnEntry* entry_;
129 int channel_id_;
130 rtc::SocketAddress ext_addr_;
131};
132
133// Manages a "connection" to a remote destination. We will attempt to bring up
134// a channel for this remote destination to reduce the overhead of sending data.
135class TurnEntry : public sigslot::has_slots<> {
136 public:
137 enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
138 TurnEntry(TurnPort* port, int channel_id,
139 const rtc::SocketAddress& ext_addr);
140
141 TurnPort* port() { return port_; }
142
143 int channel_id() const { return channel_id_; }
Honghai Zhangf67c5482015-12-11 15:16:54 -0800144 // For testing only.
145 void set_channel_id(int channel_id) { channel_id_ = channel_id; }
146
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000147 const rtc::SocketAddress& address() const { return ext_addr_; }
148 BindState state() const { return state_; }
149
honghaiz34b11eb2016-03-16 08:55:44 -0700150 int64_t destruction_timestamp() { return destruction_timestamp_; }
151 void set_destruction_timestamp(int64_t destruction_timestamp) {
honghaiz32f39962015-11-17 11:36:31 -0800152 destruction_timestamp_ = destruction_timestamp;
153 }
154
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155 // Helper methods to send permission and channel bind requests.
Honghai Zhang85975432015-11-12 11:07:12 -0800156 void SendCreatePermissionRequest(int delay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157 void SendChannelBindRequest(int delay);
158 // Sends a packet to the given destination address.
159 // This will wrap the packet in STUN if necessary.
160 int Send(const void* data, size_t size, bool payload,
161 const rtc::PacketOptions& options);
162
163 void OnCreatePermissionSuccess();
164 void OnCreatePermissionError(StunMessage* response, int code);
Honghai Zhangf67c5482015-12-11 15:16:54 -0800165 void OnCreatePermissionTimeout();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 void OnChannelBindSuccess();
167 void OnChannelBindError(StunMessage* response, int code);
Honghai Zhangf67c5482015-12-11 15:16:54 -0800168 void OnChannelBindTimeout();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000169 // Signal sent when TurnEntry is destroyed.
170 sigslot::signal1<TurnEntry*> SignalDestroyed;
171
172 private:
173 TurnPort* port_;
174 int channel_id_;
175 rtc::SocketAddress ext_addr_;
176 BindState state_;
honghaiz32f39962015-11-17 11:36:31 -0800177 // A non-zero value indicates that this entry is scheduled to be destroyed.
178 // It is also used as an ID of the event scheduling. When the destruction
179 // event actually fires, the TurnEntry will be destroyed only if the
180 // timestamp here matches the one in the firing event.
honghaiz34b11eb2016-03-16 08:55:44 -0700181 int64_t destruction_timestamp_ = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000182};
183
184TurnPort::TurnPort(rtc::Thread* thread,
185 rtc::PacketSocketFactory* factory,
186 rtc::Network* network,
187 rtc::AsyncPacketSocket* socket,
188 const std::string& username,
189 const std::string& password,
190 const ProtocolAddress& server_address,
191 const RelayCredentials& credentials,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000192 int server_priority,
maxmorine9ef9072017-08-29 04:49:00 -0700193 const std::string& origin)
194 : Port(thread,
195 RELAY_PORT_TYPE,
196 factory,
197 network,
198 username,
199 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000200 server_address_(server_address),
201 credentials_(credentials),
202 socket_(socket),
203 resolver_(NULL),
204 error_(0),
205 request_manager_(thread),
206 next_channel_number_(TURN_CHANNEL_NUMBER_START),
honghaizb19eba32015-08-03 10:23:31 -0700207 state_(STATE_CONNECTING),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000208 server_priority_(server_priority),
maxmorine9ef9072017-08-29 04:49:00 -0700209 allocate_mismatch_retries_(0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000210 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000211 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000212}
213
214TurnPort::TurnPort(rtc::Thread* thread,
215 rtc::PacketSocketFactory* factory,
216 rtc::Network* network,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200217 uint16_t min_port,
218 uint16_t max_port,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000219 const std::string& username,
220 const std::string& password,
221 const ProtocolAddress& server_address,
222 const RelayCredentials& credentials,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000223 int server_priority,
Diogo Real1dca9d52017-08-29 12:18:32 -0700224 const std::string& origin,
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700225 const std::vector<std::string>& tls_alpn_protocols,
226 const std::vector<std::string>& tls_elliptic_curves)
honghaizb19eba32015-08-03 10:23:31 -0700227 : Port(thread,
228 RELAY_PORT_TYPE,
229 factory,
230 network,
honghaizb19eba32015-08-03 10:23:31 -0700231 min_port,
232 max_port,
233 username,
234 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235 server_address_(server_address),
Diogo Real1dca9d52017-08-29 12:18:32 -0700236 tls_alpn_protocols_(tls_alpn_protocols),
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700237 tls_elliptic_curves_(tls_elliptic_curves),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000238 credentials_(credentials),
239 socket_(NULL),
240 resolver_(NULL),
241 error_(0),
242 request_manager_(thread),
243 next_channel_number_(TURN_CHANNEL_NUMBER_START),
honghaizb19eba32015-08-03 10:23:31 -0700244 state_(STATE_CONNECTING),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245 server_priority_(server_priority),
maxmorine9ef9072017-08-29 04:49:00 -0700246 allocate_mismatch_retries_(0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000247 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000248 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000249}
250
251TurnPort::~TurnPort() {
252 // TODO(juberti): Should this even be necessary?
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000253
254 // release the allocation by sending a refresh with
255 // lifetime 0.
honghaizb19eba32015-08-03 10:23:31 -0700256 if (ready()) {
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000257 TurnRefreshRequest bye(this);
258 bye.set_lifetime(0);
259 SendRequest(&bye, 0);
260 }
261
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000262 while (!entries_.empty()) {
honghaiz32f39962015-11-17 11:36:31 -0800263 DestroyEntry(entries_.front());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000264 }
265 if (resolver_) {
266 resolver_->Destroy(false);
267 }
268 if (!SharedSocket()) {
269 delete socket_;
270 }
271}
272
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000273rtc::SocketAddress TurnPort::GetLocalAddress() const {
274 return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress();
275}
276
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000277void TurnPort::PrepareAddress() {
278 if (credentials_.username.empty() ||
279 credentials_.password.empty()) {
280 LOG(LS_ERROR) << "Allocation can't be started without setting the"
281 << " TURN server credentials for the user.";
282 OnAllocateError();
283 return;
284 }
285
286 if (!server_address_.address.port()) {
287 // We will set default TURN port, if no port is set in the address.
288 server_address_.address.SetPort(TURN_DEFAULT_PORT);
289 }
290
tfarina20a34612015-11-02 16:20:22 -0800291 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000292 ResolveTurnAddress(server_address_.address);
293 } else {
294 // If protocol family of server address doesn't match with local, return.
295 if (!IsCompatibleAddress(server_address_.address)) {
honghaizb19eba32015-08-03 10:23:31 -0700296 LOG(LS_ERROR) << "IP address family does not match: "
297 << "server: " << server_address_.address.family()
deadbeef5c3c1042017-08-04 15:01:57 -0700298 << " local: " << Network()->GetBestIP().family();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000299 OnAllocateError();
300 return;
301 }
302
303 // Insert the current address to prevent redirection pingpong.
304 attempted_server_addresses_.insert(server_address_.address);
305
306 LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
307 << ProtoToString(server_address_.proto) << " @ "
308 << server_address_.address.ToSensitiveString();
309 if (!CreateTurnClientSocket()) {
honghaizb19eba32015-08-03 10:23:31 -0700310 LOG(LS_ERROR) << "Failed to create TURN client socket";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000311 OnAllocateError();
honghaizb19eba32015-08-03 10:23:31 -0700312 return;
313 }
314 if (server_address_.proto == PROTO_UDP) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000315 // If its UDP, send AllocateRequest now.
316 // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
317 SendRequest(new TurnAllocateRequest(this), 0);
318 }
319 }
320}
321
322bool TurnPort::CreateTurnClientSocket() {
nisseede5da42017-01-12 05:15:36 -0800323 RTC_DCHECK(!socket_ || SharedSocket());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000324
325 if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
326 socket_ = socket_factory()->CreateUdpSocket(
deadbeef5c3c1042017-08-04 15:01:57 -0700327 rtc::SocketAddress(Network()->GetBestIP(), 0), min_port(), max_port());
hnsl277b2502016-12-13 05:17:23 -0800328 } else if (server_address_.proto == PROTO_TCP ||
329 server_address_.proto == PROTO_TLS) {
nisseede5da42017-01-12 05:15:36 -0800330 RTC_DCHECK(!SharedSocket());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000331 int opts = rtc::PacketSocketFactory::OPT_STUN;
hnsl277b2502016-12-13 05:17:23 -0800332
333 // Apply server address TLS and insecure bits to options.
334 if (server_address_.proto == PROTO_TLS) {
hnsl04833622017-01-09 08:35:45 -0800335 if (tls_cert_policy_ ==
336 TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) {
337 opts |= rtc::PacketSocketFactory::OPT_TLS_INSECURE;
338 } else {
339 opts |= rtc::PacketSocketFactory::OPT_TLS;
340 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000341 }
hnsl04833622017-01-09 08:35:45 -0800342
Diogo Real1dca9d52017-08-29 12:18:32 -0700343 rtc::PacketSocketTcpOptions tcp_options;
344 tcp_options.opts = opts;
345 tcp_options.tls_alpn_protocols = tls_alpn_protocols_;
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700346 tcp_options.tls_elliptic_curves = tls_elliptic_curves_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000347 socket_ = socket_factory()->CreateClientTcpSocket(
deadbeef5c3c1042017-08-04 15:01:57 -0700348 rtc::SocketAddress(Network()->GetBestIP(), 0), server_address_.address,
Diogo Real1dca9d52017-08-29 12:18:32 -0700349 proxy(), user_agent(), tcp_options);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000350 }
351
352 if (!socket_) {
353 error_ = SOCKET_ERROR;
354 return false;
355 }
356
357 // Apply options if any.
358 for (SocketOptionsMap::iterator iter = socket_options_.begin();
359 iter != socket_options_.end(); ++iter) {
360 socket_->SetOption(iter->first, iter->second);
361 }
362
363 if (!SharedSocket()) {
364 // If socket is shared, AllocationSequence will receive the packet.
365 socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
366 }
367
368 socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
369
Stefan Holmer55674ff2016-01-14 15:49:16 +0100370 socket_->SignalSentPacket.connect(this, &TurnPort::OnSentPacket);
371
honghaizb19eba32015-08-03 10:23:31 -0700372 // TCP port is ready to send stun requests after the socket is connected,
373 // while UDP port is ready to do so once the socket is created.
hnsl277b2502016-12-13 05:17:23 -0800374 if (server_address_.proto == PROTO_TCP ||
375 server_address_.proto == PROTO_TLS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000376 socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
377 socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
honghaizb19eba32015-08-03 10:23:31 -0700378 } else {
379 state_ = STATE_CONNECTED;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000380 }
381 return true;
382}
383
384void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
deadbeefbbe2a372017-05-03 09:48:35 -0700385 // This slot should only be invoked if we're using a connection-oriented
386 // protocol.
387 RTC_DCHECK(server_address_.proto == PROTO_TCP ||
388 server_address_.proto == PROTO_TLS);
389
deadbeef5c3c1042017-08-04 15:01:57 -0700390 // Do not use this port if the socket bound to an address not associated with
391 // the desired network interface. This is seen in Chrome, where TCP sockets
392 // cannot be given a binding address, and the platform is expected to pick
393 // the correct local address.
394 //
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700395 // However, there are two situations in which we allow the bound address to
deadbeef5c3c1042017-08-04 15:01:57 -0700396 // not be one of the addresses of the requested interface:
397 // 1. The bound address is the loopback address. This happens when a proxy
398 // forces TCP to bind to only the localhost address (see issue 3927).
399 // 2. The bound address is the "any address". This happens when
400 // multiple_routes is disabled (see issue 4780).
401 //
402 // Note that, aside from minor differences in log statements, this logic is
403 // identical to that in TcpPort.
404 const rtc::SocketAddress& socket_address = socket->GetLocalAddress();
405 const std::vector<rtc::InterfaceAddress>& desired_addresses =
406 Network()->GetIPs();
407 if (std::find(desired_addresses.begin(), desired_addresses.end(),
408 socket_address.ipaddr()) == desired_addresses.end()) {
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000409 if (socket->GetLocalAddress().IsLoopbackIP()) {
deadbeef5c3c1042017-08-04 15:01:57 -0700410 LOG(LS_WARNING) << "Socket is bound to the address:"
411 << socket_address.ipaddr().ToString()
412 << ", rather then an address associated with network:"
413 << Network()->ToString()
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000414 << ". Still allowing it since it's localhost.";
deadbeef5c3c1042017-08-04 15:01:57 -0700415 } else if (IPIsAny(Network()->GetBestIP())) {
416 LOG(LS_WARNING) << "Socket is bound to the address:"
417 << socket_address.ipaddr().ToString()
418 << ", rather then an address associated with network:"
419 << Network()->ToString()
420 << ". Still allowing it since it's the 'any' address"
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700421 << ", possibly caused by multiple_routes being disabled.";
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000422 } else {
deadbeef5c3c1042017-08-04 15:01:57 -0700423 LOG(LS_WARNING) << "Socket is bound to the address:"
424 << socket_address.ipaddr().ToString()
425 << ", rather then an address associated with network:"
426 << Network()->ToString() << ". Discarding TURN port.";
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000427 OnAllocateError();
428 return;
429 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000430 }
431
honghaizb19eba32015-08-03 10:23:31 -0700432 state_ = STATE_CONNECTED; // It is ready to send stun requests.
tfarina20a34612015-11-02 16:20:22 -0800433 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000434 server_address_.address = socket_->GetRemoteAddress();
435 }
436
437 LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
438 << " using tcp.";
439 SendRequest(new TurnAllocateRequest(this), 0);
440}
441
442void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
443 LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
nisseede5da42017-01-12 05:15:36 -0800444 RTC_DCHECK(socket == socket_);
honghaiz6b9ab922016-01-05 09:06:12 -0800445 Close();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000446}
447
448void TurnPort::OnAllocateMismatch() {
449 if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
450 LOG_J(LS_WARNING, this) << "Giving up on the port after "
451 << allocate_mismatch_retries_
452 << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
453 OnAllocateError();
454 return;
455 }
456
457 LOG_J(LS_INFO, this) << "Allocating a new socket after "
458 << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
459 << allocate_mismatch_retries_ + 1;
460 if (SharedSocket()) {
461 ResetSharedSocket();
462 } else {
463 delete socket_;
464 }
465 socket_ = NULL;
466
honghaizc463e202016-02-01 15:19:08 -0800467 ResetNonce();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000468 PrepareAddress();
469 ++allocate_mismatch_retries_;
470}
471
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700472Connection* TurnPort::CreateConnection(const Candidate& remote_candidate,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000473 CandidateOrigin origin) {
474 // TURN-UDP can only connect to UDP candidates.
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700475 if (!SupportsProtocol(remote_candidate.protocol())) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 return NULL;
477 }
478
honghaiz079a7a12016-06-22 16:26:29 -0700479 if (state_ == STATE_DISCONNECTED || state_ == STATE_RECEIVEONLY) {
honghaizb19eba32015-08-03 10:23:31 -0700480 return NULL;
481 }
482
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483 // A TURN port will have two candiates, STUN and TURN. STUN may not
484 // present in all cases. If present stun candidate will be added first
485 // and TURN candidate later.
486 for (size_t index = 0; index < Candidates().size(); ++index) {
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700487 const Candidate& local_candidate = Candidates()[index];
488 if (local_candidate.type() == RELAY_PORT_TYPE &&
489 local_candidate.address().family() ==
490 remote_candidate.address().family()) {
491 // Create an entry, if needed, so we can get our permissions set up
492 // correctly.
493 CreateOrRefreshEntry(remote_candidate.address());
494 ProxyConnection* conn =
495 new ProxyConnection(this, index, remote_candidate);
honghaiz36f50e82016-06-01 15:57:03 -0700496 AddOrReplaceConnection(conn);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000497 return conn;
498 }
499 }
500 return NULL;
501}
502
honghaiz079a7a12016-06-22 16:26:29 -0700503bool TurnPort::FailAndPruneConnection(const rtc::SocketAddress& address) {
Honghai Zhangf67c5482015-12-11 15:16:54 -0800504 Connection* conn = GetConnection(address);
505 if (conn != nullptr) {
honghaiz079a7a12016-06-22 16:26:29 -0700506 conn->FailAndPrune();
Honghai Zhangf67c5482015-12-11 15:16:54 -0800507 return true;
508 }
509 return false;
510}
511
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000512int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
513 if (!socket_) {
514 // If socket is not created yet, these options will be applied during socket
515 // creation.
516 socket_options_[opt] = value;
517 return 0;
518 }
519 return socket_->SetOption(opt, value);
520}
521
522int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
523 if (!socket_) {
524 SocketOptionsMap::const_iterator it = socket_options_.find(opt);
525 if (it == socket_options_.end()) {
526 return -1;
527 }
528 *value = it->second;
529 return 0;
530 }
531
532 return socket_->GetOption(opt, value);
533}
534
535int TurnPort::GetError() {
536 return error_;
537}
538
539int TurnPort::SendTo(const void* data, size_t size,
540 const rtc::SocketAddress& addr,
541 const rtc::PacketOptions& options,
542 bool payload) {
543 // Try to find an entry for this specific address; we should have one.
544 TurnEntry* entry = FindEntry(addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000545 if (!entry) {
honghaizb19eba32015-08-03 10:23:31 -0700546 LOG(LS_ERROR) << "Did not find the TurnEntry for address " << addr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000547 return 0;
548 }
549
honghaizb19eba32015-08-03 10:23:31 -0700550 if (!ready()) {
skvladc309e0e2016-07-28 17:15:20 -0700551 error_ = ENOTCONN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000552 return SOCKET_ERROR;
553 }
554
555 // Send the actual contents to the server using the usual mechanism.
556 int sent = entry->Send(data, size, payload, options);
557 if (sent <= 0) {
558 return SOCKET_ERROR;
559 }
560
561 // The caller of the function is expecting the number of user data bytes,
562 // rather than the size of the packet.
563 return static_cast<int>(size);
564}
565
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700566bool TurnPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
567 const char* data, size_t size,
568 const rtc::SocketAddress& remote_addr,
569 const rtc::PacketTime& packet_time) {
570 if (socket != socket_) {
571 // The packet was received on a shared socket after we've allocated a new
572 // socket for this TURN port.
573 return false;
574 }
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000575
576 // This is to guard against a STUN response from previous server after
577 // alternative server redirection. TODO(guoweis): add a unit test for this
578 // race condition.
579 if (remote_addr != server_address_.address) {
580 LOG_J(LS_WARNING, this) << "Discarding TURN message from unknown address:"
581 << remote_addr.ToString()
582 << ", server_address_:"
583 << server_address_.address.ToString();
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700584 return false;
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000585 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000586
587 // The message must be at least the size of a channel header.
588 if (size < TURN_CHANNEL_HEADER_SIZE) {
589 LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700590 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591 }
592
honghaiz9dfed792016-01-29 13:22:31 -0800593 if (state_ == STATE_DISCONNECTED) {
594 LOG_J(LS_WARNING, this)
honghaiz079a7a12016-06-22 16:26:29 -0700595 << "Received TURN message while the TURN port is disconnected";
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700596 return false;
honghaiz9dfed792016-01-29 13:22:31 -0800597 }
598
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000599 // Check the message type, to see if is a Channel Data message.
600 // The message will either be channel data, a TURN data indication, or
601 // a response to a previous request.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200602 uint16_t msg_type = rtc::GetBE16(data);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000603 if (IsTurnChannelData(msg_type)) {
604 HandleChannelData(msg_type, data, size, packet_time);
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700605 return true;
jiayl@webrtc.org511f8a82014-12-03 02:17:07 +0000606
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000607 }
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700608
609 if (msg_type == TURN_DATA_INDICATION) {
610 HandleDataIndication(data, size, packet_time);
611 return true;
612 }
613
614 if (SharedSocket() && (msg_type == STUN_BINDING_RESPONSE ||
615 msg_type == STUN_BINDING_ERROR_RESPONSE)) {
616 LOG_J(LS_VERBOSE, this) <<
617 "Ignoring STUN binding response message on shared socket.";
618 return false;
619 }
620
621 // This must be a response for one of our requests.
622 // Check success responses, but not errors, for MESSAGE-INTEGRITY.
623 if (IsStunSuccessResponseType(msg_type) &&
624 !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
625 LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
626 << "message integrity, msg_type=" << msg_type;
627 return true;
628 }
629 request_manager_.CheckResponse(data, size);
630
631 return true;
632}
633
634void TurnPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
635 const char* data,
636 size_t size,
637 const rtc::SocketAddress& remote_addr,
638 const rtc::PacketTime& packet_time) {
639 HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000640}
641
Stefan Holmer55674ff2016-01-14 15:49:16 +0100642void TurnPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
643 const rtc::SentPacket& sent_packet) {
644 PortInterface::SignalSentPacket(sent_packet);
645}
646
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000647void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
honghaizb19eba32015-08-03 10:23:31 -0700648 if (ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000649 Port::OnReadyToSend();
650 }
651}
652
653
654// Update current server address port with the alternate server address port.
655bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
656 // Check if we have seen this address before and reject if we did.
657 AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
658 if (iter != attempted_server_addresses_.end()) {
659 LOG_J(LS_WARNING, this) << "Redirection to ["
660 << address.ToSensitiveString()
661 << "] ignored, allocation failed.";
662 return false;
663 }
664
665 // If protocol family of server address doesn't match with local, return.
666 if (!IsCompatibleAddress(address)) {
667 LOG(LS_WARNING) << "Server IP address family does not match with "
668 << "local host address family type";
669 return false;
670 }
671
deadbeeffb70b452016-10-24 13:15:59 -0700672 // Block redirects to a loopback address.
673 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=649118
674 if (address.IsLoopbackIP()) {
675 LOG_J(LS_WARNING, this)
676 << "Blocking attempted redirect to loopback address.";
677 return false;
678 }
679
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000680 LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
681 << server_address_.address.ToSensitiveString()
682 << "] to TURN server ["
683 << address.ToSensitiveString()
684 << "]";
hnsl277b2502016-12-13 05:17:23 -0800685 server_address_ = ProtocolAddress(address, server_address_.proto);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000686
687 // Insert the current address to prevent redirection pingpong.
688 attempted_server_addresses_.insert(server_address_.address);
689 return true;
690}
691
692void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
693 if (resolver_)
694 return;
695
Honghai Zhang0f490a52015-12-07 12:06:20 -0800696 LOG_J(LS_INFO, this) << "Starting TURN host lookup for "
697 << address.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000698 resolver_ = socket_factory()->CreateAsyncResolver();
699 resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
700 resolver_->Start(address);
701}
702
703void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
nisseede5da42017-01-12 05:15:36 -0800704 RTC_DCHECK(resolver == resolver_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000705 // If DNS resolve is failed when trying to connect to the server using TCP,
706 // one of the reason could be due to DNS queries blocked by firewall.
707 // In such cases we will try to connect to the server with hostname, assuming
708 // socket layer will resolve the hostname through a HTTP proxy (if any).
Steve Anton786de702017-08-17 15:15:46 -0700709 if (resolver_->GetError() != 0 && (server_address_.proto == PROTO_TCP ||
710 server_address_.proto == PROTO_TLS)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000711 if (!CreateTurnClientSocket()) {
712 OnAllocateError();
713 }
714 return;
715 }
716
717 // Copy the original server address in |resolved_address|. For TLS based
718 // sockets we need hostname along with resolved address.
719 rtc::SocketAddress resolved_address = server_address_.address;
maxmorine9ef9072017-08-29 04:49:00 -0700720 if (resolver_->GetError() != 0 ||
721 !resolver_->GetResolvedAddress(Network()->GetBestIP().family(),
722 &resolved_address)) {
723 LOG_J(LS_WARNING, this) << "TURN host lookup received error "
724 << resolver_->GetError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000725 error_ = resolver_->GetError();
726 OnAllocateError();
727 return;
728 }
729 // Signal needs both resolved and unresolved address. After signal is sent
730 // we can copy resolved address back into |server_address_|.
731 SignalResolvedServerAddress(this, server_address_.address,
732 resolved_address);
733 server_address_.address = resolved_address;
734 PrepareAddress();
735}
736
737void TurnPort::OnSendStunPacket(const void* data, size_t size,
738 StunRequest* request) {
nisseede5da42017-01-12 05:15:36 -0800739 RTC_DCHECK(connected());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740 rtc::PacketOptions options(DefaultDscpValue());
741 if (Send(data, size, options) < 0) {
742 LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
743 << socket_->GetError();
744 }
745}
746
747void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
748 // STUN Port will discover STUN candidate, as it's supplied with first TURN
749 // server address.
750 // Why not using this address? - P2PTransportChannel will start creating
751 // connections after first candidate, which means it could start creating the
752 // connections before TURN candidate added. For that to handle, we need to
753 // supply STUN candidate from this port to UDPPort, and TurnPort should have
754 // handle to UDPPort to pass back the address.
755}
756
757void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
758 const rtc::SocketAddress& stun_address) {
honghaizb19eba32015-08-03 10:23:31 -0700759 state_ = STATE_READY;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000760
761 rtc::SocketAddress related_address = stun_address;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000762
763 // For relayed candidate, Base is the candidate itself.
764 AddAddress(address, // Candidate address.
765 address, // Base address.
766 related_address, // Related address.
767 UDP_PROTOCOL_NAME,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700768 ProtoToString(server_address_.proto), // The first hop protocol.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000769 "", // TCP canddiate type, empty for turn candidates.
hnsl277b2502016-12-13 05:17:23 -0800770 RELAY_PORT_TYPE, GetRelayPreference(server_address_.proto),
zhihuang26d99c22017-02-13 12:47:27 -0800771 server_priority_, ReconstructedServerUrl(), true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000772}
773
774void TurnPort::OnAllocateError() {
775 // We will send SignalPortError asynchronously as this can be sent during
776 // port initialization. This way it will not be blocking other port
777 // creation.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700778 thread()->Post(RTC_FROM_HERE, this, MSG_ALLOCATE_ERROR);
Honghai Zhangf67c5482015-12-11 15:16:54 -0800779}
780
honghaiz079a7a12016-06-22 16:26:29 -0700781void TurnPort::OnRefreshError() {
782 // Need to clear the requests asynchronously because otherwise, the refresh
honghaiz6b9ab922016-01-05 09:06:12 -0800783 // request may be deleted twice: once at the end of the message processing
honghaiz079a7a12016-06-22 16:26:29 -0700784 // and the other in HandleRefreshError().
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700785 thread()->Post(RTC_FROM_HERE, this, MSG_REFRESH_ERROR);
honghaiz6b9ab922016-01-05 09:06:12 -0800786}
787
honghaiz079a7a12016-06-22 16:26:29 -0700788void TurnPort::HandleRefreshError() {
789 request_manager_.Clear();
790 state_ = STATE_RECEIVEONLY;
791 // Fail and prune all connections; stop sending data.
792 for (auto kv : connections()) {
793 kv.second->FailAndPrune();
794 }
795}
796
Honghai Zhangf67c5482015-12-11 15:16:54 -0800797void TurnPort::Close() {
honghaiz6b9ab922016-01-05 09:06:12 -0800798 if (!ready()) {
799 OnAllocateError();
800 }
801 request_manager_.Clear();
Honghai Zhangf67c5482015-12-11 15:16:54 -0800802 // Stop the port from creating new connections.
803 state_ = STATE_DISCONNECTED;
804 // Delete all existing connections; stop sending data.
805 for (auto kv : connections()) {
806 kv.second->Destroy();
807 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000808}
809
810void TurnPort::OnMessage(rtc::Message* message) {
Honghai Zhangf67c5482015-12-11 15:16:54 -0800811 switch (message->message_id) {
812 case MSG_ALLOCATE_ERROR:
813 SignalPortError(this);
814 break;
815 case MSG_ALLOCATE_MISMATCH:
816 OnAllocateMismatch();
817 break;
honghaiz6b9ab922016-01-05 09:06:12 -0800818 case MSG_REFRESH_ERROR:
honghaiz079a7a12016-06-22 16:26:29 -0700819 HandleRefreshError();
honghaiz6b9ab922016-01-05 09:06:12 -0800820 break;
Honghai Zhangf67c5482015-12-11 15:16:54 -0800821 case MSG_TRY_ALTERNATE_SERVER:
822 if (server_address().proto == PROTO_UDP) {
823 // Send another allocate request to alternate server, with the received
824 // realm and nonce values.
825 SendRequest(new TurnAllocateRequest(this), 0);
826 } else {
827 // Since it's TCP, we have to delete the connected socket and reconnect
828 // with the alternate server. PrepareAddress will send stun binding once
829 // the new socket is connected.
Steve Anton786de702017-08-17 15:15:46 -0700830 RTC_DCHECK(server_address().proto == PROTO_TCP ||
831 server_address().proto == PROTO_TLS);
nisseede5da42017-01-12 05:15:36 -0800832 RTC_DCHECK(!SharedSocket());
Honghai Zhangf67c5482015-12-11 15:16:54 -0800833 delete socket_;
834 socket_ = NULL;
835 PrepareAddress();
836 }
837 break;
838 default:
839 Port::OnMessage(message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000840 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000841}
842
843void TurnPort::OnAllocateRequestTimeout() {
844 OnAllocateError();
845}
846
847void TurnPort::HandleDataIndication(const char* data, size_t size,
848 const rtc::PacketTime& packet_time) {
849 // Read in the message, and process according to RFC5766, Section 10.4.
jbauchf1f87202016-03-30 06:43:37 -0700850 rtc::ByteBufferReader buf(data, size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000851 TurnMessage msg;
852 if (!msg.Read(&buf)) {
853 LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
854 return;
855 }
856
857 // Check mandatory attributes.
858 const StunAddressAttribute* addr_attr =
859 msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
860 if (!addr_attr) {
861 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
862 << "in data indication.";
863 return;
864 }
865
866 const StunByteStringAttribute* data_attr =
867 msg.GetByteString(STUN_ATTR_DATA);
868 if (!data_attr) {
869 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
870 << "data indication.";
871 return;
872 }
873
Taylor Brandstetteref184702016-06-23 17:35:47 -0700874 // Log a warning if the data didn't come from an address that we think we have
875 // a permission for.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000876 rtc::SocketAddress ext_addr(addr_attr->GetAddress());
877 if (!HasPermission(ext_addr.ipaddr())) {
Taylor Brandstetteref184702016-06-23 17:35:47 -0700878 LOG_J(LS_WARNING, this)
879 << "Received TURN data indication with unknown "
880 << "peer address, addr=" << ext_addr.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000881 }
882
883 DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
884 PROTO_UDP, packet_time);
885}
886
887void TurnPort::HandleChannelData(int channel_id, const char* data,
888 size_t size,
889 const rtc::PacketTime& packet_time) {
890 // Read the message, and process according to RFC5766, Section 11.6.
891 // 0 1 2 3
892 // 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
893 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
894 // | Channel Number | Length |
895 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
896 // | |
897 // / Application Data /
898 // / /
899 // | |
900 // | +-------------------------------+
901 // | |
902 // +-------------------------------+
903
904 // Extract header fields from the message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200905 uint16_t len = rtc::GetBE16(data + 2);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000906 if (len > size - TURN_CHANNEL_HEADER_SIZE) {
907 LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
908 << "incorrect length, len=" << len;
909 return;
910 }
911 // Allowing messages larger than |len|, as ChannelData can be padded.
912
913 TurnEntry* entry = FindEntry(channel_id);
914 if (!entry) {
915 LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
916 << "channel, channel_id=" << channel_id;
917 return;
918 }
919
920 DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
921 PROTO_UDP, packet_time);
922}
923
924void TurnPort::DispatchPacket(const char* data, size_t size,
925 const rtc::SocketAddress& remote_addr,
926 ProtocolType proto, const rtc::PacketTime& packet_time) {
927 if (Connection* conn = GetConnection(remote_addr)) {
928 conn->OnReadPacket(data, size, packet_time);
929 } else {
930 Port::OnReadPacket(data, size, remote_addr, proto);
931 }
932}
933
934bool TurnPort::ScheduleRefresh(int lifetime) {
935 // Lifetime is in seconds; we schedule a refresh for one minute less.
936 if (lifetime < 2 * 60) {
937 LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
938 << "too short, lifetime=" << lifetime;
939 return false;
940 }
941
Peter Thatcherb32a5c42015-04-10 14:04:42 -0700942 int delay = (lifetime - 60) * 1000;
943 SendRequest(new TurnRefreshRequest(this), delay);
944 LOG_J(LS_INFO, this) << "Scheduled refresh in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000945 return true;
946}
947
948void TurnPort::SendRequest(StunRequest* req, int delay) {
949 request_manager_.SendDelayed(req, delay);
950}
951
952void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
953 // If we've gotten the necessary data from the server, add it to our request.
nissec16fa5e2017-02-07 07:18:43 -0800954 RTC_DCHECK(!hash_.empty());
zsteinf42cc9d2017-03-27 16:17:19 -0700955 msg->AddAttribute(rtc::MakeUnique<StunByteStringAttribute>(
nissecc99bc22017-02-02 01:31:30 -0800956 STUN_ATTR_USERNAME, credentials_.username));
zsteinf42cc9d2017-03-27 16:17:19 -0700957 msg->AddAttribute(
958 rtc::MakeUnique<StunByteStringAttribute>(STUN_ATTR_REALM, realm_));
959 msg->AddAttribute(
960 rtc::MakeUnique<StunByteStringAttribute>(STUN_ATTR_NONCE, nonce_));
nissec16fa5e2017-02-07 07:18:43 -0800961 const bool success = msg->AddMessageIntegrity(hash());
962 RTC_DCHECK(success);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000963}
964
965int TurnPort::Send(const void* data, size_t len,
966 const rtc::PacketOptions& options) {
967 return socket_->SendTo(data, len, server_address_.address, options);
968}
969
970void TurnPort::UpdateHash() {
nissec16fa5e2017-02-07 07:18:43 -0800971 const bool success = ComputeStunCredentialHash(credentials_.username, realm_,
972 credentials_.password, &hash_);
973 RTC_DCHECK(success);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000974}
975
976bool TurnPort::UpdateNonce(StunMessage* response) {
977 // When stale nonce error received, we should update
978 // hash and store realm and nonce.
979 // Check the mandatory attributes.
980 const StunByteStringAttribute* realm_attr =
981 response->GetByteString(STUN_ATTR_REALM);
982 if (!realm_attr) {
983 LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
984 << "stale nonce error response.";
985 return false;
986 }
987 set_realm(realm_attr->GetString());
988
989 const StunByteStringAttribute* nonce_attr =
990 response->GetByteString(STUN_ATTR_NONCE);
991 if (!nonce_attr) {
992 LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
993 << "stale nonce error response.";
994 return false;
995 }
996 set_nonce(nonce_attr->GetString());
997 return true;
998}
999
honghaizc463e202016-02-01 15:19:08 -08001000void TurnPort::ResetNonce() {
1001 hash_.clear();
1002 nonce_.clear();
1003 realm_.clear();
1004}
1005
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001006static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
1007 return e->address().ipaddr() == ipaddr;
1008}
1009bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
1010 return (std::find_if(entries_.begin(), entries_.end(),
1011 std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
1012}
1013
1014static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
1015 return e->address() == addr;
1016}
1017TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
1018 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
1019 std::bind2nd(std::ptr_fun(MatchesAddress), addr));
1020 return (it != entries_.end()) ? *it : NULL;
1021}
1022
1023static bool MatchesChannelId(TurnEntry* e, int id) {
1024 return e->channel_id() == id;
1025}
1026TurnEntry* TurnPort::FindEntry(int channel_id) const {
1027 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
1028 std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
1029 return (it != entries_.end()) ? *it : NULL;
1030}
1031
honghaizc3e0fe72015-12-02 16:43:25 -08001032bool TurnPort::EntryExists(TurnEntry* e) {
1033 auto it = std::find(entries_.begin(), entries_.end(), e);
1034 return it != entries_.end();
1035}
1036
honghaiz32f39962015-11-17 11:36:31 -08001037void TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) {
1038 TurnEntry* entry = FindEntry(addr);
1039 if (entry == nullptr) {
1040 entry = new TurnEntry(this, next_channel_number_++, addr);
1041 entries_.push_back(entry);
1042 } else {
1043 // The channel binding request for the entry will be refreshed automatically
1044 // until the entry is destroyed.
1045 CancelEntryDestruction(entry);
1046 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001047}
1048
honghaiz32f39962015-11-17 11:36:31 -08001049void TurnPort::DestroyEntry(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001050 RTC_DCHECK(entry != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001051 entry->SignalDestroyed(entry);
1052 entries_.remove(entry);
1053 delete entry;
1054}
1055
honghaiz34b11eb2016-03-16 08:55:44 -07001056void TurnPort::DestroyEntryIfNotCancelled(TurnEntry* entry, int64_t timestamp) {
honghaizc3e0fe72015-12-02 16:43:25 -08001057 if (!EntryExists(entry)) {
1058 return;
1059 }
honghaiz32f39962015-11-17 11:36:31 -08001060 bool cancelled = timestamp != entry->destruction_timestamp();
1061 if (!cancelled) {
1062 DestroyEntry(entry);
1063 }
1064}
1065
honghaiz36f50e82016-06-01 15:57:03 -07001066void TurnPort::HandleConnectionDestroyed(Connection* conn) {
honghaiz32f39962015-11-17 11:36:31 -08001067 // Schedule an event to destroy TurnEntry for the connection, which is
1068 // already destroyed.
1069 const rtc::SocketAddress& remote_address = conn->remote_candidate().address();
1070 TurnEntry* entry = FindEntry(remote_address);
nisseede5da42017-01-12 05:15:36 -08001071 RTC_DCHECK(entry != NULL);
honghaiz32f39962015-11-17 11:36:31 -08001072 ScheduleEntryDestruction(entry);
1073}
1074
1075void TurnPort::ScheduleEntryDestruction(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001076 RTC_DCHECK(entry->destruction_timestamp() == 0);
nisse1bffc1d2016-05-02 08:18:55 -07001077 int64_t timestamp = rtc::TimeMillis();
honghaiz32f39962015-11-17 11:36:31 -08001078 entry->set_destruction_timestamp(timestamp);
1079 invoker_.AsyncInvokeDelayed<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001080 RTC_FROM_HERE, thread(),
honghaiz32f39962015-11-17 11:36:31 -08001081 rtc::Bind(&TurnPort::DestroyEntryIfNotCancelled, this, entry, timestamp),
1082 TURN_PERMISSION_TIMEOUT);
1083}
1084
1085void TurnPort::CancelEntryDestruction(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001086 RTC_DCHECK(entry->destruction_timestamp() != 0);
honghaiz32f39962015-11-17 11:36:31 -08001087 entry->set_destruction_timestamp(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001088}
1089
Honghai Zhangf67c5482015-12-11 15:16:54 -08001090bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address,
1091 int channel_id) {
1092 TurnEntry* entry = FindEntry(address);
1093 if (!entry) {
1094 return false;
1095 }
1096 entry->set_channel_id(channel_id);
1097 return true;
1098}
1099
zhihuang26d99c22017-02-13 12:47:27 -08001100std::string TurnPort::ReconstructedServerUrl() {
1101 // draft-petithuguenin-behave-turn-uris-01
1102 // turnURI = scheme ":" turn-host [ ":" turn-port ]
1103 // [ "?transport=" transport ]
1104 // scheme = "turn" / "turns"
1105 // transport = "udp" / "tcp" / transport-ext
1106 // transport-ext = 1*unreserved
1107 // turn-host = IP-literal / IPv4address / reg-name
1108 // turn-port = *DIGIT
1109 std::string scheme = "turn";
1110 std::string transport = "tcp";
1111 switch (server_address_.proto) {
1112 case PROTO_SSLTCP:
1113 case PROTO_TLS:
1114 scheme = "turns";
1115 break;
1116 case PROTO_UDP:
1117 transport = "udp";
1118 break;
1119 case PROTO_TCP:
1120 break;
1121 }
1122 std::ostringstream url;
1123 url << scheme << ":" << server_address_.address.ipaddr().ToString() << ":"
1124 << server_address_.address.port() << "?transport=" << transport;
1125 return url.str();
1126}
1127
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001128TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
1129 : StunRequest(new TurnMessage()),
1130 port_(port) {
1131}
1132
1133void TurnAllocateRequest::Prepare(StunMessage* request) {
1134 // Create the request as indicated in RFC 5766, Section 6.1.
1135 request->SetType(TURN_ALLOCATE_REQUEST);
zsteinf42cc9d2017-03-27 16:17:19 -07001136 auto transport_attr =
1137 StunAttribute::CreateUInt32(STUN_ATTR_REQUESTED_TRANSPORT);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001138 transport_attr->SetValue(IPPROTO_UDP << 24);
zsteinf42cc9d2017-03-27 16:17:19 -07001139 request->AddAttribute(std::move(transport_attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001140 if (!port_->hash().empty()) {
1141 port_->AddRequestAuthInfo(request);
1142 }
1143}
1144
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001145void TurnAllocateRequest::OnSent() {
1146 LOG_J(LS_INFO, port_) << "TURN allocate request sent"
1147 << ", id=" << rtc::hex_encode(id());
1148 StunRequest::OnSent();
1149}
1150
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001151void TurnAllocateRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001152 LOG_J(LS_INFO, port_) << "TURN allocate requested successfully"
1153 << ", id=" << rtc::hex_encode(id())
1154 << ", code=0" // Makes logging easier to parse.
1155 << ", rtt=" << Elapsed();
1156
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001157 // Check mandatory attributes as indicated in RFC5766, Section 6.3.
1158 const StunAddressAttribute* mapped_attr =
1159 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1160 if (!mapped_attr) {
1161 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
1162 << "attribute in allocate success response";
1163 return;
1164 }
1165 // Using XOR-Mapped-Address for stun.
1166 port_->OnStunAddress(mapped_attr->GetAddress());
1167
1168 const StunAddressAttribute* relayed_attr =
1169 response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
1170 if (!relayed_attr) {
1171 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
1172 << "attribute in allocate success response";
1173 return;
1174 }
1175
1176 const StunUInt32Attribute* lifetime_attr =
1177 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1178 if (!lifetime_attr) {
1179 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1180 << "allocate success response";
1181 return;
1182 }
1183 // Notify the port the allocate succeeded, and schedule a refresh request.
1184 port_->OnAllocateSuccess(relayed_attr->GetAddress(),
1185 mapped_attr->GetAddress());
1186 port_->ScheduleRefresh(lifetime_attr->value());
1187}
1188
1189void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
1190 // Process error response according to RFC5766, Section 6.4.
deadbeef996fc6b2017-04-26 09:21:22 -07001191 int error_code = response->GetErrorCodeValue();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001192
1193 LOG_J(LS_INFO, port_) << "Received TURN allocate error response"
1194 << ", id=" << rtc::hex_encode(id())
deadbeef996fc6b2017-04-26 09:21:22 -07001195 << ", code=" << error_code << ", rtt=" << Elapsed();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001196
deadbeef996fc6b2017-04-26 09:21:22 -07001197 switch (error_code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001198 case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
deadbeef996fc6b2017-04-26 09:21:22 -07001199 OnAuthChallenge(response, error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001200 break;
1201 case STUN_ERROR_TRY_ALTERNATE:
deadbeef996fc6b2017-04-26 09:21:22 -07001202 OnTryAlternate(response, error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001203 break;
1204 case STUN_ERROR_ALLOCATION_MISMATCH:
1205 // We must handle this error async because trying to delete the socket in
1206 // OnErrorResponse will cause a deadlock on the socket.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001207 port_->thread()->Post(RTC_FROM_HERE, port_,
1208 TurnPort::MSG_ALLOCATE_MISMATCH);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001209 break;
1210 default:
deadbeef996fc6b2017-04-26 09:21:22 -07001211 LOG_J(LS_WARNING, port_)
1212 << "Received TURN allocate error response"
1213 << ", id=" << rtc::hex_encode(id()) << ", code=" << error_code
1214 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001215 port_->OnAllocateError();
1216 }
1217}
1218
1219void TurnAllocateRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001220 LOG_J(LS_WARNING, port_) << "TURN allocate request "
deadbeef8f33fb32017-03-09 15:54:22 -08001221 << rtc::hex_encode(id()) << " timeout";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001222 port_->OnAllocateRequestTimeout();
1223}
1224
1225void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
1226 // If we failed to authenticate even after we sent our credentials, fail hard.
1227 if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
1228 LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
1229 << "after challenge.";
1230 port_->OnAllocateError();
1231 return;
1232 }
1233
1234 // Check the mandatory attributes.
1235 const StunByteStringAttribute* realm_attr =
1236 response->GetByteString(STUN_ATTR_REALM);
1237 if (!realm_attr) {
1238 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
1239 << "allocate unauthorized response.";
1240 return;
1241 }
1242 port_->set_realm(realm_attr->GetString());
1243
1244 const StunByteStringAttribute* nonce_attr =
1245 response->GetByteString(STUN_ATTR_NONCE);
1246 if (!nonce_attr) {
1247 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
1248 << "allocate unauthorized response.";
1249 return;
1250 }
1251 port_->set_nonce(nonce_attr->GetString());
1252
1253 // Send another allocate request, with the received realm and nonce values.
1254 port_->SendRequest(new TurnAllocateRequest(port_), 0);
1255}
1256
1257void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001258
1259 // According to RFC 5389 section 11, there are use cases where
1260 // authentication of response is not possible, we're not validating
1261 // message integrity.
1262
1263 // Get the alternate server address attribute value.
1264 const StunAddressAttribute* alternate_server_attr =
1265 response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1266 if (!alternate_server_attr) {
1267 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
1268 << "attribute in try alternate error response";
1269 port_->OnAllocateError();
1270 return;
1271 }
1272 if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1273 port_->OnAllocateError();
1274 return;
1275 }
1276
1277 // Check the attributes.
1278 const StunByteStringAttribute* realm_attr =
1279 response->GetByteString(STUN_ATTR_REALM);
1280 if (realm_attr) {
1281 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
1282 << "try alternate error response.";
1283 port_->set_realm(realm_attr->GetString());
1284 }
1285
1286 const StunByteStringAttribute* nonce_attr =
1287 response->GetByteString(STUN_ATTR_NONCE);
1288 if (nonce_attr) {
1289 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
1290 << "try alternate error response.";
1291 port_->set_nonce(nonce_attr->GetString());
1292 }
1293
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +00001294 // For TCP, we can't close the original Tcp socket during handling a 300 as
1295 // we're still inside that socket's event handler. Doing so will cause
1296 // deadlock.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001297 port_->thread()->Post(RTC_FROM_HERE, port_,
1298 TurnPort::MSG_TRY_ALTERNATE_SERVER);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001299}
1300
1301TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
1302 : StunRequest(new TurnMessage()),
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001303 port_(port),
1304 lifetime_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001305}
1306
1307void TurnRefreshRequest::Prepare(StunMessage* request) {
1308 // Create the request as indicated in RFC 5766, Section 7.1.
1309 // No attributes need to be included.
1310 request->SetType(TURN_REFRESH_REQUEST);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001311 if (lifetime_ > -1) {
zsteinf42cc9d2017-03-27 16:17:19 -07001312 request->AddAttribute(
1313 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_LIFETIME, lifetime_));
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001314 }
1315
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001316 port_->AddRequestAuthInfo(request);
1317}
1318
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001319void TurnRefreshRequest::OnSent() {
1320 LOG_J(LS_INFO, port_) << "TURN refresh request sent"
1321 << ", id=" << rtc::hex_encode(id());
1322 StunRequest::OnSent();
1323}
1324
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001325void TurnRefreshRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001326 LOG_J(LS_INFO, port_) << "TURN refresh requested successfully"
1327 << ", id=" << rtc::hex_encode(id())
1328 << ", code=0" // Makes logging easier to parse.
1329 << ", rtt=" << Elapsed();
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001330
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001331 // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1332 const StunUInt32Attribute* lifetime_attr =
1333 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1334 if (!lifetime_attr) {
1335 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1336 << "refresh success response.";
1337 return;
1338 }
1339
1340 // Schedule a refresh based on the returned lifetime value.
1341 port_->ScheduleRefresh(lifetime_attr->value());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001342 port_->SignalTurnRefreshResult(port_, TURN_SUCCESS_RESULT_CODE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001343}
1344
1345void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
deadbeef996fc6b2017-04-26 09:21:22 -07001346 int error_code = response->GetErrorCodeValue();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001347
deadbeef996fc6b2017-04-26 09:21:22 -07001348 if (error_code == STUN_ERROR_STALE_NONCE) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001349 if (port_->UpdateNonce(response)) {
1350 // Send RefreshRequest immediately.
1351 port_->SendRequest(new TurnRefreshRequest(port_), 0);
1352 }
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001353 } else {
deadbeef996fc6b2017-04-26 09:21:22 -07001354 LOG_J(LS_WARNING, port_)
1355 << "Received TURN refresh error response"
1356 << ", id=" << rtc::hex_encode(id()) << ", code=" << error_code
1357 << ", rtt=" << Elapsed();
honghaiz079a7a12016-06-22 16:26:29 -07001358 port_->OnRefreshError();
deadbeef996fc6b2017-04-26 09:21:22 -07001359 port_->SignalTurnRefreshResult(port_, error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001360 }
1361}
1362
1363void TurnRefreshRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001364 LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id());
honghaiz079a7a12016-06-22 16:26:29 -07001365 port_->OnRefreshError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001366}
1367
1368TurnCreatePermissionRequest::TurnCreatePermissionRequest(
1369 TurnPort* port, TurnEntry* entry,
1370 const rtc::SocketAddress& ext_addr)
1371 : StunRequest(new TurnMessage()),
1372 port_(port),
1373 entry_(entry),
1374 ext_addr_(ext_addr) {
1375 entry_->SignalDestroyed.connect(
1376 this, &TurnCreatePermissionRequest::OnEntryDestroyed);
1377}
1378
1379void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
1380 // Create the request as indicated in RFC5766, Section 9.1.
1381 request->SetType(TURN_CREATE_PERMISSION_REQUEST);
zsteinf42cc9d2017-03-27 16:17:19 -07001382 request->AddAttribute(rtc::MakeUnique<StunXorAddressAttribute>(
nissecc99bc22017-02-02 01:31:30 -08001383 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001384 port_->AddRequestAuthInfo(request);
1385}
1386
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001387void TurnCreatePermissionRequest::OnSent() {
1388 LOG_J(LS_INFO, port_) << "TURN create permission request sent"
1389 << ", id=" << rtc::hex_encode(id());
1390 StunRequest::OnSent();
1391}
1392
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001393void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001394 LOG_J(LS_INFO, port_) << "TURN permission requested successfully"
1395 << ", id=" << rtc::hex_encode(id())
1396 << ", code=0" // Makes logging easier to parse.
1397 << ", rtt=" << Elapsed();
1398
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001399 if (entry_) {
1400 entry_->OnCreatePermissionSuccess();
1401 }
1402}
1403
1404void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
deadbeef996fc6b2017-04-26 09:21:22 -07001405 int error_code = response->GetErrorCodeValue();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001406 LOG_J(LS_WARNING, port_) << "Received TURN create permission error response"
1407 << ", id=" << rtc::hex_encode(id())
deadbeef996fc6b2017-04-26 09:21:22 -07001408 << ", code=" << error_code << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001409 if (entry_) {
deadbeef996fc6b2017-04-26 09:21:22 -07001410 entry_->OnCreatePermissionError(response, error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001411 }
1412}
1413
1414void TurnCreatePermissionRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001415 LOG_J(LS_WARNING, port_) << "TURN create permission timeout "
1416 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001417 if (entry_) {
1418 entry_->OnCreatePermissionTimeout();
1419 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001420}
1421
1422void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001423 RTC_DCHECK(entry_ == entry);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001424 entry_ = NULL;
1425}
1426
1427TurnChannelBindRequest::TurnChannelBindRequest(
1428 TurnPort* port, TurnEntry* entry,
1429 int channel_id, const rtc::SocketAddress& ext_addr)
1430 : StunRequest(new TurnMessage()),
1431 port_(port),
1432 entry_(entry),
1433 channel_id_(channel_id),
1434 ext_addr_(ext_addr) {
1435 entry_->SignalDestroyed.connect(
1436 this, &TurnChannelBindRequest::OnEntryDestroyed);
1437}
1438
1439void TurnChannelBindRequest::Prepare(StunMessage* request) {
1440 // Create the request as indicated in RFC5766, Section 11.1.
1441 request->SetType(TURN_CHANNEL_BIND_REQUEST);
zsteinf42cc9d2017-03-27 16:17:19 -07001442 request->AddAttribute(rtc::MakeUnique<StunUInt32Attribute>(
nissecc99bc22017-02-02 01:31:30 -08001443 STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16));
zsteinf42cc9d2017-03-27 16:17:19 -07001444 request->AddAttribute(rtc::MakeUnique<StunXorAddressAttribute>(
nissecc99bc22017-02-02 01:31:30 -08001445 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001446 port_->AddRequestAuthInfo(request);
1447}
1448
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001449void TurnChannelBindRequest::OnSent() {
1450 LOG_J(LS_INFO, port_) << "TURN channel bind request sent"
1451 << ", id=" << rtc::hex_encode(id());
1452 StunRequest::OnSent();
1453}
1454
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001455void TurnChannelBindRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001456 LOG_J(LS_INFO, port_) << "TURN channel bind requested successfully"
1457 << ", id=" << rtc::hex_encode(id())
1458 << ", code=0" // Makes logging easier to parse.
1459 << ", rtt=" << Elapsed();
1460
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001461 if (entry_) {
1462 entry_->OnChannelBindSuccess();
1463 // Refresh the channel binding just under the permission timeout
1464 // threshold. The channel binding has a longer lifetime, but
1465 // this is the easiest way to keep both the channel and the
1466 // permission from expiring.
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001467 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1468 entry_->SendChannelBindRequest(delay);
1469 LOG_J(LS_INFO, port_) << "Scheduled channel bind in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001470 }
1471}
1472
1473void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
deadbeef996fc6b2017-04-26 09:21:22 -07001474 int error_code = response->GetErrorCodeValue();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001475 LOG_J(LS_WARNING, port_) << "Received TURN channel bind error response"
1476 << ", id=" << rtc::hex_encode(id())
deadbeef996fc6b2017-04-26 09:21:22 -07001477 << ", code=" << error_code << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001478 if (entry_) {
deadbeef996fc6b2017-04-26 09:21:22 -07001479 entry_->OnChannelBindError(response, error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001480 }
1481}
1482
1483void TurnChannelBindRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001484 LOG_J(LS_WARNING, port_) << "TURN channel bind timeout "
1485 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001486 if (entry_) {
1487 entry_->OnChannelBindTimeout();
1488 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001489}
1490
1491void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001492 RTC_DCHECK(entry_ == entry);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001493 entry_ = NULL;
1494}
1495
1496TurnEntry::TurnEntry(TurnPort* port, int channel_id,
1497 const rtc::SocketAddress& ext_addr)
1498 : port_(port),
1499 channel_id_(channel_id),
1500 ext_addr_(ext_addr),
1501 state_(STATE_UNBOUND) {
1502 // Creating permission for |ext_addr_|.
Honghai Zhang85975432015-11-12 11:07:12 -08001503 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001504}
1505
Honghai Zhang85975432015-11-12 11:07:12 -08001506void TurnEntry::SendCreatePermissionRequest(int delay) {
1507 port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
1508 delay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001509}
1510
1511void TurnEntry::SendChannelBindRequest(int delay) {
1512 port_->SendRequest(new TurnChannelBindRequest(
1513 port_, this, channel_id_, ext_addr_), delay);
1514}
1515
1516int TurnEntry::Send(const void* data, size_t size, bool payload,
1517 const rtc::PacketOptions& options) {
jbauchf1f87202016-03-30 06:43:37 -07001518 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001519 if (state_ != STATE_BOUND) {
1520 // If we haven't bound the channel yet, we have to use a Send Indication.
1521 TurnMessage msg;
1522 msg.SetType(TURN_SEND_INDICATION);
1523 msg.SetTransactionID(
1524 rtc::CreateRandomString(kStunTransactionIdLength));
zsteinf42cc9d2017-03-27 16:17:19 -07001525 msg.AddAttribute(rtc::MakeUnique<StunXorAddressAttribute>(
nissecc99bc22017-02-02 01:31:30 -08001526 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
zsteinf42cc9d2017-03-27 16:17:19 -07001527 msg.AddAttribute(
1528 rtc::MakeUnique<StunByteStringAttribute>(STUN_ATTR_DATA, data, size));
nissec16fa5e2017-02-07 07:18:43 -08001529 const bool success = msg.Write(&buf);
1530 RTC_DCHECK(success);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001531
1532 // If we're sending real data, request a channel bind that we can use later.
1533 if (state_ == STATE_UNBOUND && payload) {
1534 SendChannelBindRequest(0);
1535 state_ = STATE_BINDING;
1536 }
1537 } else {
1538 // If the channel is bound, we can send the data as a Channel Message.
1539 buf.WriteUInt16(channel_id_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001540 buf.WriteUInt16(static_cast<uint16_t>(size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001541 buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1542 }
1543 return port_->Send(buf.Data(), buf.Length(), options);
1544}
1545
1546void TurnEntry::OnCreatePermissionSuccess() {
1547 LOG_J(LS_INFO, port_) << "Create permission for "
1548 << ext_addr_.ToSensitiveString()
1549 << " succeeded";
Honghai Zhangf67c5482015-12-11 15:16:54 -08001550 port_->SignalCreatePermissionResult(port_, ext_addr_,
1551 TURN_SUCCESS_RESULT_CODE);
Honghai Zhang85975432015-11-12 11:07:12 -08001552
1553 // If |state_| is STATE_BOUND, the permission will be refreshed
1554 // by ChannelBindRequest.
1555 if (state_ != STATE_BOUND) {
1556 // Refresh the permission request about 1 minute before the permission
1557 // times out.
1558 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1559 SendCreatePermissionRequest(delay);
1560 LOG_J(LS_INFO, port_) << "Scheduled create-permission-request in "
1561 << delay << "ms.";
1562 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001563}
1564
1565void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001566 if (code == STUN_ERROR_STALE_NONCE) {
1567 if (port_->UpdateNonce(response)) {
Honghai Zhang85975432015-11-12 11:07:12 -08001568 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001569 }
1570 } else {
honghaiz079a7a12016-06-22 16:26:29 -07001571 bool found = port_->FailAndPruneConnection(ext_addr_);
1572 if (found) {
1573 LOG(LS_ERROR) << "Received TURN CreatePermission error response, "
1574 << "code=" << code << "; pruned connection.";
1575 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001576 // Send signal with error code.
1577 port_->SignalCreatePermissionResult(port_, ext_addr_, code);
1578 }
1579}
1580
Honghai Zhangf67c5482015-12-11 15:16:54 -08001581void TurnEntry::OnCreatePermissionTimeout() {
honghaiz079a7a12016-06-22 16:26:29 -07001582 port_->FailAndPruneConnection(ext_addr_);
Honghai Zhangf67c5482015-12-11 15:16:54 -08001583}
1584
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001585void TurnEntry::OnChannelBindSuccess() {
1586 LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
1587 << " succeeded";
nisseede5da42017-01-12 05:15:36 -08001588 RTC_DCHECK(state_ == STATE_BINDING || state_ == STATE_BOUND);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001589 state_ = STATE_BOUND;
1590}
1591
1592void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
Honghai Zhangf67c5482015-12-11 15:16:54 -08001593 // If the channel bind fails due to errors other than STATE_NONCE,
honghaiz079a7a12016-06-22 16:26:29 -07001594 // we will fail and prune the connection and rely on ICE restart to
1595 // re-establish a new connection if needed.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001596 if (code == STUN_ERROR_STALE_NONCE) {
1597 if (port_->UpdateNonce(response)) {
1598 // Send channel bind request with fresh nonce.
1599 SendChannelBindRequest(0);
1600 }
Honghai Zhangf67c5482015-12-11 15:16:54 -08001601 } else {
1602 state_ = STATE_UNBOUND;
honghaiz079a7a12016-06-22 16:26:29 -07001603 port_->FailAndPruneConnection(ext_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001604 }
1605}
Honghai Zhangf67c5482015-12-11 15:16:54 -08001606void TurnEntry::OnChannelBindTimeout() {
1607 state_ = STATE_UNBOUND;
honghaiz079a7a12016-06-22 16:26:29 -07001608 port_->FailAndPruneConnection(ext_addr_);
Honghai Zhangf67c5482015-12-11 15:16:54 -08001609}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001610} // namespace cricket