blob: 4f5fef1d53ffcd90c7b191ee7a88146c1e17f951 [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"
19#include "webrtc/base/common.h"
20#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
47static int GetRelayPreference(cricket::ProtocolType proto, bool secure) {
48 int relay_preference = ICE_TYPE_PREFERENCE_RELAY;
49 if (proto == cricket::PROTO_TCP) {
50 relay_preference -= 1;
51 if (secure)
52 relay_preference -= 1;
53 }
54
55 ASSERT(relay_preference >= 0);
56 return relay_preference;
57}
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
honghaiz32f39962015-11-17 11:36:31 -0800148 uint32_t destruction_timestamp() { return destruction_timestamp_; }
149 void set_destruction_timestamp(uint32_t destruction_timestamp) {
150 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.
179 uint32_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,
193 factory,
194 network,
195 socket->GetLocalAddress().ipaddr(),
196 username,
197 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000198 server_address_(server_address),
199 credentials_(credentials),
200 socket_(socket),
201 resolver_(NULL),
202 error_(0),
203 request_manager_(thread),
204 next_channel_number_(TURN_CHANNEL_NUMBER_START),
honghaizb19eba32015-08-03 10:23:31 -0700205 state_(STATE_CONNECTING),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000206 server_priority_(server_priority),
207 allocate_mismatch_retries_(0) {
208 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000209 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000210}
211
212TurnPort::TurnPort(rtc::Thread* thread,
213 rtc::PacketSocketFactory* factory,
214 rtc::Network* network,
215 const rtc::IPAddress& ip,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200216 uint16_t min_port,
217 uint16_t max_port,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218 const std::string& username,
219 const std::string& password,
220 const ProtocolAddress& server_address,
221 const RelayCredentials& credentials,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000222 int server_priority,
223 const std::string& origin)
honghaizb19eba32015-08-03 10:23:31 -0700224 : Port(thread,
225 RELAY_PORT_TYPE,
226 factory,
227 network,
228 ip,
229 min_port,
230 max_port,
231 username,
232 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000233 server_address_(server_address),
234 credentials_(credentials),
235 socket_(NULL),
236 resolver_(NULL),
237 error_(0),
238 request_manager_(thread),
239 next_channel_number_(TURN_CHANNEL_NUMBER_START),
honghaizb19eba32015-08-03 10:23:31 -0700240 state_(STATE_CONNECTING),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000241 server_priority_(server_priority),
242 allocate_mismatch_retries_(0) {
243 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000244 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245}
246
247TurnPort::~TurnPort() {
248 // TODO(juberti): Should this even be necessary?
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000249
250 // release the allocation by sending a refresh with
251 // lifetime 0.
honghaizb19eba32015-08-03 10:23:31 -0700252 if (ready()) {
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000253 TurnRefreshRequest bye(this);
254 bye.set_lifetime(0);
255 SendRequest(&bye, 0);
256 }
257
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000258 while (!entries_.empty()) {
honghaiz32f39962015-11-17 11:36:31 -0800259 DestroyEntry(entries_.front());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000260 }
261 if (resolver_) {
262 resolver_->Destroy(false);
263 }
264 if (!SharedSocket()) {
265 delete socket_;
266 }
267}
268
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000269rtc::SocketAddress TurnPort::GetLocalAddress() const {
270 return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress();
271}
272
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000273void TurnPort::PrepareAddress() {
274 if (credentials_.username.empty() ||
275 credentials_.password.empty()) {
276 LOG(LS_ERROR) << "Allocation can't be started without setting the"
277 << " TURN server credentials for the user.";
278 OnAllocateError();
279 return;
280 }
281
282 if (!server_address_.address.port()) {
283 // We will set default TURN port, if no port is set in the address.
284 server_address_.address.SetPort(TURN_DEFAULT_PORT);
285 }
286
tfarina20a34612015-11-02 16:20:22 -0800287 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000288 ResolveTurnAddress(server_address_.address);
289 } else {
290 // If protocol family of server address doesn't match with local, return.
291 if (!IsCompatibleAddress(server_address_.address)) {
honghaizb19eba32015-08-03 10:23:31 -0700292 LOG(LS_ERROR) << "IP address family does not match: "
293 << "server: " << server_address_.address.family()
294 << "local: " << ip().family();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000295 OnAllocateError();
296 return;
297 }
298
299 // Insert the current address to prevent redirection pingpong.
300 attempted_server_addresses_.insert(server_address_.address);
301
302 LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
303 << ProtoToString(server_address_.proto) << " @ "
304 << server_address_.address.ToSensitiveString();
305 if (!CreateTurnClientSocket()) {
honghaizb19eba32015-08-03 10:23:31 -0700306 LOG(LS_ERROR) << "Failed to create TURN client socket";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000307 OnAllocateError();
honghaizb19eba32015-08-03 10:23:31 -0700308 return;
309 }
310 if (server_address_.proto == PROTO_UDP) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000311 // If its UDP, send AllocateRequest now.
312 // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
313 SendRequest(new TurnAllocateRequest(this), 0);
314 }
315 }
316}
317
318bool TurnPort::CreateTurnClientSocket() {
319 ASSERT(!socket_ || SharedSocket());
320
321 if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
322 socket_ = socket_factory()->CreateUdpSocket(
323 rtc::SocketAddress(ip(), 0), min_port(), max_port());
324 } else if (server_address_.proto == PROTO_TCP) {
325 ASSERT(!SharedSocket());
326 int opts = rtc::PacketSocketFactory::OPT_STUN;
327 // If secure bit is enabled in server address, use TLS over TCP.
328 if (server_address_.secure) {
329 opts |= rtc::PacketSocketFactory::OPT_TLS;
330 }
331 socket_ = socket_factory()->CreateClientTcpSocket(
332 rtc::SocketAddress(ip(), 0), server_address_.address,
333 proxy(), user_agent(), opts);
334 }
335
336 if (!socket_) {
337 error_ = SOCKET_ERROR;
338 return false;
339 }
340
341 // Apply options if any.
342 for (SocketOptionsMap::iterator iter = socket_options_.begin();
343 iter != socket_options_.end(); ++iter) {
344 socket_->SetOption(iter->first, iter->second);
345 }
346
347 if (!SharedSocket()) {
348 // If socket is shared, AllocationSequence will receive the packet.
349 socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
350 }
351
352 socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
353
Stefan Holmer55674ff2016-01-14 15:49:16 +0100354 socket_->SignalSentPacket.connect(this, &TurnPort::OnSentPacket);
355
honghaizb19eba32015-08-03 10:23:31 -0700356 // TCP port is ready to send stun requests after the socket is connected,
357 // while UDP port is ready to do so once the socket is created.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000358 if (server_address_.proto == PROTO_TCP) {
359 socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
360 socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
honghaizb19eba32015-08-03 10:23:31 -0700361 } else {
362 state_ = STATE_CONNECTED;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363 }
364 return true;
365}
366
367void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
368 ASSERT(server_address_.proto == PROTO_TCP);
369 // Do not use this port if the socket bound to a different address than
370 // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
371 // given a binding address, and the platform is expected to pick the
372 // correct local address.
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000373
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700374 // However, there are two situations in which we allow the bound address to
375 // differ from the requested address: 1. The bound address is the loopback
376 // address. This happens when a proxy forces TCP to bind to only the
377 // localhost address (see issue 3927). 2. The bound address is the "any
378 // address". This happens when multiple_routes is disabled (see issue 4780).
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379 if (socket->GetLocalAddress().ipaddr() != ip()) {
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000380 if (socket->GetLocalAddress().IsLoopbackIP()) {
381 LOG(LS_WARNING) << "Socket is bound to a different address:"
382 << socket->GetLocalAddress().ipaddr().ToString()
383 << ", rather then the local port:" << ip().ToString()
384 << ". Still allowing it since it's localhost.";
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700385 } else if (IPIsAny(ip())) {
386 LOG(LS_WARNING) << "Socket is bound to a different address:"
387 << socket->GetLocalAddress().ipaddr().ToString()
388 << ", rather then the local port:" << ip().ToString()
389 << ". Still allowing it since it's any address"
390 << ", possibly caused by multiple_routes being disabled.";
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000391 } else {
392 LOG(LS_WARNING) << "Socket is bound to a different address:"
393 << socket->GetLocalAddress().ipaddr().ToString()
394 << ", rather then the local port:" << ip().ToString()
395 << ". Discarding TURN port.";
396 OnAllocateError();
397 return;
398 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000399 }
400
honghaizb19eba32015-08-03 10:23:31 -0700401 state_ = STATE_CONNECTED; // It is ready to send stun requests.
tfarina20a34612015-11-02 16:20:22 -0800402 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000403 server_address_.address = socket_->GetRemoteAddress();
404 }
405
406 LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
407 << " using tcp.";
408 SendRequest(new TurnAllocateRequest(this), 0);
409}
410
411void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
412 LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +0000413 ASSERT(socket == socket_);
honghaiz6b9ab922016-01-05 09:06:12 -0800414 Close();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000415}
416
417void TurnPort::OnAllocateMismatch() {
418 if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
419 LOG_J(LS_WARNING, this) << "Giving up on the port after "
420 << allocate_mismatch_retries_
421 << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
422 OnAllocateError();
423 return;
424 }
425
426 LOG_J(LS_INFO, this) << "Allocating a new socket after "
427 << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
428 << allocate_mismatch_retries_ + 1;
429 if (SharedSocket()) {
430 ResetSharedSocket();
431 } else {
432 delete socket_;
433 }
434 socket_ = NULL;
435
436 PrepareAddress();
437 ++allocate_mismatch_retries_;
438}
439
440Connection* TurnPort::CreateConnection(const Candidate& address,
441 CandidateOrigin origin) {
442 // TURN-UDP can only connect to UDP candidates.
Honghai Zhangf9945b22015-12-15 12:20:13 -0800443 if (!SupportsProtocol(address.protocol())) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000444 return NULL;
445 }
446
447 if (!IsCompatibleAddress(address.address())) {
448 return NULL;
449 }
450
honghaizb19eba32015-08-03 10:23:31 -0700451 if (state_ == STATE_DISCONNECTED) {
452 return NULL;
453 }
454
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000455 // Create an entry, if needed, so we can get our permissions set up correctly.
honghaiz32f39962015-11-17 11:36:31 -0800456 CreateOrRefreshEntry(address.address());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000457
458 // A TURN port will have two candiates, STUN and TURN. STUN may not
459 // present in all cases. If present stun candidate will be added first
460 // and TURN candidate later.
461 for (size_t index = 0; index < Candidates().size(); ++index) {
462 if (Candidates()[index].type() == RELAY_PORT_TYPE) {
463 ProxyConnection* conn = new ProxyConnection(this, index, address);
464 conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
465 AddConnection(conn);
466 return conn;
467 }
468 }
469 return NULL;
470}
471
Honghai Zhangf67c5482015-12-11 15:16:54 -0800472bool TurnPort::DestroyConnection(const rtc::SocketAddress& address) {
473 Connection* conn = GetConnection(address);
474 if (conn != nullptr) {
475 conn->Destroy();
476 return true;
477 }
478 return false;
479}
480
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000481int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
482 if (!socket_) {
483 // If socket is not created yet, these options will be applied during socket
484 // creation.
485 socket_options_[opt] = value;
486 return 0;
487 }
488 return socket_->SetOption(opt, value);
489}
490
491int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
492 if (!socket_) {
493 SocketOptionsMap::const_iterator it = socket_options_.find(opt);
494 if (it == socket_options_.end()) {
495 return -1;
496 }
497 *value = it->second;
498 return 0;
499 }
500
501 return socket_->GetOption(opt, value);
502}
503
504int TurnPort::GetError() {
505 return error_;
506}
507
508int TurnPort::SendTo(const void* data, size_t size,
509 const rtc::SocketAddress& addr,
510 const rtc::PacketOptions& options,
511 bool payload) {
512 // Try to find an entry for this specific address; we should have one.
513 TurnEntry* entry = FindEntry(addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000514 if (!entry) {
honghaizb19eba32015-08-03 10:23:31 -0700515 LOG(LS_ERROR) << "Did not find the TurnEntry for address " << addr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000516 return 0;
517 }
518
honghaizb19eba32015-08-03 10:23:31 -0700519 if (!ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520 error_ = EWOULDBLOCK;
521 return SOCKET_ERROR;
522 }
523
524 // Send the actual contents to the server using the usual mechanism.
525 int sent = entry->Send(data, size, payload, options);
526 if (sent <= 0) {
527 return SOCKET_ERROR;
528 }
529
530 // The caller of the function is expecting the number of user data bytes,
531 // rather than the size of the packet.
532 return static_cast<int>(size);
533}
534
535void TurnPort::OnReadPacket(
536 rtc::AsyncPacketSocket* socket, const char* data, size_t size,
537 const rtc::SocketAddress& remote_addr,
538 const rtc::PacketTime& packet_time) {
539 ASSERT(socket == socket_);
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000540
541 // This is to guard against a STUN response from previous server after
542 // alternative server redirection. TODO(guoweis): add a unit test for this
543 // race condition.
544 if (remote_addr != server_address_.address) {
545 LOG_J(LS_WARNING, this) << "Discarding TURN message from unknown address:"
546 << remote_addr.ToString()
547 << ", server_address_:"
548 << server_address_.address.ToString();
549 return;
550 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000551
552 // The message must be at least the size of a channel header.
553 if (size < TURN_CHANNEL_HEADER_SIZE) {
554 LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
555 return;
556 }
557
honghaiz9dfed792016-01-29 13:22:31 -0800558 if (state_ == STATE_DISCONNECTED) {
559 LOG_J(LS_WARNING, this)
560 << "Received TURN message while the Turn port is disconnected";
561 return;
562 }
563
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564 // Check the message type, to see if is a Channel Data message.
565 // The message will either be channel data, a TURN data indication, or
566 // a response to a previous request.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200567 uint16_t msg_type = rtc::GetBE16(data);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000568 if (IsTurnChannelData(msg_type)) {
569 HandleChannelData(msg_type, data, size, packet_time);
570 } else if (msg_type == TURN_DATA_INDICATION) {
571 HandleDataIndication(data, size, packet_time);
572 } else {
jiayl@webrtc.org511f8a82014-12-03 02:17:07 +0000573 if (SharedSocket() &&
574 (msg_type == STUN_BINDING_RESPONSE ||
575 msg_type == STUN_BINDING_ERROR_RESPONSE)) {
576 LOG_J(LS_VERBOSE, this) <<
577 "Ignoring STUN binding response message on shared socket.";
578 return;
579 }
580
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000581 // This must be a response for one of our requests.
582 // Check success responses, but not errors, for MESSAGE-INTEGRITY.
583 if (IsStunSuccessResponseType(msg_type) &&
584 !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
585 LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
586 << "message integrity, msg_type=" << msg_type;
587 return;
588 }
589 request_manager_.CheckResponse(data, size);
590 }
591}
592
Stefan Holmer55674ff2016-01-14 15:49:16 +0100593void TurnPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
594 const rtc::SentPacket& sent_packet) {
595 PortInterface::SignalSentPacket(sent_packet);
596}
597
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000598void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
honghaizb19eba32015-08-03 10:23:31 -0700599 if (ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000600 Port::OnReadyToSend();
601 }
602}
603
604
605// Update current server address port with the alternate server address port.
606bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
607 // Check if we have seen this address before and reject if we did.
608 AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
609 if (iter != attempted_server_addresses_.end()) {
610 LOG_J(LS_WARNING, this) << "Redirection to ["
611 << address.ToSensitiveString()
612 << "] ignored, allocation failed.";
613 return false;
614 }
615
616 // If protocol family of server address doesn't match with local, return.
617 if (!IsCompatibleAddress(address)) {
618 LOG(LS_WARNING) << "Server IP address family does not match with "
619 << "local host address family type";
620 return false;
621 }
622
623 LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
624 << server_address_.address.ToSensitiveString()
625 << "] to TURN server ["
626 << address.ToSensitiveString()
627 << "]";
628 server_address_ = ProtocolAddress(address, server_address_.proto,
629 server_address_.secure);
630
631 // Insert the current address to prevent redirection pingpong.
632 attempted_server_addresses_.insert(server_address_.address);
633 return true;
634}
635
636void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
637 if (resolver_)
638 return;
639
Honghai Zhang0f490a52015-12-07 12:06:20 -0800640 LOG_J(LS_INFO, this) << "Starting TURN host lookup for "
641 << address.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000642 resolver_ = socket_factory()->CreateAsyncResolver();
643 resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
644 resolver_->Start(address);
645}
646
647void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
648 ASSERT(resolver == resolver_);
649 // If DNS resolve is failed when trying to connect to the server using TCP,
650 // one of the reason could be due to DNS queries blocked by firewall.
651 // In such cases we will try to connect to the server with hostname, assuming
652 // socket layer will resolve the hostname through a HTTP proxy (if any).
653 if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
654 if (!CreateTurnClientSocket()) {
655 OnAllocateError();
656 }
657 return;
658 }
659
660 // Copy the original server address in |resolved_address|. For TLS based
661 // sockets we need hostname along with resolved address.
662 rtc::SocketAddress resolved_address = server_address_.address;
663 if (resolver_->GetError() != 0 ||
664 !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
665 LOG_J(LS_WARNING, this) << "TURN host lookup received error "
666 << resolver_->GetError();
667 error_ = resolver_->GetError();
668 OnAllocateError();
669 return;
670 }
671 // Signal needs both resolved and unresolved address. After signal is sent
672 // we can copy resolved address back into |server_address_|.
673 SignalResolvedServerAddress(this, server_address_.address,
674 resolved_address);
675 server_address_.address = resolved_address;
676 PrepareAddress();
677}
678
679void TurnPort::OnSendStunPacket(const void* data, size_t size,
680 StunRequest* request) {
honghaizb19eba32015-08-03 10:23:31 -0700681 ASSERT(connected());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682 rtc::PacketOptions options(DefaultDscpValue());
683 if (Send(data, size, options) < 0) {
684 LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
685 << socket_->GetError();
686 }
687}
688
689void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
690 // STUN Port will discover STUN candidate, as it's supplied with first TURN
691 // server address.
692 // Why not using this address? - P2PTransportChannel will start creating
693 // connections after first candidate, which means it could start creating the
694 // connections before TURN candidate added. For that to handle, we need to
695 // supply STUN candidate from this port to UDPPort, and TurnPort should have
696 // handle to UDPPort to pass back the address.
697}
698
699void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
700 const rtc::SocketAddress& stun_address) {
honghaizb19eba32015-08-03 10:23:31 -0700701 state_ = STATE_READY;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000702
703 rtc::SocketAddress related_address = stun_address;
704 if (!(candidate_filter() & CF_REFLEXIVE)) {
705 // If candidate filter only allows relay type of address, empty raddr to
706 // avoid local address leakage.
707 related_address = rtc::EmptySocketAddressWithFamily(stun_address.family());
708 }
709
710 // For relayed candidate, Base is the candidate itself.
711 AddAddress(address, // Candidate address.
712 address, // Base address.
713 related_address, // Related address.
714 UDP_PROTOCOL_NAME,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700715 ProtoToString(server_address_.proto), // The first hop protocol.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000716 "", // TCP canddiate type, empty for turn candidates.
717 RELAY_PORT_TYPE,
718 GetRelayPreference(server_address_.proto, server_address_.secure),
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700719 server_priority_, true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000720}
721
722void TurnPort::OnAllocateError() {
723 // We will send SignalPortError asynchronously as this can be sent during
724 // port initialization. This way it will not be blocking other port
725 // creation.
Honghai Zhangf67c5482015-12-11 15:16:54 -0800726 thread()->Post(this, MSG_ALLOCATE_ERROR);
727}
728
honghaiz6b9ab922016-01-05 09:06:12 -0800729void TurnPort::OnTurnRefreshError() {
730 // Need to Close the port asynchronously because otherwise, the refresh
731 // request may be deleted twice: once at the end of the message processing
732 // and the other in Close().
733 thread()->Post(this, MSG_REFRESH_ERROR);
734}
735
Honghai Zhangf67c5482015-12-11 15:16:54 -0800736void TurnPort::Close() {
honghaiz6b9ab922016-01-05 09:06:12 -0800737 if (!ready()) {
738 OnAllocateError();
739 }
740 request_manager_.Clear();
Honghai Zhangf67c5482015-12-11 15:16:54 -0800741 // Stop the port from creating new connections.
742 state_ = STATE_DISCONNECTED;
743 // Delete all existing connections; stop sending data.
744 for (auto kv : connections()) {
745 kv.second->Destroy();
746 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000747}
748
749void TurnPort::OnMessage(rtc::Message* message) {
Honghai Zhangf67c5482015-12-11 15:16:54 -0800750 switch (message->message_id) {
751 case MSG_ALLOCATE_ERROR:
752 SignalPortError(this);
753 break;
754 case MSG_ALLOCATE_MISMATCH:
755 OnAllocateMismatch();
756 break;
honghaiz6b9ab922016-01-05 09:06:12 -0800757 case MSG_REFRESH_ERROR:
758 Close();
759 break;
Honghai Zhangf67c5482015-12-11 15:16:54 -0800760 case MSG_TRY_ALTERNATE_SERVER:
761 if (server_address().proto == PROTO_UDP) {
762 // Send another allocate request to alternate server, with the received
763 // realm and nonce values.
764 SendRequest(new TurnAllocateRequest(this), 0);
765 } else {
766 // Since it's TCP, we have to delete the connected socket and reconnect
767 // with the alternate server. PrepareAddress will send stun binding once
768 // the new socket is connected.
769 ASSERT(server_address().proto == PROTO_TCP);
770 ASSERT(!SharedSocket());
771 delete socket_;
772 socket_ = NULL;
773 PrepareAddress();
774 }
775 break;
776 default:
777 Port::OnMessage(message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000778 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000779}
780
781void TurnPort::OnAllocateRequestTimeout() {
782 OnAllocateError();
783}
784
785void TurnPort::HandleDataIndication(const char* data, size_t size,
786 const rtc::PacketTime& packet_time) {
787 // Read in the message, and process according to RFC5766, Section 10.4.
788 rtc::ByteBuffer buf(data, size);
789 TurnMessage msg;
790 if (!msg.Read(&buf)) {
791 LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
792 return;
793 }
794
795 // Check mandatory attributes.
796 const StunAddressAttribute* addr_attr =
797 msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
798 if (!addr_attr) {
799 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
800 << "in data indication.";
801 return;
802 }
803
804 const StunByteStringAttribute* data_attr =
805 msg.GetByteString(STUN_ATTR_DATA);
806 if (!data_attr) {
807 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
808 << "data indication.";
809 return;
810 }
811
812 // Verify that the data came from somewhere we think we have a permission for.
813 rtc::SocketAddress ext_addr(addr_attr->GetAddress());
814 if (!HasPermission(ext_addr.ipaddr())) {
815 LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
816 << "peer address, addr="
817 << ext_addr.ToSensitiveString();
818 return;
819 }
820
821 DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
822 PROTO_UDP, packet_time);
823}
824
825void TurnPort::HandleChannelData(int channel_id, const char* data,
826 size_t size,
827 const rtc::PacketTime& packet_time) {
828 // Read the message, and process according to RFC5766, Section 11.6.
829 // 0 1 2 3
830 // 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
831 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
832 // | Channel Number | Length |
833 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
834 // | |
835 // / Application Data /
836 // / /
837 // | |
838 // | +-------------------------------+
839 // | |
840 // +-------------------------------+
841
842 // Extract header fields from the message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200843 uint16_t len = rtc::GetBE16(data + 2);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844 if (len > size - TURN_CHANNEL_HEADER_SIZE) {
845 LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
846 << "incorrect length, len=" << len;
847 return;
848 }
849 // Allowing messages larger than |len|, as ChannelData can be padded.
850
851 TurnEntry* entry = FindEntry(channel_id);
852 if (!entry) {
853 LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
854 << "channel, channel_id=" << channel_id;
855 return;
856 }
857
858 DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
859 PROTO_UDP, packet_time);
860}
861
862void TurnPort::DispatchPacket(const char* data, size_t size,
863 const rtc::SocketAddress& remote_addr,
864 ProtocolType proto, const rtc::PacketTime& packet_time) {
865 if (Connection* conn = GetConnection(remote_addr)) {
866 conn->OnReadPacket(data, size, packet_time);
867 } else {
868 Port::OnReadPacket(data, size, remote_addr, proto);
869 }
870}
871
872bool TurnPort::ScheduleRefresh(int lifetime) {
873 // Lifetime is in seconds; we schedule a refresh for one minute less.
874 if (lifetime < 2 * 60) {
875 LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
876 << "too short, lifetime=" << lifetime;
877 return false;
878 }
879
Peter Thatcherb32a5c42015-04-10 14:04:42 -0700880 int delay = (lifetime - 60) * 1000;
881 SendRequest(new TurnRefreshRequest(this), delay);
882 LOG_J(LS_INFO, this) << "Scheduled refresh in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000883 return true;
884}
885
886void TurnPort::SendRequest(StunRequest* req, int delay) {
887 request_manager_.SendDelayed(req, delay);
888}
889
890void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
891 // If we've gotten the necessary data from the server, add it to our request.
892 VERIFY(!hash_.empty());
893 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
894 STUN_ATTR_USERNAME, credentials_.username)));
895 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
896 STUN_ATTR_REALM, realm_)));
897 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
898 STUN_ATTR_NONCE, nonce_)));
899 VERIFY(msg->AddMessageIntegrity(hash()));
900}
901
902int TurnPort::Send(const void* data, size_t len,
903 const rtc::PacketOptions& options) {
904 return socket_->SendTo(data, len, server_address_.address, options);
905}
906
907void TurnPort::UpdateHash() {
908 VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
909 credentials_.password, &hash_));
910}
911
912bool TurnPort::UpdateNonce(StunMessage* response) {
913 // When stale nonce error received, we should update
914 // hash and store realm and nonce.
915 // Check the mandatory attributes.
916 const StunByteStringAttribute* realm_attr =
917 response->GetByteString(STUN_ATTR_REALM);
918 if (!realm_attr) {
919 LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
920 << "stale nonce error response.";
921 return false;
922 }
923 set_realm(realm_attr->GetString());
924
925 const StunByteStringAttribute* nonce_attr =
926 response->GetByteString(STUN_ATTR_NONCE);
927 if (!nonce_attr) {
928 LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
929 << "stale nonce error response.";
930 return false;
931 }
932 set_nonce(nonce_attr->GetString());
933 return true;
934}
935
936static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
937 return e->address().ipaddr() == ipaddr;
938}
939bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
940 return (std::find_if(entries_.begin(), entries_.end(),
941 std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
942}
943
944static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
945 return e->address() == addr;
946}
947TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
948 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
949 std::bind2nd(std::ptr_fun(MatchesAddress), addr));
950 return (it != entries_.end()) ? *it : NULL;
951}
952
953static bool MatchesChannelId(TurnEntry* e, int id) {
954 return e->channel_id() == id;
955}
956TurnEntry* TurnPort::FindEntry(int channel_id) const {
957 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
958 std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
959 return (it != entries_.end()) ? *it : NULL;
960}
961
honghaizc3e0fe72015-12-02 16:43:25 -0800962bool TurnPort::EntryExists(TurnEntry* e) {
963 auto it = std::find(entries_.begin(), entries_.end(), e);
964 return it != entries_.end();
965}
966
honghaiz32f39962015-11-17 11:36:31 -0800967void TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) {
968 TurnEntry* entry = FindEntry(addr);
969 if (entry == nullptr) {
970 entry = new TurnEntry(this, next_channel_number_++, addr);
971 entries_.push_back(entry);
972 } else {
973 // The channel binding request for the entry will be refreshed automatically
974 // until the entry is destroyed.
975 CancelEntryDestruction(entry);
976 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000977}
978
honghaiz32f39962015-11-17 11:36:31 -0800979void TurnPort::DestroyEntry(TurnEntry* entry) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980 ASSERT(entry != NULL);
981 entry->SignalDestroyed(entry);
982 entries_.remove(entry);
983 delete entry;
984}
985
honghaiz32f39962015-11-17 11:36:31 -0800986void TurnPort::DestroyEntryIfNotCancelled(TurnEntry* entry,
987 uint32_t timestamp) {
honghaizc3e0fe72015-12-02 16:43:25 -0800988 if (!EntryExists(entry)) {
989 return;
990 }
honghaiz32f39962015-11-17 11:36:31 -0800991 bool cancelled = timestamp != entry->destruction_timestamp();
992 if (!cancelled) {
993 DestroyEntry(entry);
994 }
995}
996
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000997void TurnPort::OnConnectionDestroyed(Connection* conn) {
honghaiz32f39962015-11-17 11:36:31 -0800998 // Schedule an event to destroy TurnEntry for the connection, which is
999 // already destroyed.
1000 const rtc::SocketAddress& remote_address = conn->remote_candidate().address();
1001 TurnEntry* entry = FindEntry(remote_address);
1002 ASSERT(entry != NULL);
1003 ScheduleEntryDestruction(entry);
1004}
1005
1006void TurnPort::ScheduleEntryDestruction(TurnEntry* entry) {
1007 ASSERT(entry->destruction_timestamp() == 0);
1008 uint32_t timestamp = rtc::Time();
1009 entry->set_destruction_timestamp(timestamp);
1010 invoker_.AsyncInvokeDelayed<void>(
1011 thread(),
1012 rtc::Bind(&TurnPort::DestroyEntryIfNotCancelled, this, entry, timestamp),
1013 TURN_PERMISSION_TIMEOUT);
1014}
1015
1016void TurnPort::CancelEntryDestruction(TurnEntry* entry) {
1017 ASSERT(entry->destruction_timestamp() != 0);
1018 entry->set_destruction_timestamp(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001019}
1020
Honghai Zhangf67c5482015-12-11 15:16:54 -08001021bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address,
1022 int channel_id) {
1023 TurnEntry* entry = FindEntry(address);
1024 if (!entry) {
1025 return false;
1026 }
1027 entry->set_channel_id(channel_id);
1028 return true;
1029}
1030
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001031TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
1032 : StunRequest(new TurnMessage()),
1033 port_(port) {
1034}
1035
1036void TurnAllocateRequest::Prepare(StunMessage* request) {
1037 // Create the request as indicated in RFC 5766, Section 6.1.
1038 request->SetType(TURN_ALLOCATE_REQUEST);
1039 StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
1040 STUN_ATTR_REQUESTED_TRANSPORT);
1041 transport_attr->SetValue(IPPROTO_UDP << 24);
1042 VERIFY(request->AddAttribute(transport_attr));
1043 if (!port_->hash().empty()) {
1044 port_->AddRequestAuthInfo(request);
1045 }
1046}
1047
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001048void TurnAllocateRequest::OnSent() {
1049 LOG_J(LS_INFO, port_) << "TURN allocate request sent"
1050 << ", id=" << rtc::hex_encode(id());
1051 StunRequest::OnSent();
1052}
1053
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001054void TurnAllocateRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001055 LOG_J(LS_INFO, port_) << "TURN allocate requested successfully"
1056 << ", id=" << rtc::hex_encode(id())
1057 << ", code=0" // Makes logging easier to parse.
1058 << ", rtt=" << Elapsed();
1059
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001060 // Check mandatory attributes as indicated in RFC5766, Section 6.3.
1061 const StunAddressAttribute* mapped_attr =
1062 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1063 if (!mapped_attr) {
1064 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
1065 << "attribute in allocate success response";
1066 return;
1067 }
1068 // Using XOR-Mapped-Address for stun.
1069 port_->OnStunAddress(mapped_attr->GetAddress());
1070
1071 const StunAddressAttribute* relayed_attr =
1072 response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
1073 if (!relayed_attr) {
1074 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
1075 << "attribute in allocate success response";
1076 return;
1077 }
1078
1079 const StunUInt32Attribute* lifetime_attr =
1080 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1081 if (!lifetime_attr) {
1082 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1083 << "allocate success response";
1084 return;
1085 }
1086 // Notify the port the allocate succeeded, and schedule a refresh request.
1087 port_->OnAllocateSuccess(relayed_attr->GetAddress(),
1088 mapped_attr->GetAddress());
1089 port_->ScheduleRefresh(lifetime_attr->value());
1090}
1091
1092void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
1093 // Process error response according to RFC5766, Section 6.4.
1094 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001095
1096 LOG_J(LS_INFO, port_) << "Received TURN allocate error response"
1097 << ", id=" << rtc::hex_encode(id())
1098 << ", code=" << error_code->code()
1099 << ", rtt=" << Elapsed();
1100
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001101 switch (error_code->code()) {
1102 case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
1103 OnAuthChallenge(response, error_code->code());
1104 break;
1105 case STUN_ERROR_TRY_ALTERNATE:
1106 OnTryAlternate(response, error_code->code());
1107 break;
1108 case STUN_ERROR_ALLOCATION_MISMATCH:
1109 // We must handle this error async because trying to delete the socket in
1110 // OnErrorResponse will cause a deadlock on the socket.
1111 port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH);
1112 break;
1113 default:
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001114 LOG_J(LS_WARNING, port_) << "Received TURN allocate error response"
1115 << ", id=" << rtc::hex_encode(id())
1116 << ", code=" << error_code->code()
1117 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001118 port_->OnAllocateError();
1119 }
1120}
1121
1122void TurnAllocateRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001123 LOG_J(LS_WARNING, port_) << "TURN allocate request "
1124 << rtc::hex_encode(id()) << " timout";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001125 port_->OnAllocateRequestTimeout();
1126}
1127
1128void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
1129 // If we failed to authenticate even after we sent our credentials, fail hard.
1130 if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
1131 LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
1132 << "after challenge.";
1133 port_->OnAllocateError();
1134 return;
1135 }
1136
1137 // Check the mandatory attributes.
1138 const StunByteStringAttribute* realm_attr =
1139 response->GetByteString(STUN_ATTR_REALM);
1140 if (!realm_attr) {
1141 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
1142 << "allocate unauthorized response.";
1143 return;
1144 }
1145 port_->set_realm(realm_attr->GetString());
1146
1147 const StunByteStringAttribute* nonce_attr =
1148 response->GetByteString(STUN_ATTR_NONCE);
1149 if (!nonce_attr) {
1150 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
1151 << "allocate unauthorized response.";
1152 return;
1153 }
1154 port_->set_nonce(nonce_attr->GetString());
1155
1156 // Send another allocate request, with the received realm and nonce values.
1157 port_->SendRequest(new TurnAllocateRequest(port_), 0);
1158}
1159
1160void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001161
1162 // According to RFC 5389 section 11, there are use cases where
1163 // authentication of response is not possible, we're not validating
1164 // message integrity.
1165
1166 // Get the alternate server address attribute value.
1167 const StunAddressAttribute* alternate_server_attr =
1168 response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1169 if (!alternate_server_attr) {
1170 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
1171 << "attribute in try alternate error response";
1172 port_->OnAllocateError();
1173 return;
1174 }
1175 if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1176 port_->OnAllocateError();
1177 return;
1178 }
1179
1180 // Check the attributes.
1181 const StunByteStringAttribute* realm_attr =
1182 response->GetByteString(STUN_ATTR_REALM);
1183 if (realm_attr) {
1184 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
1185 << "try alternate error response.";
1186 port_->set_realm(realm_attr->GetString());
1187 }
1188
1189 const StunByteStringAttribute* nonce_attr =
1190 response->GetByteString(STUN_ATTR_NONCE);
1191 if (nonce_attr) {
1192 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
1193 << "try alternate error response.";
1194 port_->set_nonce(nonce_attr->GetString());
1195 }
1196
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +00001197 // For TCP, we can't close the original Tcp socket during handling a 300 as
1198 // we're still inside that socket's event handler. Doing so will cause
1199 // deadlock.
1200 port_->thread()->Post(port_, TurnPort::MSG_TRY_ALTERNATE_SERVER);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001201}
1202
1203TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
1204 : StunRequest(new TurnMessage()),
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001205 port_(port),
1206 lifetime_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001207}
1208
1209void TurnRefreshRequest::Prepare(StunMessage* request) {
1210 // Create the request as indicated in RFC 5766, Section 7.1.
1211 // No attributes need to be included.
1212 request->SetType(TURN_REFRESH_REQUEST);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001213 if (lifetime_ > -1) {
1214 VERIFY(request->AddAttribute(new StunUInt32Attribute(
1215 STUN_ATTR_LIFETIME, lifetime_)));
1216 }
1217
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001218 port_->AddRequestAuthInfo(request);
1219}
1220
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001221void TurnRefreshRequest::OnSent() {
1222 LOG_J(LS_INFO, port_) << "TURN refresh request sent"
1223 << ", id=" << rtc::hex_encode(id());
1224 StunRequest::OnSent();
1225}
1226
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001227void TurnRefreshRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001228 LOG_J(LS_INFO, port_) << "TURN refresh requested successfully"
1229 << ", id=" << rtc::hex_encode(id())
1230 << ", code=0" // Makes logging easier to parse.
1231 << ", rtt=" << Elapsed();
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001232
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001233 // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1234 const StunUInt32Attribute* lifetime_attr =
1235 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1236 if (!lifetime_attr) {
1237 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1238 << "refresh success response.";
1239 return;
1240 }
1241
1242 // Schedule a refresh based on the returned lifetime value.
1243 port_->ScheduleRefresh(lifetime_attr->value());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001244 port_->SignalTurnRefreshResult(port_, TURN_SUCCESS_RESULT_CODE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001245}
1246
1247void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
1248 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001249
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001250 if (error_code->code() == STUN_ERROR_STALE_NONCE) {
1251 if (port_->UpdateNonce(response)) {
1252 // Send RefreshRequest immediately.
1253 port_->SendRequest(new TurnRefreshRequest(port_), 0);
1254 }
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001255 } else {
1256 LOG_J(LS_WARNING, port_) << "Received TURN refresh error response"
1257 << ", id=" << rtc::hex_encode(id())
1258 << ", code=" << error_code->code()
1259 << ", rtt=" << Elapsed();
Honghai Zhangf67c5482015-12-11 15:16:54 -08001260 port_->OnTurnRefreshError();
1261 port_->SignalTurnRefreshResult(port_, error_code->code());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001262 }
1263}
1264
1265void TurnRefreshRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001266 LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001267 port_->OnTurnRefreshError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001268}
1269
1270TurnCreatePermissionRequest::TurnCreatePermissionRequest(
1271 TurnPort* port, TurnEntry* entry,
1272 const rtc::SocketAddress& ext_addr)
1273 : StunRequest(new TurnMessage()),
1274 port_(port),
1275 entry_(entry),
1276 ext_addr_(ext_addr) {
1277 entry_->SignalDestroyed.connect(
1278 this, &TurnCreatePermissionRequest::OnEntryDestroyed);
1279}
1280
1281void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
1282 // Create the request as indicated in RFC5766, Section 9.1.
1283 request->SetType(TURN_CREATE_PERMISSION_REQUEST);
1284 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1285 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1286 port_->AddRequestAuthInfo(request);
1287}
1288
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001289void TurnCreatePermissionRequest::OnSent() {
1290 LOG_J(LS_INFO, port_) << "TURN create permission request sent"
1291 << ", id=" << rtc::hex_encode(id());
1292 StunRequest::OnSent();
1293}
1294
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001295void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001296 LOG_J(LS_INFO, port_) << "TURN permission requested successfully"
1297 << ", id=" << rtc::hex_encode(id())
1298 << ", code=0" // Makes logging easier to parse.
1299 << ", rtt=" << Elapsed();
1300
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001301 if (entry_) {
1302 entry_->OnCreatePermissionSuccess();
1303 }
1304}
1305
1306void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001307 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001308 LOG_J(LS_WARNING, port_) << "Received TURN create permission error response"
1309 << ", id=" << rtc::hex_encode(id())
1310 << ", code=" << error_code->code()
1311 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001312 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001313 entry_->OnCreatePermissionError(response, error_code->code());
1314 }
1315}
1316
1317void TurnCreatePermissionRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001318 LOG_J(LS_WARNING, port_) << "TURN create permission timeout "
1319 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001320 if (entry_) {
1321 entry_->OnCreatePermissionTimeout();
1322 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001323}
1324
1325void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
1326 ASSERT(entry_ == entry);
1327 entry_ = NULL;
1328}
1329
1330TurnChannelBindRequest::TurnChannelBindRequest(
1331 TurnPort* port, TurnEntry* entry,
1332 int channel_id, const rtc::SocketAddress& ext_addr)
1333 : StunRequest(new TurnMessage()),
1334 port_(port),
1335 entry_(entry),
1336 channel_id_(channel_id),
1337 ext_addr_(ext_addr) {
1338 entry_->SignalDestroyed.connect(
1339 this, &TurnChannelBindRequest::OnEntryDestroyed);
1340}
1341
1342void TurnChannelBindRequest::Prepare(StunMessage* request) {
1343 // Create the request as indicated in RFC5766, Section 11.1.
1344 request->SetType(TURN_CHANNEL_BIND_REQUEST);
1345 VERIFY(request->AddAttribute(new StunUInt32Attribute(
1346 STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)));
1347 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1348 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1349 port_->AddRequestAuthInfo(request);
1350}
1351
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001352void TurnChannelBindRequest::OnSent() {
1353 LOG_J(LS_INFO, port_) << "TURN channel bind request sent"
1354 << ", id=" << rtc::hex_encode(id());
1355 StunRequest::OnSent();
1356}
1357
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001358void TurnChannelBindRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001359 LOG_J(LS_INFO, port_) << "TURN channel bind requested successfully"
1360 << ", id=" << rtc::hex_encode(id())
1361 << ", code=0" // Makes logging easier to parse.
1362 << ", rtt=" << Elapsed();
1363
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001364 if (entry_) {
1365 entry_->OnChannelBindSuccess();
1366 // Refresh the channel binding just under the permission timeout
1367 // threshold. The channel binding has a longer lifetime, but
1368 // this is the easiest way to keep both the channel and the
1369 // permission from expiring.
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001370 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1371 entry_->SendChannelBindRequest(delay);
1372 LOG_J(LS_INFO, port_) << "Scheduled channel bind in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001373 }
1374}
1375
1376void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001377 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
1378 LOG_J(LS_WARNING, port_) << "Received TURN channel bind error response"
1379 << ", id=" << rtc::hex_encode(id())
1380 << ", code=" << error_code->code()
1381 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001382 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001383 entry_->OnChannelBindError(response, error_code->code());
1384 }
1385}
1386
1387void TurnChannelBindRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001388 LOG_J(LS_WARNING, port_) << "TURN channel bind timeout "
1389 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001390 if (entry_) {
1391 entry_->OnChannelBindTimeout();
1392 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001393}
1394
1395void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
1396 ASSERT(entry_ == entry);
1397 entry_ = NULL;
1398}
1399
1400TurnEntry::TurnEntry(TurnPort* port, int channel_id,
1401 const rtc::SocketAddress& ext_addr)
1402 : port_(port),
1403 channel_id_(channel_id),
1404 ext_addr_(ext_addr),
1405 state_(STATE_UNBOUND) {
1406 // Creating permission for |ext_addr_|.
Honghai Zhang85975432015-11-12 11:07:12 -08001407 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001408}
1409
Honghai Zhang85975432015-11-12 11:07:12 -08001410void TurnEntry::SendCreatePermissionRequest(int delay) {
1411 port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
1412 delay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001413}
1414
1415void TurnEntry::SendChannelBindRequest(int delay) {
1416 port_->SendRequest(new TurnChannelBindRequest(
1417 port_, this, channel_id_, ext_addr_), delay);
1418}
1419
1420int TurnEntry::Send(const void* data, size_t size, bool payload,
1421 const rtc::PacketOptions& options) {
1422 rtc::ByteBuffer buf;
1423 if (state_ != STATE_BOUND) {
1424 // If we haven't bound the channel yet, we have to use a Send Indication.
1425 TurnMessage msg;
1426 msg.SetType(TURN_SEND_INDICATION);
1427 msg.SetTransactionID(
1428 rtc::CreateRandomString(kStunTransactionIdLength));
1429 VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
1430 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1431 VERIFY(msg.AddAttribute(new StunByteStringAttribute(
1432 STUN_ATTR_DATA, data, size)));
1433 VERIFY(msg.Write(&buf));
1434
1435 // If we're sending real data, request a channel bind that we can use later.
1436 if (state_ == STATE_UNBOUND && payload) {
1437 SendChannelBindRequest(0);
1438 state_ = STATE_BINDING;
1439 }
1440 } else {
1441 // If the channel is bound, we can send the data as a Channel Message.
1442 buf.WriteUInt16(channel_id_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001443 buf.WriteUInt16(static_cast<uint16_t>(size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001444 buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1445 }
1446 return port_->Send(buf.Data(), buf.Length(), options);
1447}
1448
1449void TurnEntry::OnCreatePermissionSuccess() {
1450 LOG_J(LS_INFO, port_) << "Create permission for "
1451 << ext_addr_.ToSensitiveString()
1452 << " succeeded";
Honghai Zhangf67c5482015-12-11 15:16:54 -08001453 port_->SignalCreatePermissionResult(port_, ext_addr_,
1454 TURN_SUCCESS_RESULT_CODE);
Honghai Zhang85975432015-11-12 11:07:12 -08001455
1456 // If |state_| is STATE_BOUND, the permission will be refreshed
1457 // by ChannelBindRequest.
1458 if (state_ != STATE_BOUND) {
1459 // Refresh the permission request about 1 minute before the permission
1460 // times out.
1461 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1462 SendCreatePermissionRequest(delay);
1463 LOG_J(LS_INFO, port_) << "Scheduled create-permission-request in "
1464 << delay << "ms.";
1465 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001466}
1467
1468void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001469 if (code == STUN_ERROR_STALE_NONCE) {
1470 if (port_->UpdateNonce(response)) {
Honghai Zhang85975432015-11-12 11:07:12 -08001471 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001472 }
1473 } else {
Honghai Zhangf67c5482015-12-11 15:16:54 -08001474 port_->DestroyConnection(ext_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001475 // Send signal with error code.
1476 port_->SignalCreatePermissionResult(port_, ext_addr_, code);
deadbeef376e1232015-11-25 09:00:08 -08001477 Connection* c = port_->GetConnection(ext_addr_);
1478 if (c) {
1479 LOG_J(LS_ERROR, c) << "Received TURN CreatePermission error response, "
1480 << "code=" << code << "; killing connection.";
1481 c->FailAndDestroy();
1482 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001483 }
1484}
1485
Honghai Zhangf67c5482015-12-11 15:16:54 -08001486void TurnEntry::OnCreatePermissionTimeout() {
1487 port_->DestroyConnection(ext_addr_);
1488}
1489
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001490void TurnEntry::OnChannelBindSuccess() {
1491 LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
1492 << " succeeded";
1493 ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND);
1494 state_ = STATE_BOUND;
1495}
1496
1497void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
Honghai Zhangf67c5482015-12-11 15:16:54 -08001498 // If the channel bind fails due to errors other than STATE_NONCE,
1499 // we just destroy the connection and rely on ICE restart to re-establish
1500 // the connection.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001501 if (code == STUN_ERROR_STALE_NONCE) {
1502 if (port_->UpdateNonce(response)) {
1503 // Send channel bind request with fresh nonce.
1504 SendChannelBindRequest(0);
1505 }
Honghai Zhangf67c5482015-12-11 15:16:54 -08001506 } else {
1507 state_ = STATE_UNBOUND;
1508 port_->DestroyConnection(ext_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001509 }
1510}
Honghai Zhangf67c5482015-12-11 15:16:54 -08001511void TurnEntry::OnChannelBindTimeout() {
1512 state_ = STATE_UNBOUND;
1513 port_->DestroyConnection(ext_addr_);
1514}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001515} // namespace cricket