blob: 9ecc75ea2867c01c7e73122fc74bceff97c3385d [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
13#include <functional>
14
15#include "webrtc/p2p/base/common.h"
16#include "webrtc/p2p/base/stun.h"
17#include "webrtc/base/asyncpacketsocket.h"
18#include "webrtc/base/byteorder.h"
nisseede5da42017-01-12 05:15:36 -080019#include "webrtc/base/checks.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000020#include "webrtc/base/logging.h"
21#include "webrtc/base/nethelpers.h"
22#include "webrtc/base/socketaddress.h"
23#include "webrtc/base/stringencode.h"
24
25namespace cricket {
26
27// TODO(juberti): Move to stun.h when relay messages have been renamed.
28static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
29
30// TODO(juberti): Extract to turnmessage.h
31static const int TURN_DEFAULT_PORT = 3478;
32static const int TURN_CHANNEL_NUMBER_START = 0x4000;
33static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
34
35static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
36
37// Retry at most twice (i.e. three different ALLOCATE requests) on
38// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
39static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
40
Honghai Zhangf67c5482015-12-11 15:16:54 -080041static const int TURN_SUCCESS_RESULT_CODE = 0;
42
Peter Boström0c4e06b2015-10-07 12:23:21 +020043inline bool IsTurnChannelData(uint16_t msg_type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000044 return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
45}
46
hnsl277b2502016-12-13 05:17:23 -080047static int GetRelayPreference(cricket::ProtocolType proto) {
48 switch (proto) {
49 case cricket::PROTO_TCP:
50 return ICE_TYPE_PREFERENCE_RELAY_TCP;
51 case cricket::PROTO_TLS:
52 return ICE_TYPE_PREFERENCE_RELAY_TLS;
53 default:
54 RTC_DCHECK(proto == PROTO_UDP);
55 return ICE_TYPE_PREFERENCE_RELAY_UDP;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000056 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000057}
58
59class TurnAllocateRequest : public StunRequest {
60 public:
61 explicit TurnAllocateRequest(TurnPort* port);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070062 void Prepare(StunMessage* request) override;
63 void OnSent() override;
64 void OnResponse(StunMessage* response) override;
65 void OnErrorResponse(StunMessage* response) override;
66 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000067
68 private:
69 // Handles authentication challenge from the server.
70 void OnAuthChallenge(StunMessage* response, int code);
71 void OnTryAlternate(StunMessage* response, int code);
72 void OnUnknownAttribute(StunMessage* response);
73
74 TurnPort* port_;
75};
76
77class TurnRefreshRequest : public StunRequest {
78 public:
79 explicit TurnRefreshRequest(TurnPort* port);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070080 void Prepare(StunMessage* request) override;
81 void OnSent() override;
82 void OnResponse(StunMessage* response) override;
83 void OnErrorResponse(StunMessage* response) override;
84 void OnTimeout() override;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000085 void set_lifetime(int lifetime) { lifetime_ = lifetime; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000086
87 private:
88 TurnPort* port_;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000089 int lifetime_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000090};
91
92class TurnCreatePermissionRequest : public StunRequest,
93 public sigslot::has_slots<> {
94 public:
95 TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
96 const rtc::SocketAddress& ext_addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070097 void Prepare(StunMessage* request) override;
98 void OnSent() override;
99 void OnResponse(StunMessage* response) override;
100 void OnErrorResponse(StunMessage* response) override;
101 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000102
103 private:
104 void OnEntryDestroyed(TurnEntry* entry);
105
106 TurnPort* port_;
107 TurnEntry* entry_;
108 rtc::SocketAddress ext_addr_;
109};
110
111class TurnChannelBindRequest : public StunRequest,
112 public sigslot::has_slots<> {
113 public:
114 TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
115 const rtc::SocketAddress& ext_addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700116 void Prepare(StunMessage* request) override;
117 void OnSent() override;
118 void OnResponse(StunMessage* response) override;
119 void OnErrorResponse(StunMessage* response) override;
120 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000121
122 private:
123 void OnEntryDestroyed(TurnEntry* entry);
124
125 TurnPort* port_;
126 TurnEntry* entry_;
127 int channel_id_;
128 rtc::SocketAddress ext_addr_;
129};
130
131// Manages a "connection" to a remote destination. We will attempt to bring up
132// a channel for this remote destination to reduce the overhead of sending data.
133class TurnEntry : public sigslot::has_slots<> {
134 public:
135 enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
136 TurnEntry(TurnPort* port, int channel_id,
137 const rtc::SocketAddress& ext_addr);
138
139 TurnPort* port() { return port_; }
140
141 int channel_id() const { return channel_id_; }
Honghai Zhangf67c5482015-12-11 15:16:54 -0800142 // For testing only.
143 void set_channel_id(int channel_id) { channel_id_ = channel_id; }
144
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000145 const rtc::SocketAddress& address() const { return ext_addr_; }
146 BindState state() const { return state_; }
147
honghaiz34b11eb2016-03-16 08:55:44 -0700148 int64_t destruction_timestamp() { return destruction_timestamp_; }
149 void set_destruction_timestamp(int64_t destruction_timestamp) {
honghaiz32f39962015-11-17 11:36:31 -0800150 destruction_timestamp_ = destruction_timestamp;
151 }
152
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000153 // Helper methods to send permission and channel bind requests.
Honghai Zhang85975432015-11-12 11:07:12 -0800154 void SendCreatePermissionRequest(int delay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155 void SendChannelBindRequest(int delay);
156 // Sends a packet to the given destination address.
157 // This will wrap the packet in STUN if necessary.
158 int Send(const void* data, size_t size, bool payload,
159 const rtc::PacketOptions& options);
160
161 void OnCreatePermissionSuccess();
162 void OnCreatePermissionError(StunMessage* response, int code);
Honghai Zhangf67c5482015-12-11 15:16:54 -0800163 void OnCreatePermissionTimeout();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000164 void OnChannelBindSuccess();
165 void OnChannelBindError(StunMessage* response, int code);
Honghai Zhangf67c5482015-12-11 15:16:54 -0800166 void OnChannelBindTimeout();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000167 // Signal sent when TurnEntry is destroyed.
168 sigslot::signal1<TurnEntry*> SignalDestroyed;
169
170 private:
171 TurnPort* port_;
172 int channel_id_;
173 rtc::SocketAddress ext_addr_;
174 BindState state_;
honghaiz32f39962015-11-17 11:36:31 -0800175 // A non-zero value indicates that this entry is scheduled to be destroyed.
176 // It is also used as an ID of the event scheduling. When the destruction
177 // event actually fires, the TurnEntry will be destroyed only if the
178 // timestamp here matches the one in the firing event.
honghaiz34b11eb2016-03-16 08:55:44 -0700179 int64_t destruction_timestamp_ = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000180};
181
182TurnPort::TurnPort(rtc::Thread* thread,
183 rtc::PacketSocketFactory* factory,
184 rtc::Network* network,
185 rtc::AsyncPacketSocket* socket,
186 const std::string& username,
187 const std::string& password,
188 const ProtocolAddress& server_address,
189 const RelayCredentials& credentials,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000190 int server_priority,
191 const std::string& origin)
honghaizb19eba32015-08-03 10:23:31 -0700192 : Port(thread,
Honghai Zhangd00c0572016-06-28 09:44:47 -0700193 RELAY_PORT_TYPE,
honghaizb19eba32015-08-03 10:23:31 -0700194 factory,
195 network,
196 socket->GetLocalAddress().ipaddr(),
197 username,
198 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000199 server_address_(server_address),
200 credentials_(credentials),
201 socket_(socket),
202 resolver_(NULL),
203 error_(0),
204 request_manager_(thread),
205 next_channel_number_(TURN_CHANNEL_NUMBER_START),
honghaizb19eba32015-08-03 10:23:31 -0700206 state_(STATE_CONNECTING),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000207 server_priority_(server_priority),
208 allocate_mismatch_retries_(0) {
209 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000210 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211}
212
213TurnPort::TurnPort(rtc::Thread* thread,
214 rtc::PacketSocketFactory* factory,
215 rtc::Network* network,
216 const rtc::IPAddress& ip,
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,
224 const std::string& origin)
honghaizb19eba32015-08-03 10:23:31 -0700225 : Port(thread,
226 RELAY_PORT_TYPE,
227 factory,
228 network,
229 ip,
230 min_port,
231 max_port,
232 username,
233 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234 server_address_(server_address),
235 credentials_(credentials),
236 socket_(NULL),
237 resolver_(NULL),
238 error_(0),
239 request_manager_(thread),
240 next_channel_number_(TURN_CHANNEL_NUMBER_START),
honghaizb19eba32015-08-03 10:23:31 -0700241 state_(STATE_CONNECTING),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000242 server_priority_(server_priority),
243 allocate_mismatch_retries_(0) {
244 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000245 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000246}
247
248TurnPort::~TurnPort() {
249 // TODO(juberti): Should this even be necessary?
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000250
251 // release the allocation by sending a refresh with
252 // lifetime 0.
honghaizb19eba32015-08-03 10:23:31 -0700253 if (ready()) {
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000254 TurnRefreshRequest bye(this);
255 bye.set_lifetime(0);
256 SendRequest(&bye, 0);
257 }
258
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000259 while (!entries_.empty()) {
honghaiz32f39962015-11-17 11:36:31 -0800260 DestroyEntry(entries_.front());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000261 }
262 if (resolver_) {
263 resolver_->Destroy(false);
264 }
265 if (!SharedSocket()) {
266 delete socket_;
267 }
268}
269
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000270rtc::SocketAddress TurnPort::GetLocalAddress() const {
271 return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress();
272}
273
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000274void TurnPort::PrepareAddress() {
275 if (credentials_.username.empty() ||
276 credentials_.password.empty()) {
277 LOG(LS_ERROR) << "Allocation can't be started without setting the"
278 << " TURN server credentials for the user.";
279 OnAllocateError();
280 return;
281 }
282
283 if (!server_address_.address.port()) {
284 // We will set default TURN port, if no port is set in the address.
285 server_address_.address.SetPort(TURN_DEFAULT_PORT);
286 }
287
tfarina20a34612015-11-02 16:20:22 -0800288 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000289 ResolveTurnAddress(server_address_.address);
290 } else {
291 // If protocol family of server address doesn't match with local, return.
292 if (!IsCompatibleAddress(server_address_.address)) {
honghaizb19eba32015-08-03 10:23:31 -0700293 LOG(LS_ERROR) << "IP address family does not match: "
294 << "server: " << server_address_.address.family()
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700295 << " local: " << ip().family();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296 OnAllocateError();
297 return;
298 }
299
300 // Insert the current address to prevent redirection pingpong.
301 attempted_server_addresses_.insert(server_address_.address);
302
303 LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
304 << ProtoToString(server_address_.proto) << " @ "
305 << server_address_.address.ToSensitiveString();
306 if (!CreateTurnClientSocket()) {
honghaizb19eba32015-08-03 10:23:31 -0700307 LOG(LS_ERROR) << "Failed to create TURN client socket";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000308 OnAllocateError();
honghaizb19eba32015-08-03 10:23:31 -0700309 return;
310 }
311 if (server_address_.proto == PROTO_UDP) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000312 // If its UDP, send AllocateRequest now.
313 // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
314 SendRequest(new TurnAllocateRequest(this), 0);
315 }
316 }
317}
318
319bool TurnPort::CreateTurnClientSocket() {
nisseede5da42017-01-12 05:15:36 -0800320 RTC_DCHECK(!socket_ || SharedSocket());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000321
322 if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
323 socket_ = socket_factory()->CreateUdpSocket(
324 rtc::SocketAddress(ip(), 0), min_port(), max_port());
hnsl277b2502016-12-13 05:17:23 -0800325 } else if (server_address_.proto == PROTO_TCP ||
326 server_address_.proto == PROTO_TLS) {
nisseede5da42017-01-12 05:15:36 -0800327 RTC_DCHECK(!SharedSocket());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000328 int opts = rtc::PacketSocketFactory::OPT_STUN;
hnsl277b2502016-12-13 05:17:23 -0800329
330 // Apply server address TLS and insecure bits to options.
331 if (server_address_.proto == PROTO_TLS) {
hnsl04833622017-01-09 08:35:45 -0800332 if (tls_cert_policy_ ==
333 TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) {
334 opts |= rtc::PacketSocketFactory::OPT_TLS_INSECURE;
335 } else {
336 opts |= rtc::PacketSocketFactory::OPT_TLS;
337 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 }
hnsl04833622017-01-09 08:35:45 -0800339
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000340 socket_ = socket_factory()->CreateClientTcpSocket(
341 rtc::SocketAddress(ip(), 0), server_address_.address,
342 proxy(), user_agent(), opts);
343 }
344
345 if (!socket_) {
346 error_ = SOCKET_ERROR;
347 return false;
348 }
349
350 // Apply options if any.
351 for (SocketOptionsMap::iterator iter = socket_options_.begin();
352 iter != socket_options_.end(); ++iter) {
353 socket_->SetOption(iter->first, iter->second);
354 }
355
356 if (!SharedSocket()) {
357 // If socket is shared, AllocationSequence will receive the packet.
358 socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
359 }
360
361 socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
362
Stefan Holmer55674ff2016-01-14 15:49:16 +0100363 socket_->SignalSentPacket.connect(this, &TurnPort::OnSentPacket);
364
honghaizb19eba32015-08-03 10:23:31 -0700365 // TCP port is ready to send stun requests after the socket is connected,
366 // while UDP port is ready to do so once the socket is created.
hnsl277b2502016-12-13 05:17:23 -0800367 if (server_address_.proto == PROTO_TCP ||
368 server_address_.proto == PROTO_TLS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000369 socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
370 socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
honghaizb19eba32015-08-03 10:23:31 -0700371 } else {
372 state_ = STATE_CONNECTED;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000373 }
374 return true;
375}
376
377void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
nisseede5da42017-01-12 05:15:36 -0800378 RTC_DCHECK(server_address_.proto == PROTO_TCP);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379 // Do not use this port if the socket bound to a different address than
380 // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
381 // given a binding address, and the platform is expected to pick the
382 // correct local address.
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000383
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700384 // However, there are two situations in which we allow the bound address to
385 // differ from the requested address: 1. The bound address is the loopback
386 // address. This happens when a proxy forces TCP to bind to only the
387 // localhost address (see issue 3927). 2. The bound address is the "any
388 // address". This happens when multiple_routes is disabled (see issue 4780).
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 if (socket->GetLocalAddress().ipaddr() != ip()) {
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000390 if (socket->GetLocalAddress().IsLoopbackIP()) {
391 LOG(LS_WARNING) << "Socket is bound to a different address:"
392 << socket->GetLocalAddress().ipaddr().ToString()
393 << ", rather then the local port:" << ip().ToString()
394 << ". Still allowing it since it's localhost.";
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700395 } else if (IPIsAny(ip())) {
396 LOG(LS_WARNING) << "Socket is bound to a different address:"
397 << socket->GetLocalAddress().ipaddr().ToString()
398 << ", rather then the local port:" << ip().ToString()
399 << ". Still allowing it since it's any address"
400 << ", possibly caused by multiple_routes being disabled.";
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000401 } else {
402 LOG(LS_WARNING) << "Socket is bound to a different address:"
403 << socket->GetLocalAddress().ipaddr().ToString()
404 << ", rather then the local port:" << ip().ToString()
405 << ". Discarding TURN port.";
406 OnAllocateError();
407 return;
408 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409 }
410
honghaizb19eba32015-08-03 10:23:31 -0700411 state_ = STATE_CONNECTED; // It is ready to send stun requests.
tfarina20a34612015-11-02 16:20:22 -0800412 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 server_address_.address = socket_->GetRemoteAddress();
414 }
415
416 LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
417 << " using tcp.";
418 SendRequest(new TurnAllocateRequest(this), 0);
419}
420
421void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
422 LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
nisseede5da42017-01-12 05:15:36 -0800423 RTC_DCHECK(socket == socket_);
honghaiz6b9ab922016-01-05 09:06:12 -0800424 Close();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000425}
426
427void TurnPort::OnAllocateMismatch() {
428 if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
429 LOG_J(LS_WARNING, this) << "Giving up on the port after "
430 << allocate_mismatch_retries_
431 << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
432 OnAllocateError();
433 return;
434 }
435
436 LOG_J(LS_INFO, this) << "Allocating a new socket after "
437 << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
438 << allocate_mismatch_retries_ + 1;
439 if (SharedSocket()) {
440 ResetSharedSocket();
441 } else {
442 delete socket_;
443 }
444 socket_ = NULL;
445
honghaizc463e202016-02-01 15:19:08 -0800446 ResetNonce();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000447 PrepareAddress();
448 ++allocate_mismatch_retries_;
449}
450
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700451Connection* TurnPort::CreateConnection(const Candidate& remote_candidate,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000452 CandidateOrigin origin) {
453 // TURN-UDP can only connect to UDP candidates.
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700454 if (!SupportsProtocol(remote_candidate.protocol())) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000455 return NULL;
456 }
457
honghaiz079a7a12016-06-22 16:26:29 -0700458 if (state_ == STATE_DISCONNECTED || state_ == STATE_RECEIVEONLY) {
honghaizb19eba32015-08-03 10:23:31 -0700459 return NULL;
460 }
461
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000462 // A TURN port will have two candiates, STUN and TURN. STUN may not
463 // present in all cases. If present stun candidate will be added first
464 // and TURN candidate later.
465 for (size_t index = 0; index < Candidates().size(); ++index) {
Honghai Zhangf4ae6dc2016-06-22 22:34:58 -0700466 const Candidate& local_candidate = Candidates()[index];
467 if (local_candidate.type() == RELAY_PORT_TYPE &&
468 local_candidate.address().family() ==
469 remote_candidate.address().family()) {
470 // Create an entry, if needed, so we can get our permissions set up
471 // correctly.
472 CreateOrRefreshEntry(remote_candidate.address());
473 ProxyConnection* conn =
474 new ProxyConnection(this, index, remote_candidate);
honghaiz36f50e82016-06-01 15:57:03 -0700475 AddOrReplaceConnection(conn);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 return conn;
477 }
478 }
479 return NULL;
480}
481
honghaiz079a7a12016-06-22 16:26:29 -0700482bool TurnPort::FailAndPruneConnection(const rtc::SocketAddress& address) {
Honghai Zhangf67c5482015-12-11 15:16:54 -0800483 Connection* conn = GetConnection(address);
484 if (conn != nullptr) {
honghaiz079a7a12016-06-22 16:26:29 -0700485 conn->FailAndPrune();
Honghai Zhangf67c5482015-12-11 15:16:54 -0800486 return true;
487 }
488 return false;
489}
490
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000491int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
492 if (!socket_) {
493 // If socket is not created yet, these options will be applied during socket
494 // creation.
495 socket_options_[opt] = value;
496 return 0;
497 }
498 return socket_->SetOption(opt, value);
499}
500
501int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
502 if (!socket_) {
503 SocketOptionsMap::const_iterator it = socket_options_.find(opt);
504 if (it == socket_options_.end()) {
505 return -1;
506 }
507 *value = it->second;
508 return 0;
509 }
510
511 return socket_->GetOption(opt, value);
512}
513
514int TurnPort::GetError() {
515 return error_;
516}
517
518int TurnPort::SendTo(const void* data, size_t size,
519 const rtc::SocketAddress& addr,
520 const rtc::PacketOptions& options,
521 bool payload) {
522 // Try to find an entry for this specific address; we should have one.
523 TurnEntry* entry = FindEntry(addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000524 if (!entry) {
honghaizb19eba32015-08-03 10:23:31 -0700525 LOG(LS_ERROR) << "Did not find the TurnEntry for address " << addr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000526 return 0;
527 }
528
honghaizb19eba32015-08-03 10:23:31 -0700529 if (!ready()) {
skvladc309e0e2016-07-28 17:15:20 -0700530 error_ = ENOTCONN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000531 return SOCKET_ERROR;
532 }
533
534 // Send the actual contents to the server using the usual mechanism.
535 int sent = entry->Send(data, size, payload, options);
536 if (sent <= 0) {
537 return SOCKET_ERROR;
538 }
539
540 // The caller of the function is expecting the number of user data bytes,
541 // rather than the size of the packet.
542 return static_cast<int>(size);
543}
544
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700545bool TurnPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
546 const char* data, size_t size,
547 const rtc::SocketAddress& remote_addr,
548 const rtc::PacketTime& packet_time) {
549 if (socket != socket_) {
550 // The packet was received on a shared socket after we've allocated a new
551 // socket for this TURN port.
552 return false;
553 }
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000554
555 // This is to guard against a STUN response from previous server after
556 // alternative server redirection. TODO(guoweis): add a unit test for this
557 // race condition.
558 if (remote_addr != server_address_.address) {
559 LOG_J(LS_WARNING, this) << "Discarding TURN message from unknown address:"
560 << remote_addr.ToString()
561 << ", server_address_:"
562 << server_address_.address.ToString();
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700563 return false;
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000564 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000565
566 // The message must be at least the size of a channel header.
567 if (size < TURN_CHANNEL_HEADER_SIZE) {
568 LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700569 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570 }
571
honghaiz9dfed792016-01-29 13:22:31 -0800572 if (state_ == STATE_DISCONNECTED) {
573 LOG_J(LS_WARNING, this)
honghaiz079a7a12016-06-22 16:26:29 -0700574 << "Received TURN message while the TURN port is disconnected";
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700575 return false;
honghaiz9dfed792016-01-29 13:22:31 -0800576 }
577
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000578 // Check the message type, to see if is a Channel Data message.
579 // The message will either be channel data, a TURN data indication, or
580 // a response to a previous request.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200581 uint16_t msg_type = rtc::GetBE16(data);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000582 if (IsTurnChannelData(msg_type)) {
583 HandleChannelData(msg_type, data, size, packet_time);
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700584 return true;
jiayl@webrtc.org511f8a82014-12-03 02:17:07 +0000585
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000586 }
Sergey Ulanov17fa6722016-05-10 10:20:47 -0700587
588 if (msg_type == TURN_DATA_INDICATION) {
589 HandleDataIndication(data, size, packet_time);
590 return true;
591 }
592
593 if (SharedSocket() && (msg_type == STUN_BINDING_RESPONSE ||
594 msg_type == STUN_BINDING_ERROR_RESPONSE)) {
595 LOG_J(LS_VERBOSE, this) <<
596 "Ignoring STUN binding response message on shared socket.";
597 return false;
598 }
599
600 // This must be a response for one of our requests.
601 // Check success responses, but not errors, for MESSAGE-INTEGRITY.
602 if (IsStunSuccessResponseType(msg_type) &&
603 !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
604 LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
605 << "message integrity, msg_type=" << msg_type;
606 return true;
607 }
608 request_manager_.CheckResponse(data, size);
609
610 return true;
611}
612
613void TurnPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
614 const char* data,
615 size_t size,
616 const rtc::SocketAddress& remote_addr,
617 const rtc::PacketTime& packet_time) {
618 HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000619}
620
Stefan Holmer55674ff2016-01-14 15:49:16 +0100621void TurnPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
622 const rtc::SentPacket& sent_packet) {
623 PortInterface::SignalSentPacket(sent_packet);
624}
625
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000626void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
honghaizb19eba32015-08-03 10:23:31 -0700627 if (ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000628 Port::OnReadyToSend();
629 }
630}
631
632
633// Update current server address port with the alternate server address port.
634bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
635 // Check if we have seen this address before and reject if we did.
636 AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
637 if (iter != attempted_server_addresses_.end()) {
638 LOG_J(LS_WARNING, this) << "Redirection to ["
639 << address.ToSensitiveString()
640 << "] ignored, allocation failed.";
641 return false;
642 }
643
644 // If protocol family of server address doesn't match with local, return.
645 if (!IsCompatibleAddress(address)) {
646 LOG(LS_WARNING) << "Server IP address family does not match with "
647 << "local host address family type";
648 return false;
649 }
650
deadbeeffb70b452016-10-24 13:15:59 -0700651 // Block redirects to a loopback address.
652 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=649118
653 if (address.IsLoopbackIP()) {
654 LOG_J(LS_WARNING, this)
655 << "Blocking attempted redirect to loopback address.";
656 return false;
657 }
658
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000659 LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
660 << server_address_.address.ToSensitiveString()
661 << "] to TURN server ["
662 << address.ToSensitiveString()
663 << "]";
hnsl277b2502016-12-13 05:17:23 -0800664 server_address_ = ProtocolAddress(address, server_address_.proto);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000665
666 // Insert the current address to prevent redirection pingpong.
667 attempted_server_addresses_.insert(server_address_.address);
668 return true;
669}
670
671void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
672 if (resolver_)
673 return;
674
Honghai Zhang0f490a52015-12-07 12:06:20 -0800675 LOG_J(LS_INFO, this) << "Starting TURN host lookup for "
676 << address.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677 resolver_ = socket_factory()->CreateAsyncResolver();
678 resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
679 resolver_->Start(address);
680}
681
682void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
nisseede5da42017-01-12 05:15:36 -0800683 RTC_DCHECK(resolver == resolver_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000684 // If DNS resolve is failed when trying to connect to the server using TCP,
685 // one of the reason could be due to DNS queries blocked by firewall.
686 // In such cases we will try to connect to the server with hostname, assuming
687 // socket layer will resolve the hostname through a HTTP proxy (if any).
688 if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
689 if (!CreateTurnClientSocket()) {
690 OnAllocateError();
691 }
692 return;
693 }
694
695 // Copy the original server address in |resolved_address|. For TLS based
696 // sockets we need hostname along with resolved address.
697 rtc::SocketAddress resolved_address = server_address_.address;
698 if (resolver_->GetError() != 0 ||
699 !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
700 LOG_J(LS_WARNING, this) << "TURN host lookup received error "
701 << resolver_->GetError();
702 error_ = resolver_->GetError();
703 OnAllocateError();
704 return;
705 }
706 // Signal needs both resolved and unresolved address. After signal is sent
707 // we can copy resolved address back into |server_address_|.
708 SignalResolvedServerAddress(this, server_address_.address,
709 resolved_address);
710 server_address_.address = resolved_address;
711 PrepareAddress();
712}
713
714void TurnPort::OnSendStunPacket(const void* data, size_t size,
715 StunRequest* request) {
nisseede5da42017-01-12 05:15:36 -0800716 RTC_DCHECK(connected());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000717 rtc::PacketOptions options(DefaultDscpValue());
718 if (Send(data, size, options) < 0) {
719 LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
720 << socket_->GetError();
721 }
722}
723
724void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
725 // STUN Port will discover STUN candidate, as it's supplied with first TURN
726 // server address.
727 // Why not using this address? - P2PTransportChannel will start creating
728 // connections after first candidate, which means it could start creating the
729 // connections before TURN candidate added. For that to handle, we need to
730 // supply STUN candidate from this port to UDPPort, and TurnPort should have
731 // handle to UDPPort to pass back the address.
732}
733
734void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
735 const rtc::SocketAddress& stun_address) {
honghaizb19eba32015-08-03 10:23:31 -0700736 state_ = STATE_READY;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000737
738 rtc::SocketAddress related_address = stun_address;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000739
740 // For relayed candidate, Base is the candidate itself.
741 AddAddress(address, // Candidate address.
742 address, // Base address.
743 related_address, // Related address.
744 UDP_PROTOCOL_NAME,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700745 ProtoToString(server_address_.proto), // The first hop protocol.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000746 "", // TCP canddiate type, empty for turn candidates.
hnsl277b2502016-12-13 05:17:23 -0800747 RELAY_PORT_TYPE, GetRelayPreference(server_address_.proto),
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700748 server_priority_, true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000749}
750
751void TurnPort::OnAllocateError() {
752 // We will send SignalPortError asynchronously as this can be sent during
753 // port initialization. This way it will not be blocking other port
754 // creation.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700755 thread()->Post(RTC_FROM_HERE, this, MSG_ALLOCATE_ERROR);
Honghai Zhangf67c5482015-12-11 15:16:54 -0800756}
757
honghaiz079a7a12016-06-22 16:26:29 -0700758void TurnPort::OnRefreshError() {
759 // Need to clear the requests asynchronously because otherwise, the refresh
honghaiz6b9ab922016-01-05 09:06:12 -0800760 // request may be deleted twice: once at the end of the message processing
honghaiz079a7a12016-06-22 16:26:29 -0700761 // and the other in HandleRefreshError().
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700762 thread()->Post(RTC_FROM_HERE, this, MSG_REFRESH_ERROR);
honghaiz6b9ab922016-01-05 09:06:12 -0800763}
764
honghaiz079a7a12016-06-22 16:26:29 -0700765void TurnPort::HandleRefreshError() {
766 request_manager_.Clear();
767 state_ = STATE_RECEIVEONLY;
768 // Fail and prune all connections; stop sending data.
769 for (auto kv : connections()) {
770 kv.second->FailAndPrune();
771 }
772}
773
Honghai Zhangf67c5482015-12-11 15:16:54 -0800774void TurnPort::Close() {
honghaiz6b9ab922016-01-05 09:06:12 -0800775 if (!ready()) {
776 OnAllocateError();
777 }
778 request_manager_.Clear();
Honghai Zhangf67c5482015-12-11 15:16:54 -0800779 // Stop the port from creating new connections.
780 state_ = STATE_DISCONNECTED;
781 // Delete all existing connections; stop sending data.
782 for (auto kv : connections()) {
783 kv.second->Destroy();
784 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000785}
786
787void TurnPort::OnMessage(rtc::Message* message) {
Honghai Zhangf67c5482015-12-11 15:16:54 -0800788 switch (message->message_id) {
789 case MSG_ALLOCATE_ERROR:
790 SignalPortError(this);
791 break;
792 case MSG_ALLOCATE_MISMATCH:
793 OnAllocateMismatch();
794 break;
honghaiz6b9ab922016-01-05 09:06:12 -0800795 case MSG_REFRESH_ERROR:
honghaiz079a7a12016-06-22 16:26:29 -0700796 HandleRefreshError();
honghaiz6b9ab922016-01-05 09:06:12 -0800797 break;
Honghai Zhangf67c5482015-12-11 15:16:54 -0800798 case MSG_TRY_ALTERNATE_SERVER:
799 if (server_address().proto == PROTO_UDP) {
800 // Send another allocate request to alternate server, with the received
801 // realm and nonce values.
802 SendRequest(new TurnAllocateRequest(this), 0);
803 } else {
804 // Since it's TCP, we have to delete the connected socket and reconnect
805 // with the alternate server. PrepareAddress will send stun binding once
806 // the new socket is connected.
nisseede5da42017-01-12 05:15:36 -0800807 RTC_DCHECK(server_address().proto == PROTO_TCP);
808 RTC_DCHECK(!SharedSocket());
Honghai Zhangf67c5482015-12-11 15:16:54 -0800809 delete socket_;
810 socket_ = NULL;
811 PrepareAddress();
812 }
813 break;
814 default:
815 Port::OnMessage(message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000816 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000817}
818
819void TurnPort::OnAllocateRequestTimeout() {
820 OnAllocateError();
821}
822
823void TurnPort::HandleDataIndication(const char* data, size_t size,
824 const rtc::PacketTime& packet_time) {
825 // Read in the message, and process according to RFC5766, Section 10.4.
jbauchf1f87202016-03-30 06:43:37 -0700826 rtc::ByteBufferReader buf(data, size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 TurnMessage msg;
828 if (!msg.Read(&buf)) {
829 LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
830 return;
831 }
832
833 // Check mandatory attributes.
834 const StunAddressAttribute* addr_attr =
835 msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
836 if (!addr_attr) {
837 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
838 << "in data indication.";
839 return;
840 }
841
842 const StunByteStringAttribute* data_attr =
843 msg.GetByteString(STUN_ATTR_DATA);
844 if (!data_attr) {
845 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
846 << "data indication.";
847 return;
848 }
849
Taylor Brandstetteref184702016-06-23 17:35:47 -0700850 // Log a warning if the data didn't come from an address that we think we have
851 // a permission for.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000852 rtc::SocketAddress ext_addr(addr_attr->GetAddress());
853 if (!HasPermission(ext_addr.ipaddr())) {
Taylor Brandstetteref184702016-06-23 17:35:47 -0700854 LOG_J(LS_WARNING, this)
855 << "Received TURN data indication with unknown "
856 << "peer address, addr=" << ext_addr.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000857 }
858
859 DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
860 PROTO_UDP, packet_time);
861}
862
863void TurnPort::HandleChannelData(int channel_id, const char* data,
864 size_t size,
865 const rtc::PacketTime& packet_time) {
866 // Read the message, and process according to RFC5766, Section 11.6.
867 // 0 1 2 3
868 // 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
869 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
870 // | Channel Number | Length |
871 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
872 // | |
873 // / Application Data /
874 // / /
875 // | |
876 // | +-------------------------------+
877 // | |
878 // +-------------------------------+
879
880 // Extract header fields from the message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200881 uint16_t len = rtc::GetBE16(data + 2);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000882 if (len > size - TURN_CHANNEL_HEADER_SIZE) {
883 LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
884 << "incorrect length, len=" << len;
885 return;
886 }
887 // Allowing messages larger than |len|, as ChannelData can be padded.
888
889 TurnEntry* entry = FindEntry(channel_id);
890 if (!entry) {
891 LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
892 << "channel, channel_id=" << channel_id;
893 return;
894 }
895
896 DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
897 PROTO_UDP, packet_time);
898}
899
900void TurnPort::DispatchPacket(const char* data, size_t size,
901 const rtc::SocketAddress& remote_addr,
902 ProtocolType proto, const rtc::PacketTime& packet_time) {
903 if (Connection* conn = GetConnection(remote_addr)) {
904 conn->OnReadPacket(data, size, packet_time);
905 } else {
906 Port::OnReadPacket(data, size, remote_addr, proto);
907 }
908}
909
910bool TurnPort::ScheduleRefresh(int lifetime) {
911 // Lifetime is in seconds; we schedule a refresh for one minute less.
912 if (lifetime < 2 * 60) {
913 LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
914 << "too short, lifetime=" << lifetime;
915 return false;
916 }
917
Peter Thatcherb32a5c42015-04-10 14:04:42 -0700918 int delay = (lifetime - 60) * 1000;
919 SendRequest(new TurnRefreshRequest(this), delay);
920 LOG_J(LS_INFO, this) << "Scheduled refresh in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000921 return true;
922}
923
924void TurnPort::SendRequest(StunRequest* req, int delay) {
925 request_manager_.SendDelayed(req, delay);
926}
927
928void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
929 // If we've gotten the necessary data from the server, add it to our request.
930 VERIFY(!hash_.empty());
nissecc99bc22017-02-02 01:31:30 -0800931 msg->AddAttribute(new StunByteStringAttribute(
932 STUN_ATTR_USERNAME, credentials_.username));
933 msg->AddAttribute(new StunByteStringAttribute(
934 STUN_ATTR_REALM, realm_));
935 msg->AddAttribute(new StunByteStringAttribute(
936 STUN_ATTR_NONCE, nonce_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000937 VERIFY(msg->AddMessageIntegrity(hash()));
938}
939
940int TurnPort::Send(const void* data, size_t len,
941 const rtc::PacketOptions& options) {
942 return socket_->SendTo(data, len, server_address_.address, options);
943}
944
945void TurnPort::UpdateHash() {
946 VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
947 credentials_.password, &hash_));
948}
949
950bool TurnPort::UpdateNonce(StunMessage* response) {
951 // When stale nonce error received, we should update
952 // hash and store realm and nonce.
953 // Check the mandatory attributes.
954 const StunByteStringAttribute* realm_attr =
955 response->GetByteString(STUN_ATTR_REALM);
956 if (!realm_attr) {
957 LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
958 << "stale nonce error response.";
959 return false;
960 }
961 set_realm(realm_attr->GetString());
962
963 const StunByteStringAttribute* nonce_attr =
964 response->GetByteString(STUN_ATTR_NONCE);
965 if (!nonce_attr) {
966 LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
967 << "stale nonce error response.";
968 return false;
969 }
970 set_nonce(nonce_attr->GetString());
971 return true;
972}
973
honghaizc463e202016-02-01 15:19:08 -0800974void TurnPort::ResetNonce() {
975 hash_.clear();
976 nonce_.clear();
977 realm_.clear();
978}
979
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
981 return e->address().ipaddr() == ipaddr;
982}
983bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
984 return (std::find_if(entries_.begin(), entries_.end(),
985 std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
986}
987
988static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
989 return e->address() == addr;
990}
991TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
992 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
993 std::bind2nd(std::ptr_fun(MatchesAddress), addr));
994 return (it != entries_.end()) ? *it : NULL;
995}
996
997static bool MatchesChannelId(TurnEntry* e, int id) {
998 return e->channel_id() == id;
999}
1000TurnEntry* TurnPort::FindEntry(int channel_id) const {
1001 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
1002 std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
1003 return (it != entries_.end()) ? *it : NULL;
1004}
1005
honghaizc3e0fe72015-12-02 16:43:25 -08001006bool TurnPort::EntryExists(TurnEntry* e) {
1007 auto it = std::find(entries_.begin(), entries_.end(), e);
1008 return it != entries_.end();
1009}
1010
honghaiz32f39962015-11-17 11:36:31 -08001011void TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) {
1012 TurnEntry* entry = FindEntry(addr);
1013 if (entry == nullptr) {
1014 entry = new TurnEntry(this, next_channel_number_++, addr);
1015 entries_.push_back(entry);
1016 } else {
1017 // The channel binding request for the entry will be refreshed automatically
1018 // until the entry is destroyed.
1019 CancelEntryDestruction(entry);
1020 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001021}
1022
honghaiz32f39962015-11-17 11:36:31 -08001023void TurnPort::DestroyEntry(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001024 RTC_DCHECK(entry != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001025 entry->SignalDestroyed(entry);
1026 entries_.remove(entry);
1027 delete entry;
1028}
1029
honghaiz34b11eb2016-03-16 08:55:44 -07001030void TurnPort::DestroyEntryIfNotCancelled(TurnEntry* entry, int64_t timestamp) {
honghaizc3e0fe72015-12-02 16:43:25 -08001031 if (!EntryExists(entry)) {
1032 return;
1033 }
honghaiz32f39962015-11-17 11:36:31 -08001034 bool cancelled = timestamp != entry->destruction_timestamp();
1035 if (!cancelled) {
1036 DestroyEntry(entry);
1037 }
1038}
1039
honghaiz36f50e82016-06-01 15:57:03 -07001040void TurnPort::HandleConnectionDestroyed(Connection* conn) {
honghaiz32f39962015-11-17 11:36:31 -08001041 // Schedule an event to destroy TurnEntry for the connection, which is
1042 // already destroyed.
1043 const rtc::SocketAddress& remote_address = conn->remote_candidate().address();
1044 TurnEntry* entry = FindEntry(remote_address);
nisseede5da42017-01-12 05:15:36 -08001045 RTC_DCHECK(entry != NULL);
honghaiz32f39962015-11-17 11:36:31 -08001046 ScheduleEntryDestruction(entry);
1047}
1048
1049void TurnPort::ScheduleEntryDestruction(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001050 RTC_DCHECK(entry->destruction_timestamp() == 0);
nisse1bffc1d2016-05-02 08:18:55 -07001051 int64_t timestamp = rtc::TimeMillis();
honghaiz32f39962015-11-17 11:36:31 -08001052 entry->set_destruction_timestamp(timestamp);
1053 invoker_.AsyncInvokeDelayed<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001054 RTC_FROM_HERE, thread(),
honghaiz32f39962015-11-17 11:36:31 -08001055 rtc::Bind(&TurnPort::DestroyEntryIfNotCancelled, this, entry, timestamp),
1056 TURN_PERMISSION_TIMEOUT);
1057}
1058
1059void TurnPort::CancelEntryDestruction(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001060 RTC_DCHECK(entry->destruction_timestamp() != 0);
honghaiz32f39962015-11-17 11:36:31 -08001061 entry->set_destruction_timestamp(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001062}
1063
Honghai Zhangf67c5482015-12-11 15:16:54 -08001064bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address,
1065 int channel_id) {
1066 TurnEntry* entry = FindEntry(address);
1067 if (!entry) {
1068 return false;
1069 }
1070 entry->set_channel_id(channel_id);
1071 return true;
1072}
1073
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001074TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
1075 : StunRequest(new TurnMessage()),
1076 port_(port) {
1077}
1078
1079void TurnAllocateRequest::Prepare(StunMessage* request) {
1080 // Create the request as indicated in RFC 5766, Section 6.1.
1081 request->SetType(TURN_ALLOCATE_REQUEST);
1082 StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
1083 STUN_ATTR_REQUESTED_TRANSPORT);
1084 transport_attr->SetValue(IPPROTO_UDP << 24);
nissecc99bc22017-02-02 01:31:30 -08001085 request->AddAttribute(transport_attr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001086 if (!port_->hash().empty()) {
1087 port_->AddRequestAuthInfo(request);
1088 }
1089}
1090
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001091void TurnAllocateRequest::OnSent() {
1092 LOG_J(LS_INFO, port_) << "TURN allocate request sent"
1093 << ", id=" << rtc::hex_encode(id());
1094 StunRequest::OnSent();
1095}
1096
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001097void TurnAllocateRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001098 LOG_J(LS_INFO, port_) << "TURN allocate requested successfully"
1099 << ", id=" << rtc::hex_encode(id())
1100 << ", code=0" // Makes logging easier to parse.
1101 << ", rtt=" << Elapsed();
1102
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001103 // Check mandatory attributes as indicated in RFC5766, Section 6.3.
1104 const StunAddressAttribute* mapped_attr =
1105 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1106 if (!mapped_attr) {
1107 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
1108 << "attribute in allocate success response";
1109 return;
1110 }
1111 // Using XOR-Mapped-Address for stun.
1112 port_->OnStunAddress(mapped_attr->GetAddress());
1113
1114 const StunAddressAttribute* relayed_attr =
1115 response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
1116 if (!relayed_attr) {
1117 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
1118 << "attribute in allocate success response";
1119 return;
1120 }
1121
1122 const StunUInt32Attribute* lifetime_attr =
1123 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1124 if (!lifetime_attr) {
1125 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1126 << "allocate success response";
1127 return;
1128 }
1129 // Notify the port the allocate succeeded, and schedule a refresh request.
1130 port_->OnAllocateSuccess(relayed_attr->GetAddress(),
1131 mapped_attr->GetAddress());
1132 port_->ScheduleRefresh(lifetime_attr->value());
1133}
1134
1135void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
1136 // Process error response according to RFC5766, Section 6.4.
1137 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001138
1139 LOG_J(LS_INFO, port_) << "Received TURN allocate error response"
1140 << ", id=" << rtc::hex_encode(id())
1141 << ", code=" << error_code->code()
1142 << ", rtt=" << Elapsed();
1143
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001144 switch (error_code->code()) {
1145 case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
1146 OnAuthChallenge(response, error_code->code());
1147 break;
1148 case STUN_ERROR_TRY_ALTERNATE:
1149 OnTryAlternate(response, error_code->code());
1150 break;
1151 case STUN_ERROR_ALLOCATION_MISMATCH:
1152 // We must handle this error async because trying to delete the socket in
1153 // OnErrorResponse will cause a deadlock on the socket.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001154 port_->thread()->Post(RTC_FROM_HERE, port_,
1155 TurnPort::MSG_ALLOCATE_MISMATCH);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001156 break;
1157 default:
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001158 LOG_J(LS_WARNING, port_) << "Received TURN allocate error response"
1159 << ", id=" << rtc::hex_encode(id())
1160 << ", code=" << error_code->code()
1161 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001162 port_->OnAllocateError();
1163 }
1164}
1165
1166void TurnAllocateRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001167 LOG_J(LS_WARNING, port_) << "TURN allocate request "
1168 << rtc::hex_encode(id()) << " timout";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001169 port_->OnAllocateRequestTimeout();
1170}
1171
1172void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
1173 // If we failed to authenticate even after we sent our credentials, fail hard.
1174 if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
1175 LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
1176 << "after challenge.";
1177 port_->OnAllocateError();
1178 return;
1179 }
1180
1181 // Check the mandatory attributes.
1182 const StunByteStringAttribute* realm_attr =
1183 response->GetByteString(STUN_ATTR_REALM);
1184 if (!realm_attr) {
1185 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
1186 << "allocate unauthorized response.";
1187 return;
1188 }
1189 port_->set_realm(realm_attr->GetString());
1190
1191 const StunByteStringAttribute* nonce_attr =
1192 response->GetByteString(STUN_ATTR_NONCE);
1193 if (!nonce_attr) {
1194 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
1195 << "allocate unauthorized response.";
1196 return;
1197 }
1198 port_->set_nonce(nonce_attr->GetString());
1199
1200 // Send another allocate request, with the received realm and nonce values.
1201 port_->SendRequest(new TurnAllocateRequest(port_), 0);
1202}
1203
1204void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001205
1206 // According to RFC 5389 section 11, there are use cases where
1207 // authentication of response is not possible, we're not validating
1208 // message integrity.
1209
1210 // Get the alternate server address attribute value.
1211 const StunAddressAttribute* alternate_server_attr =
1212 response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1213 if (!alternate_server_attr) {
1214 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
1215 << "attribute in try alternate error response";
1216 port_->OnAllocateError();
1217 return;
1218 }
1219 if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1220 port_->OnAllocateError();
1221 return;
1222 }
1223
1224 // Check the attributes.
1225 const StunByteStringAttribute* realm_attr =
1226 response->GetByteString(STUN_ATTR_REALM);
1227 if (realm_attr) {
1228 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
1229 << "try alternate error response.";
1230 port_->set_realm(realm_attr->GetString());
1231 }
1232
1233 const StunByteStringAttribute* nonce_attr =
1234 response->GetByteString(STUN_ATTR_NONCE);
1235 if (nonce_attr) {
1236 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
1237 << "try alternate error response.";
1238 port_->set_nonce(nonce_attr->GetString());
1239 }
1240
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +00001241 // For TCP, we can't close the original Tcp socket during handling a 300 as
1242 // we're still inside that socket's event handler. Doing so will cause
1243 // deadlock.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001244 port_->thread()->Post(RTC_FROM_HERE, port_,
1245 TurnPort::MSG_TRY_ALTERNATE_SERVER);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001246}
1247
1248TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
1249 : StunRequest(new TurnMessage()),
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001250 port_(port),
1251 lifetime_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001252}
1253
1254void TurnRefreshRequest::Prepare(StunMessage* request) {
1255 // Create the request as indicated in RFC 5766, Section 7.1.
1256 // No attributes need to be included.
1257 request->SetType(TURN_REFRESH_REQUEST);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001258 if (lifetime_ > -1) {
nissecc99bc22017-02-02 01:31:30 -08001259 request->AddAttribute(new StunUInt32Attribute(
1260 STUN_ATTR_LIFETIME, lifetime_));
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001261 }
1262
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001263 port_->AddRequestAuthInfo(request);
1264}
1265
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001266void TurnRefreshRequest::OnSent() {
1267 LOG_J(LS_INFO, port_) << "TURN refresh request sent"
1268 << ", id=" << rtc::hex_encode(id());
1269 StunRequest::OnSent();
1270}
1271
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001272void TurnRefreshRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001273 LOG_J(LS_INFO, port_) << "TURN refresh requested successfully"
1274 << ", id=" << rtc::hex_encode(id())
1275 << ", code=0" // Makes logging easier to parse.
1276 << ", rtt=" << Elapsed();
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001277
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001278 // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1279 const StunUInt32Attribute* lifetime_attr =
1280 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1281 if (!lifetime_attr) {
1282 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1283 << "refresh success response.";
1284 return;
1285 }
1286
1287 // Schedule a refresh based on the returned lifetime value.
1288 port_->ScheduleRefresh(lifetime_attr->value());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001289 port_->SignalTurnRefreshResult(port_, TURN_SUCCESS_RESULT_CODE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001290}
1291
1292void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
1293 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001294
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001295 if (error_code->code() == STUN_ERROR_STALE_NONCE) {
1296 if (port_->UpdateNonce(response)) {
1297 // Send RefreshRequest immediately.
1298 port_->SendRequest(new TurnRefreshRequest(port_), 0);
1299 }
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001300 } else {
1301 LOG_J(LS_WARNING, port_) << "Received TURN refresh error response"
1302 << ", id=" << rtc::hex_encode(id())
1303 << ", code=" << error_code->code()
1304 << ", rtt=" << Elapsed();
honghaiz079a7a12016-06-22 16:26:29 -07001305 port_->OnRefreshError();
Honghai Zhangf67c5482015-12-11 15:16:54 -08001306 port_->SignalTurnRefreshResult(port_, error_code->code());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001307 }
1308}
1309
1310void TurnRefreshRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001311 LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id());
honghaiz079a7a12016-06-22 16:26:29 -07001312 port_->OnRefreshError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001313}
1314
1315TurnCreatePermissionRequest::TurnCreatePermissionRequest(
1316 TurnPort* port, TurnEntry* entry,
1317 const rtc::SocketAddress& ext_addr)
1318 : StunRequest(new TurnMessage()),
1319 port_(port),
1320 entry_(entry),
1321 ext_addr_(ext_addr) {
1322 entry_->SignalDestroyed.connect(
1323 this, &TurnCreatePermissionRequest::OnEntryDestroyed);
1324}
1325
1326void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
1327 // Create the request as indicated in RFC5766, Section 9.1.
1328 request->SetType(TURN_CREATE_PERMISSION_REQUEST);
nissecc99bc22017-02-02 01:31:30 -08001329 request->AddAttribute(new StunXorAddressAttribute(
1330 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001331 port_->AddRequestAuthInfo(request);
1332}
1333
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001334void TurnCreatePermissionRequest::OnSent() {
1335 LOG_J(LS_INFO, port_) << "TURN create permission request sent"
1336 << ", id=" << rtc::hex_encode(id());
1337 StunRequest::OnSent();
1338}
1339
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001340void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001341 LOG_J(LS_INFO, port_) << "TURN permission requested successfully"
1342 << ", id=" << rtc::hex_encode(id())
1343 << ", code=0" // Makes logging easier to parse.
1344 << ", rtt=" << Elapsed();
1345
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001346 if (entry_) {
1347 entry_->OnCreatePermissionSuccess();
1348 }
1349}
1350
1351void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001352 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001353 LOG_J(LS_WARNING, port_) << "Received TURN create permission error response"
1354 << ", id=" << rtc::hex_encode(id())
1355 << ", code=" << error_code->code()
1356 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001357 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001358 entry_->OnCreatePermissionError(response, error_code->code());
1359 }
1360}
1361
1362void TurnCreatePermissionRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001363 LOG_J(LS_WARNING, port_) << "TURN create permission timeout "
1364 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001365 if (entry_) {
1366 entry_->OnCreatePermissionTimeout();
1367 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001368}
1369
1370void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001371 RTC_DCHECK(entry_ == entry);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001372 entry_ = NULL;
1373}
1374
1375TurnChannelBindRequest::TurnChannelBindRequest(
1376 TurnPort* port, TurnEntry* entry,
1377 int channel_id, const rtc::SocketAddress& ext_addr)
1378 : StunRequest(new TurnMessage()),
1379 port_(port),
1380 entry_(entry),
1381 channel_id_(channel_id),
1382 ext_addr_(ext_addr) {
1383 entry_->SignalDestroyed.connect(
1384 this, &TurnChannelBindRequest::OnEntryDestroyed);
1385}
1386
1387void TurnChannelBindRequest::Prepare(StunMessage* request) {
1388 // Create the request as indicated in RFC5766, Section 11.1.
1389 request->SetType(TURN_CHANNEL_BIND_REQUEST);
nissecc99bc22017-02-02 01:31:30 -08001390 request->AddAttribute(new StunUInt32Attribute(
1391 STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16));
1392 request->AddAttribute(new StunXorAddressAttribute(
1393 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001394 port_->AddRequestAuthInfo(request);
1395}
1396
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001397void TurnChannelBindRequest::OnSent() {
1398 LOG_J(LS_INFO, port_) << "TURN channel bind request sent"
1399 << ", id=" << rtc::hex_encode(id());
1400 StunRequest::OnSent();
1401}
1402
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001403void TurnChannelBindRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001404 LOG_J(LS_INFO, port_) << "TURN channel bind requested successfully"
1405 << ", id=" << rtc::hex_encode(id())
1406 << ", code=0" // Makes logging easier to parse.
1407 << ", rtt=" << Elapsed();
1408
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001409 if (entry_) {
1410 entry_->OnChannelBindSuccess();
1411 // Refresh the channel binding just under the permission timeout
1412 // threshold. The channel binding has a longer lifetime, but
1413 // this is the easiest way to keep both the channel and the
1414 // permission from expiring.
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001415 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1416 entry_->SendChannelBindRequest(delay);
1417 LOG_J(LS_INFO, port_) << "Scheduled channel bind in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001418 }
1419}
1420
1421void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001422 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
1423 LOG_J(LS_WARNING, port_) << "Received TURN channel bind error response"
1424 << ", id=" << rtc::hex_encode(id())
1425 << ", code=" << error_code->code()
1426 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001427 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001428 entry_->OnChannelBindError(response, error_code->code());
1429 }
1430}
1431
1432void TurnChannelBindRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001433 LOG_J(LS_WARNING, port_) << "TURN channel bind timeout "
1434 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001435 if (entry_) {
1436 entry_->OnChannelBindTimeout();
1437 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001438}
1439
1440void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
nisseede5da42017-01-12 05:15:36 -08001441 RTC_DCHECK(entry_ == entry);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001442 entry_ = NULL;
1443}
1444
1445TurnEntry::TurnEntry(TurnPort* port, int channel_id,
1446 const rtc::SocketAddress& ext_addr)
1447 : port_(port),
1448 channel_id_(channel_id),
1449 ext_addr_(ext_addr),
1450 state_(STATE_UNBOUND) {
1451 // Creating permission for |ext_addr_|.
Honghai Zhang85975432015-11-12 11:07:12 -08001452 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001453}
1454
Honghai Zhang85975432015-11-12 11:07:12 -08001455void TurnEntry::SendCreatePermissionRequest(int delay) {
1456 port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
1457 delay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001458}
1459
1460void TurnEntry::SendChannelBindRequest(int delay) {
1461 port_->SendRequest(new TurnChannelBindRequest(
1462 port_, this, channel_id_, ext_addr_), delay);
1463}
1464
1465int TurnEntry::Send(const void* data, size_t size, bool payload,
1466 const rtc::PacketOptions& options) {
jbauchf1f87202016-03-30 06:43:37 -07001467 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001468 if (state_ != STATE_BOUND) {
1469 // If we haven't bound the channel yet, we have to use a Send Indication.
1470 TurnMessage msg;
1471 msg.SetType(TURN_SEND_INDICATION);
1472 msg.SetTransactionID(
1473 rtc::CreateRandomString(kStunTransactionIdLength));
nissecc99bc22017-02-02 01:31:30 -08001474 msg.AddAttribute(new StunXorAddressAttribute(
1475 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
1476 msg.AddAttribute(new StunByteStringAttribute(
1477 STUN_ATTR_DATA, data, size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001478 VERIFY(msg.Write(&buf));
1479
1480 // If we're sending real data, request a channel bind that we can use later.
1481 if (state_ == STATE_UNBOUND && payload) {
1482 SendChannelBindRequest(0);
1483 state_ = STATE_BINDING;
1484 }
1485 } else {
1486 // If the channel is bound, we can send the data as a Channel Message.
1487 buf.WriteUInt16(channel_id_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001488 buf.WriteUInt16(static_cast<uint16_t>(size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001489 buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1490 }
1491 return port_->Send(buf.Data(), buf.Length(), options);
1492}
1493
1494void TurnEntry::OnCreatePermissionSuccess() {
1495 LOG_J(LS_INFO, port_) << "Create permission for "
1496 << ext_addr_.ToSensitiveString()
1497 << " succeeded";
Honghai Zhangf67c5482015-12-11 15:16:54 -08001498 port_->SignalCreatePermissionResult(port_, ext_addr_,
1499 TURN_SUCCESS_RESULT_CODE);
Honghai Zhang85975432015-11-12 11:07:12 -08001500
1501 // If |state_| is STATE_BOUND, the permission will be refreshed
1502 // by ChannelBindRequest.
1503 if (state_ != STATE_BOUND) {
1504 // Refresh the permission request about 1 minute before the permission
1505 // times out.
1506 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1507 SendCreatePermissionRequest(delay);
1508 LOG_J(LS_INFO, port_) << "Scheduled create-permission-request in "
1509 << delay << "ms.";
1510 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001511}
1512
1513void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001514 if (code == STUN_ERROR_STALE_NONCE) {
1515 if (port_->UpdateNonce(response)) {
Honghai Zhang85975432015-11-12 11:07:12 -08001516 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001517 }
1518 } else {
honghaiz079a7a12016-06-22 16:26:29 -07001519 bool found = port_->FailAndPruneConnection(ext_addr_);
1520 if (found) {
1521 LOG(LS_ERROR) << "Received TURN CreatePermission error response, "
1522 << "code=" << code << "; pruned connection.";
1523 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001524 // Send signal with error code.
1525 port_->SignalCreatePermissionResult(port_, ext_addr_, code);
1526 }
1527}
1528
Honghai Zhangf67c5482015-12-11 15:16:54 -08001529void TurnEntry::OnCreatePermissionTimeout() {
honghaiz079a7a12016-06-22 16:26:29 -07001530 port_->FailAndPruneConnection(ext_addr_);
Honghai Zhangf67c5482015-12-11 15:16:54 -08001531}
1532
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001533void TurnEntry::OnChannelBindSuccess() {
1534 LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
1535 << " succeeded";
nisseede5da42017-01-12 05:15:36 -08001536 RTC_DCHECK(state_ == STATE_BINDING || state_ == STATE_BOUND);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001537 state_ = STATE_BOUND;
1538}
1539
1540void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
Honghai Zhangf67c5482015-12-11 15:16:54 -08001541 // If the channel bind fails due to errors other than STATE_NONCE,
honghaiz079a7a12016-06-22 16:26:29 -07001542 // we will fail and prune the connection and rely on ICE restart to
1543 // re-establish a new connection if needed.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001544 if (code == STUN_ERROR_STALE_NONCE) {
1545 if (port_->UpdateNonce(response)) {
1546 // Send channel bind request with fresh nonce.
1547 SendChannelBindRequest(0);
1548 }
Honghai Zhangf67c5482015-12-11 15:16:54 -08001549 } else {
1550 state_ = STATE_UNBOUND;
honghaiz079a7a12016-06-22 16:26:29 -07001551 port_->FailAndPruneConnection(ext_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001552 }
1553}
Honghai Zhangf67c5482015-12-11 15:16:54 -08001554void TurnEntry::OnChannelBindTimeout() {
1555 state_ = STATE_UNBOUND;
honghaiz079a7a12016-06-22 16:26:29 -07001556 port_->FailAndPruneConnection(ext_addr_);
Honghai Zhangf67c5482015-12-11 15:16:54 -08001557}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001558} // namespace cricket