blob: 55b3b9479c26cee120055e85ff333219548b2d79 [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
honghaizb19eba32015-08-03 10:23:31 -0700354 // TCP port is ready to send stun requests after the socket is connected,
355 // while UDP port is ready to do so once the socket is created.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000356 if (server_address_.proto == PROTO_TCP) {
357 socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
358 socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
honghaizb19eba32015-08-03 10:23:31 -0700359 } else {
360 state_ = STATE_CONNECTED;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000361 }
362 return true;
363}
364
365void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
366 ASSERT(server_address_.proto == PROTO_TCP);
367 // Do not use this port if the socket bound to a different address than
368 // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
369 // given a binding address, and the platform is expected to pick the
370 // correct local address.
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000371
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700372 // However, there are two situations in which we allow the bound address to
373 // differ from the requested address: 1. The bound address is the loopback
374 // address. This happens when a proxy forces TCP to bind to only the
375 // localhost address (see issue 3927). 2. The bound address is the "any
376 // address". This happens when multiple_routes is disabled (see issue 4780).
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000377 if (socket->GetLocalAddress().ipaddr() != ip()) {
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000378 if (socket->GetLocalAddress().IsLoopbackIP()) {
379 LOG(LS_WARNING) << "Socket is bound to a different address:"
380 << socket->GetLocalAddress().ipaddr().ToString()
381 << ", rather then the local port:" << ip().ToString()
382 << ". Still allowing it since it's localhost.";
Guo-wei Shieh7f04b082015-06-19 11:27:08 -0700383 } else if (IPIsAny(ip())) {
384 LOG(LS_WARNING) << "Socket is bound to a different address:"
385 << socket->GetLocalAddress().ipaddr().ToString()
386 << ", rather then the local port:" << ip().ToString()
387 << ". Still allowing it since it's any address"
388 << ", possibly caused by multiple_routes being disabled.";
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000389 } else {
390 LOG(LS_WARNING) << "Socket is bound to a different address:"
391 << socket->GetLocalAddress().ipaddr().ToString()
392 << ", rather then the local port:" << ip().ToString()
393 << ". Discarding TURN port.";
394 OnAllocateError();
395 return;
396 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000397 }
398
honghaizb19eba32015-08-03 10:23:31 -0700399 state_ = STATE_CONNECTED; // It is ready to send stun requests.
tfarina20a34612015-11-02 16:20:22 -0800400 if (server_address_.address.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000401 server_address_.address = socket_->GetRemoteAddress();
402 }
403
404 LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
405 << " using tcp.";
406 SendRequest(new TurnAllocateRequest(this), 0);
407}
408
409void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
410 LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +0000411 ASSERT(socket == socket_);
honghaizb19eba32015-08-03 10:23:31 -0700412 if (!ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 OnAllocateError();
414 }
honghaizb19eba32015-08-03 10:23:31 -0700415 request_manager_.Clear();
416 state_ = STATE_DISCONNECTED;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000417}
418
419void TurnPort::OnAllocateMismatch() {
420 if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
421 LOG_J(LS_WARNING, this) << "Giving up on the port after "
422 << allocate_mismatch_retries_
423 << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
424 OnAllocateError();
425 return;
426 }
427
428 LOG_J(LS_INFO, this) << "Allocating a new socket after "
429 << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
430 << allocate_mismatch_retries_ + 1;
431 if (SharedSocket()) {
432 ResetSharedSocket();
433 } else {
434 delete socket_;
435 }
436 socket_ = NULL;
437
438 PrepareAddress();
439 ++allocate_mismatch_retries_;
440}
441
442Connection* TurnPort::CreateConnection(const Candidate& address,
443 CandidateOrigin origin) {
444 // TURN-UDP can only connect to UDP candidates.
445 if (address.protocol() != UDP_PROTOCOL_NAME) {
446 return NULL;
447 }
448
449 if (!IsCompatibleAddress(address.address())) {
450 return NULL;
451 }
452
honghaizb19eba32015-08-03 10:23:31 -0700453 if (state_ == STATE_DISCONNECTED) {
454 return NULL;
455 }
456
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000457 // Create an entry, if needed, so we can get our permissions set up correctly.
honghaiz32f39962015-11-17 11:36:31 -0800458 CreateOrRefreshEntry(address.address());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000459
460 // A TURN port will have two candiates, STUN and TURN. STUN may not
461 // present in all cases. If present stun candidate will be added first
462 // and TURN candidate later.
463 for (size_t index = 0; index < Candidates().size(); ++index) {
464 if (Candidates()[index].type() == RELAY_PORT_TYPE) {
465 ProxyConnection* conn = new ProxyConnection(this, index, address);
466 conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
467 AddConnection(conn);
468 return conn;
469 }
470 }
471 return NULL;
472}
473
Honghai Zhangf67c5482015-12-11 15:16:54 -0800474bool TurnPort::DestroyConnection(const rtc::SocketAddress& address) {
475 Connection* conn = GetConnection(address);
476 if (conn != nullptr) {
477 conn->Destroy();
478 return true;
479 }
480 return false;
481}
482
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
484 if (!socket_) {
485 // If socket is not created yet, these options will be applied during socket
486 // creation.
487 socket_options_[opt] = value;
488 return 0;
489 }
490 return socket_->SetOption(opt, value);
491}
492
493int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
494 if (!socket_) {
495 SocketOptionsMap::const_iterator it = socket_options_.find(opt);
496 if (it == socket_options_.end()) {
497 return -1;
498 }
499 *value = it->second;
500 return 0;
501 }
502
503 return socket_->GetOption(opt, value);
504}
505
506int TurnPort::GetError() {
507 return error_;
508}
509
510int TurnPort::SendTo(const void* data, size_t size,
511 const rtc::SocketAddress& addr,
512 const rtc::PacketOptions& options,
513 bool payload) {
514 // Try to find an entry for this specific address; we should have one.
515 TurnEntry* entry = FindEntry(addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000516 if (!entry) {
honghaizb19eba32015-08-03 10:23:31 -0700517 LOG(LS_ERROR) << "Did not find the TurnEntry for address " << addr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000518 return 0;
519 }
520
honghaizb19eba32015-08-03 10:23:31 -0700521 if (!ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000522 error_ = EWOULDBLOCK;
523 return SOCKET_ERROR;
524 }
525
526 // Send the actual contents to the server using the usual mechanism.
527 int sent = entry->Send(data, size, payload, options);
528 if (sent <= 0) {
529 return SOCKET_ERROR;
530 }
531
532 // The caller of the function is expecting the number of user data bytes,
533 // rather than the size of the packet.
534 return static_cast<int>(size);
535}
536
537void TurnPort::OnReadPacket(
538 rtc::AsyncPacketSocket* socket, const char* data, size_t size,
539 const rtc::SocketAddress& remote_addr,
540 const rtc::PacketTime& packet_time) {
541 ASSERT(socket == socket_);
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000542
543 // This is to guard against a STUN response from previous server after
544 // alternative server redirection. TODO(guoweis): add a unit test for this
545 // race condition.
546 if (remote_addr != server_address_.address) {
547 LOG_J(LS_WARNING, this) << "Discarding TURN message from unknown address:"
548 << remote_addr.ToString()
549 << ", server_address_:"
550 << server_address_.address.ToString();
551 return;
552 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000553
554 // The message must be at least the size of a channel header.
555 if (size < TURN_CHANNEL_HEADER_SIZE) {
556 LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
557 return;
558 }
559
560 // Check the message type, to see if is a Channel Data message.
561 // The message will either be channel data, a TURN data indication, or
562 // a response to a previous request.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200563 uint16_t msg_type = rtc::GetBE16(data);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564 if (IsTurnChannelData(msg_type)) {
565 HandleChannelData(msg_type, data, size, packet_time);
566 } else if (msg_type == TURN_DATA_INDICATION) {
567 HandleDataIndication(data, size, packet_time);
568 } else {
jiayl@webrtc.org511f8a82014-12-03 02:17:07 +0000569 if (SharedSocket() &&
570 (msg_type == STUN_BINDING_RESPONSE ||
571 msg_type == STUN_BINDING_ERROR_RESPONSE)) {
572 LOG_J(LS_VERBOSE, this) <<
573 "Ignoring STUN binding response message on shared socket.";
574 return;
575 }
576
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000577 // This must be a response for one of our requests.
578 // Check success responses, but not errors, for MESSAGE-INTEGRITY.
579 if (IsStunSuccessResponseType(msg_type) &&
580 !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
581 LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
582 << "message integrity, msg_type=" << msg_type;
583 return;
584 }
585 request_manager_.CheckResponse(data, size);
586 }
587}
588
589void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
honghaizb19eba32015-08-03 10:23:31 -0700590 if (ready()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591 Port::OnReadyToSend();
592 }
593}
594
595
596// Update current server address port with the alternate server address port.
597bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
598 // Check if we have seen this address before and reject if we did.
599 AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
600 if (iter != attempted_server_addresses_.end()) {
601 LOG_J(LS_WARNING, this) << "Redirection to ["
602 << address.ToSensitiveString()
603 << "] ignored, allocation failed.";
604 return false;
605 }
606
607 // If protocol family of server address doesn't match with local, return.
608 if (!IsCompatibleAddress(address)) {
609 LOG(LS_WARNING) << "Server IP address family does not match with "
610 << "local host address family type";
611 return false;
612 }
613
614 LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
615 << server_address_.address.ToSensitiveString()
616 << "] to TURN server ["
617 << address.ToSensitiveString()
618 << "]";
619 server_address_ = ProtocolAddress(address, server_address_.proto,
620 server_address_.secure);
621
622 // Insert the current address to prevent redirection pingpong.
623 attempted_server_addresses_.insert(server_address_.address);
624 return true;
625}
626
627void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
628 if (resolver_)
629 return;
630
Honghai Zhang0f490a52015-12-07 12:06:20 -0800631 LOG_J(LS_INFO, this) << "Starting TURN host lookup for "
632 << address.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000633 resolver_ = socket_factory()->CreateAsyncResolver();
634 resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
635 resolver_->Start(address);
636}
637
638void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
639 ASSERT(resolver == resolver_);
640 // If DNS resolve is failed when trying to connect to the server using TCP,
641 // one of the reason could be due to DNS queries blocked by firewall.
642 // In such cases we will try to connect to the server with hostname, assuming
643 // socket layer will resolve the hostname through a HTTP proxy (if any).
644 if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
645 if (!CreateTurnClientSocket()) {
646 OnAllocateError();
647 }
648 return;
649 }
650
651 // Copy the original server address in |resolved_address|. For TLS based
652 // sockets we need hostname along with resolved address.
653 rtc::SocketAddress resolved_address = server_address_.address;
654 if (resolver_->GetError() != 0 ||
655 !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
656 LOG_J(LS_WARNING, this) << "TURN host lookup received error "
657 << resolver_->GetError();
658 error_ = resolver_->GetError();
659 OnAllocateError();
660 return;
661 }
662 // Signal needs both resolved and unresolved address. After signal is sent
663 // we can copy resolved address back into |server_address_|.
664 SignalResolvedServerAddress(this, server_address_.address,
665 resolved_address);
666 server_address_.address = resolved_address;
667 PrepareAddress();
668}
669
670void TurnPort::OnSendStunPacket(const void* data, size_t size,
671 StunRequest* request) {
honghaizb19eba32015-08-03 10:23:31 -0700672 ASSERT(connected());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000673 rtc::PacketOptions options(DefaultDscpValue());
674 if (Send(data, size, options) < 0) {
675 LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
676 << socket_->GetError();
677 }
678}
679
680void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
681 // STUN Port will discover STUN candidate, as it's supplied with first TURN
682 // server address.
683 // Why not using this address? - P2PTransportChannel will start creating
684 // connections after first candidate, which means it could start creating the
685 // connections before TURN candidate added. For that to handle, we need to
686 // supply STUN candidate from this port to UDPPort, and TurnPort should have
687 // handle to UDPPort to pass back the address.
688}
689
690void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
691 const rtc::SocketAddress& stun_address) {
honghaizb19eba32015-08-03 10:23:31 -0700692 state_ = STATE_READY;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693
694 rtc::SocketAddress related_address = stun_address;
695 if (!(candidate_filter() & CF_REFLEXIVE)) {
696 // If candidate filter only allows relay type of address, empty raddr to
697 // avoid local address leakage.
698 related_address = rtc::EmptySocketAddressWithFamily(stun_address.family());
699 }
700
701 // For relayed candidate, Base is the candidate itself.
702 AddAddress(address, // Candidate address.
703 address, // Base address.
704 related_address, // Related address.
705 UDP_PROTOCOL_NAME,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700706 ProtoToString(server_address_.proto), // The first hop protocol.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000707 "", // TCP canddiate type, empty for turn candidates.
708 RELAY_PORT_TYPE,
709 GetRelayPreference(server_address_.proto, server_address_.secure),
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700710 server_priority_, true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000711}
712
713void TurnPort::OnAllocateError() {
714 // We will send SignalPortError asynchronously as this can be sent during
715 // port initialization. This way it will not be blocking other port
716 // creation.
Honghai Zhangf67c5482015-12-11 15:16:54 -0800717 thread()->Post(this, MSG_ALLOCATE_ERROR);
718}
719
720void TurnPort::Close() {
721 // Stop the port from creating new connections.
722 state_ = STATE_DISCONNECTED;
723 // Delete all existing connections; stop sending data.
724 for (auto kv : connections()) {
725 kv.second->Destroy();
726 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000727}
728
729void TurnPort::OnMessage(rtc::Message* message) {
Honghai Zhangf67c5482015-12-11 15:16:54 -0800730 switch (message->message_id) {
731 case MSG_ALLOCATE_ERROR:
732 SignalPortError(this);
733 break;
734 case MSG_ALLOCATE_MISMATCH:
735 OnAllocateMismatch();
736 break;
737 case MSG_TRY_ALTERNATE_SERVER:
738 if (server_address().proto == PROTO_UDP) {
739 // Send another allocate request to alternate server, with the received
740 // realm and nonce values.
741 SendRequest(new TurnAllocateRequest(this), 0);
742 } else {
743 // Since it's TCP, we have to delete the connected socket and reconnect
744 // with the alternate server. PrepareAddress will send stun binding once
745 // the new socket is connected.
746 ASSERT(server_address().proto == PROTO_TCP);
747 ASSERT(!SharedSocket());
748 delete socket_;
749 socket_ = NULL;
750 PrepareAddress();
751 }
752 break;
753 default:
754 Port::OnMessage(message);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000755 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000756}
757
758void TurnPort::OnAllocateRequestTimeout() {
759 OnAllocateError();
760}
761
762void TurnPort::HandleDataIndication(const char* data, size_t size,
763 const rtc::PacketTime& packet_time) {
764 // Read in the message, and process according to RFC5766, Section 10.4.
765 rtc::ByteBuffer buf(data, size);
766 TurnMessage msg;
767 if (!msg.Read(&buf)) {
768 LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
769 return;
770 }
771
772 // Check mandatory attributes.
773 const StunAddressAttribute* addr_attr =
774 msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
775 if (!addr_attr) {
776 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
777 << "in data indication.";
778 return;
779 }
780
781 const StunByteStringAttribute* data_attr =
782 msg.GetByteString(STUN_ATTR_DATA);
783 if (!data_attr) {
784 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
785 << "data indication.";
786 return;
787 }
788
789 // Verify that the data came from somewhere we think we have a permission for.
790 rtc::SocketAddress ext_addr(addr_attr->GetAddress());
791 if (!HasPermission(ext_addr.ipaddr())) {
792 LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
793 << "peer address, addr="
794 << ext_addr.ToSensitiveString();
795 return;
796 }
797
798 DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
799 PROTO_UDP, packet_time);
800}
801
802void TurnPort::HandleChannelData(int channel_id, const char* data,
803 size_t size,
804 const rtc::PacketTime& packet_time) {
805 // Read the message, and process according to RFC5766, Section 11.6.
806 // 0 1 2 3
807 // 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
808 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
809 // | Channel Number | Length |
810 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
811 // | |
812 // / Application Data /
813 // / /
814 // | |
815 // | +-------------------------------+
816 // | |
817 // +-------------------------------+
818
819 // Extract header fields from the message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200820 uint16_t len = rtc::GetBE16(data + 2);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000821 if (len > size - TURN_CHANNEL_HEADER_SIZE) {
822 LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
823 << "incorrect length, len=" << len;
824 return;
825 }
826 // Allowing messages larger than |len|, as ChannelData can be padded.
827
828 TurnEntry* entry = FindEntry(channel_id);
829 if (!entry) {
830 LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
831 << "channel, channel_id=" << channel_id;
832 return;
833 }
834
835 DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
836 PROTO_UDP, packet_time);
837}
838
839void TurnPort::DispatchPacket(const char* data, size_t size,
840 const rtc::SocketAddress& remote_addr,
841 ProtocolType proto, const rtc::PacketTime& packet_time) {
842 if (Connection* conn = GetConnection(remote_addr)) {
843 conn->OnReadPacket(data, size, packet_time);
844 } else {
845 Port::OnReadPacket(data, size, remote_addr, proto);
846 }
847}
848
849bool TurnPort::ScheduleRefresh(int lifetime) {
850 // Lifetime is in seconds; we schedule a refresh for one minute less.
851 if (lifetime < 2 * 60) {
852 LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
853 << "too short, lifetime=" << lifetime;
854 return false;
855 }
856
Peter Thatcherb32a5c42015-04-10 14:04:42 -0700857 int delay = (lifetime - 60) * 1000;
858 SendRequest(new TurnRefreshRequest(this), delay);
859 LOG_J(LS_INFO, this) << "Scheduled refresh in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000860 return true;
861}
862
863void TurnPort::SendRequest(StunRequest* req, int delay) {
864 request_manager_.SendDelayed(req, delay);
865}
866
867void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
868 // If we've gotten the necessary data from the server, add it to our request.
869 VERIFY(!hash_.empty());
870 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
871 STUN_ATTR_USERNAME, credentials_.username)));
872 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
873 STUN_ATTR_REALM, realm_)));
874 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
875 STUN_ATTR_NONCE, nonce_)));
876 VERIFY(msg->AddMessageIntegrity(hash()));
877}
878
879int TurnPort::Send(const void* data, size_t len,
880 const rtc::PacketOptions& options) {
881 return socket_->SendTo(data, len, server_address_.address, options);
882}
883
884void TurnPort::UpdateHash() {
885 VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
886 credentials_.password, &hash_));
887}
888
889bool TurnPort::UpdateNonce(StunMessage* response) {
890 // When stale nonce error received, we should update
891 // hash and store realm and nonce.
892 // Check the mandatory attributes.
893 const StunByteStringAttribute* realm_attr =
894 response->GetByteString(STUN_ATTR_REALM);
895 if (!realm_attr) {
896 LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
897 << "stale nonce error response.";
898 return false;
899 }
900 set_realm(realm_attr->GetString());
901
902 const StunByteStringAttribute* nonce_attr =
903 response->GetByteString(STUN_ATTR_NONCE);
904 if (!nonce_attr) {
905 LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
906 << "stale nonce error response.";
907 return false;
908 }
909 set_nonce(nonce_attr->GetString());
910 return true;
911}
912
913static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
914 return e->address().ipaddr() == ipaddr;
915}
916bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
917 return (std::find_if(entries_.begin(), entries_.end(),
918 std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
919}
920
921static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
922 return e->address() == addr;
923}
924TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
925 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
926 std::bind2nd(std::ptr_fun(MatchesAddress), addr));
927 return (it != entries_.end()) ? *it : NULL;
928}
929
930static bool MatchesChannelId(TurnEntry* e, int id) {
931 return e->channel_id() == id;
932}
933TurnEntry* TurnPort::FindEntry(int channel_id) const {
934 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
935 std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
936 return (it != entries_.end()) ? *it : NULL;
937}
938
honghaizc3e0fe72015-12-02 16:43:25 -0800939bool TurnPort::EntryExists(TurnEntry* e) {
940 auto it = std::find(entries_.begin(), entries_.end(), e);
941 return it != entries_.end();
942}
943
honghaiz32f39962015-11-17 11:36:31 -0800944void TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) {
945 TurnEntry* entry = FindEntry(addr);
946 if (entry == nullptr) {
947 entry = new TurnEntry(this, next_channel_number_++, addr);
948 entries_.push_back(entry);
949 } else {
950 // The channel binding request for the entry will be refreshed automatically
951 // until the entry is destroyed.
952 CancelEntryDestruction(entry);
953 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000954}
955
honghaiz32f39962015-11-17 11:36:31 -0800956void TurnPort::DestroyEntry(TurnEntry* entry) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000957 ASSERT(entry != NULL);
958 entry->SignalDestroyed(entry);
959 entries_.remove(entry);
960 delete entry;
961}
962
honghaiz32f39962015-11-17 11:36:31 -0800963void TurnPort::DestroyEntryIfNotCancelled(TurnEntry* entry,
964 uint32_t timestamp) {
honghaizc3e0fe72015-12-02 16:43:25 -0800965 if (!EntryExists(entry)) {
966 return;
967 }
honghaiz32f39962015-11-17 11:36:31 -0800968 bool cancelled = timestamp != entry->destruction_timestamp();
969 if (!cancelled) {
970 DestroyEntry(entry);
971 }
972}
973
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000974void TurnPort::OnConnectionDestroyed(Connection* conn) {
honghaiz32f39962015-11-17 11:36:31 -0800975 // Schedule an event to destroy TurnEntry for the connection, which is
976 // already destroyed.
977 const rtc::SocketAddress& remote_address = conn->remote_candidate().address();
978 TurnEntry* entry = FindEntry(remote_address);
979 ASSERT(entry != NULL);
980 ScheduleEntryDestruction(entry);
981}
982
983void TurnPort::ScheduleEntryDestruction(TurnEntry* entry) {
984 ASSERT(entry->destruction_timestamp() == 0);
985 uint32_t timestamp = rtc::Time();
986 entry->set_destruction_timestamp(timestamp);
987 invoker_.AsyncInvokeDelayed<void>(
988 thread(),
989 rtc::Bind(&TurnPort::DestroyEntryIfNotCancelled, this, entry, timestamp),
990 TURN_PERMISSION_TIMEOUT);
991}
992
993void TurnPort::CancelEntryDestruction(TurnEntry* entry) {
994 ASSERT(entry->destruction_timestamp() != 0);
995 entry->set_destruction_timestamp(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000996}
997
Honghai Zhangf67c5482015-12-11 15:16:54 -0800998bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address,
999 int channel_id) {
1000 TurnEntry* entry = FindEntry(address);
1001 if (!entry) {
1002 return false;
1003 }
1004 entry->set_channel_id(channel_id);
1005 return true;
1006}
1007
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001008TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
1009 : StunRequest(new TurnMessage()),
1010 port_(port) {
1011}
1012
1013void TurnAllocateRequest::Prepare(StunMessage* request) {
1014 // Create the request as indicated in RFC 5766, Section 6.1.
1015 request->SetType(TURN_ALLOCATE_REQUEST);
1016 StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
1017 STUN_ATTR_REQUESTED_TRANSPORT);
1018 transport_attr->SetValue(IPPROTO_UDP << 24);
1019 VERIFY(request->AddAttribute(transport_attr));
1020 if (!port_->hash().empty()) {
1021 port_->AddRequestAuthInfo(request);
1022 }
1023}
1024
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001025void TurnAllocateRequest::OnSent() {
1026 LOG_J(LS_INFO, port_) << "TURN allocate request sent"
1027 << ", id=" << rtc::hex_encode(id());
1028 StunRequest::OnSent();
1029}
1030
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001031void TurnAllocateRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001032 LOG_J(LS_INFO, port_) << "TURN allocate requested successfully"
1033 << ", id=" << rtc::hex_encode(id())
1034 << ", code=0" // Makes logging easier to parse.
1035 << ", rtt=" << Elapsed();
1036
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001037 // Check mandatory attributes as indicated in RFC5766, Section 6.3.
1038 const StunAddressAttribute* mapped_attr =
1039 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1040 if (!mapped_attr) {
1041 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
1042 << "attribute in allocate success response";
1043 return;
1044 }
1045 // Using XOR-Mapped-Address for stun.
1046 port_->OnStunAddress(mapped_attr->GetAddress());
1047
1048 const StunAddressAttribute* relayed_attr =
1049 response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
1050 if (!relayed_attr) {
1051 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
1052 << "attribute in allocate success response";
1053 return;
1054 }
1055
1056 const StunUInt32Attribute* lifetime_attr =
1057 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1058 if (!lifetime_attr) {
1059 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1060 << "allocate success response";
1061 return;
1062 }
1063 // Notify the port the allocate succeeded, and schedule a refresh request.
1064 port_->OnAllocateSuccess(relayed_attr->GetAddress(),
1065 mapped_attr->GetAddress());
1066 port_->ScheduleRefresh(lifetime_attr->value());
1067}
1068
1069void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
1070 // Process error response according to RFC5766, Section 6.4.
1071 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001072
1073 LOG_J(LS_INFO, port_) << "Received TURN allocate error response"
1074 << ", id=" << rtc::hex_encode(id())
1075 << ", code=" << error_code->code()
1076 << ", rtt=" << Elapsed();
1077
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001078 switch (error_code->code()) {
1079 case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
1080 OnAuthChallenge(response, error_code->code());
1081 break;
1082 case STUN_ERROR_TRY_ALTERNATE:
1083 OnTryAlternate(response, error_code->code());
1084 break;
1085 case STUN_ERROR_ALLOCATION_MISMATCH:
1086 // We must handle this error async because trying to delete the socket in
1087 // OnErrorResponse will cause a deadlock on the socket.
1088 port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH);
1089 break;
1090 default:
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001091 LOG_J(LS_WARNING, port_) << "Received TURN allocate error response"
1092 << ", id=" << rtc::hex_encode(id())
1093 << ", code=" << error_code->code()
1094 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001095 port_->OnAllocateError();
1096 }
1097}
1098
1099void TurnAllocateRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001100 LOG_J(LS_WARNING, port_) << "TURN allocate request "
1101 << rtc::hex_encode(id()) << " timout";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001102 port_->OnAllocateRequestTimeout();
1103}
1104
1105void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
1106 // If we failed to authenticate even after we sent our credentials, fail hard.
1107 if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
1108 LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
1109 << "after challenge.";
1110 port_->OnAllocateError();
1111 return;
1112 }
1113
1114 // Check the mandatory attributes.
1115 const StunByteStringAttribute* realm_attr =
1116 response->GetByteString(STUN_ATTR_REALM);
1117 if (!realm_attr) {
1118 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
1119 << "allocate unauthorized response.";
1120 return;
1121 }
1122 port_->set_realm(realm_attr->GetString());
1123
1124 const StunByteStringAttribute* nonce_attr =
1125 response->GetByteString(STUN_ATTR_NONCE);
1126 if (!nonce_attr) {
1127 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
1128 << "allocate unauthorized response.";
1129 return;
1130 }
1131 port_->set_nonce(nonce_attr->GetString());
1132
1133 // Send another allocate request, with the received realm and nonce values.
1134 port_->SendRequest(new TurnAllocateRequest(port_), 0);
1135}
1136
1137void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001138
1139 // According to RFC 5389 section 11, there are use cases where
1140 // authentication of response is not possible, we're not validating
1141 // message integrity.
1142
1143 // Get the alternate server address attribute value.
1144 const StunAddressAttribute* alternate_server_attr =
1145 response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1146 if (!alternate_server_attr) {
1147 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
1148 << "attribute in try alternate error response";
1149 port_->OnAllocateError();
1150 return;
1151 }
1152 if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1153 port_->OnAllocateError();
1154 return;
1155 }
1156
1157 // Check the attributes.
1158 const StunByteStringAttribute* realm_attr =
1159 response->GetByteString(STUN_ATTR_REALM);
1160 if (realm_attr) {
1161 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
1162 << "try alternate error response.";
1163 port_->set_realm(realm_attr->GetString());
1164 }
1165
1166 const StunByteStringAttribute* nonce_attr =
1167 response->GetByteString(STUN_ATTR_NONCE);
1168 if (nonce_attr) {
1169 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
1170 << "try alternate error response.";
1171 port_->set_nonce(nonce_attr->GetString());
1172 }
1173
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +00001174 // For TCP, we can't close the original Tcp socket during handling a 300 as
1175 // we're still inside that socket's event handler. Doing so will cause
1176 // deadlock.
1177 port_->thread()->Post(port_, TurnPort::MSG_TRY_ALTERNATE_SERVER);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001178}
1179
1180TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
1181 : StunRequest(new TurnMessage()),
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001182 port_(port),
1183 lifetime_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001184}
1185
1186void TurnRefreshRequest::Prepare(StunMessage* request) {
1187 // Create the request as indicated in RFC 5766, Section 7.1.
1188 // No attributes need to be included.
1189 request->SetType(TURN_REFRESH_REQUEST);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001190 if (lifetime_ > -1) {
1191 VERIFY(request->AddAttribute(new StunUInt32Attribute(
1192 STUN_ATTR_LIFETIME, lifetime_)));
1193 }
1194
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001195 port_->AddRequestAuthInfo(request);
1196}
1197
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001198void TurnRefreshRequest::OnSent() {
1199 LOG_J(LS_INFO, port_) << "TURN refresh request sent"
1200 << ", id=" << rtc::hex_encode(id());
1201 StunRequest::OnSent();
1202}
1203
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001204void TurnRefreshRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001205 LOG_J(LS_INFO, port_) << "TURN refresh requested successfully"
1206 << ", id=" << rtc::hex_encode(id())
1207 << ", code=0" // Makes logging easier to parse.
1208 << ", rtt=" << Elapsed();
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001209
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001210 // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1211 const StunUInt32Attribute* lifetime_attr =
1212 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1213 if (!lifetime_attr) {
1214 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1215 << "refresh success response.";
1216 return;
1217 }
1218
1219 // Schedule a refresh based on the returned lifetime value.
1220 port_->ScheduleRefresh(lifetime_attr->value());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001221 port_->SignalTurnRefreshResult(port_, TURN_SUCCESS_RESULT_CODE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001222}
1223
1224void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
1225 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001226
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001227 if (error_code->code() == STUN_ERROR_STALE_NONCE) {
1228 if (port_->UpdateNonce(response)) {
1229 // Send RefreshRequest immediately.
1230 port_->SendRequest(new TurnRefreshRequest(port_), 0);
1231 }
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001232 } else {
1233 LOG_J(LS_WARNING, port_) << "Received TURN refresh error response"
1234 << ", id=" << rtc::hex_encode(id())
1235 << ", code=" << error_code->code()
1236 << ", rtt=" << Elapsed();
Honghai Zhangf67c5482015-12-11 15:16:54 -08001237 port_->OnTurnRefreshError();
1238 port_->SignalTurnRefreshResult(port_, error_code->code());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001239 }
1240}
1241
1242void TurnRefreshRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001243 LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001244 port_->OnTurnRefreshError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001245}
1246
1247TurnCreatePermissionRequest::TurnCreatePermissionRequest(
1248 TurnPort* port, TurnEntry* entry,
1249 const rtc::SocketAddress& ext_addr)
1250 : StunRequest(new TurnMessage()),
1251 port_(port),
1252 entry_(entry),
1253 ext_addr_(ext_addr) {
1254 entry_->SignalDestroyed.connect(
1255 this, &TurnCreatePermissionRequest::OnEntryDestroyed);
1256}
1257
1258void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
1259 // Create the request as indicated in RFC5766, Section 9.1.
1260 request->SetType(TURN_CREATE_PERMISSION_REQUEST);
1261 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1262 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1263 port_->AddRequestAuthInfo(request);
1264}
1265
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001266void TurnCreatePermissionRequest::OnSent() {
1267 LOG_J(LS_INFO, port_) << "TURN create permission request sent"
1268 << ", id=" << rtc::hex_encode(id());
1269 StunRequest::OnSent();
1270}
1271
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001272void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001273 LOG_J(LS_INFO, port_) << "TURN permission requested successfully"
1274 << ", id=" << rtc::hex_encode(id())
1275 << ", code=0" // Makes logging easier to parse.
1276 << ", rtt=" << Elapsed();
1277
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001278 if (entry_) {
1279 entry_->OnCreatePermissionSuccess();
1280 }
1281}
1282
1283void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001284 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001285 LOG_J(LS_WARNING, port_) << "Received TURN create permission error response"
1286 << ", id=" << rtc::hex_encode(id())
1287 << ", code=" << error_code->code()
1288 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001289 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001290 entry_->OnCreatePermissionError(response, error_code->code());
1291 }
1292}
1293
1294void TurnCreatePermissionRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001295 LOG_J(LS_WARNING, port_) << "TURN create permission timeout "
1296 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001297 if (entry_) {
1298 entry_->OnCreatePermissionTimeout();
1299 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001300}
1301
1302void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
1303 ASSERT(entry_ == entry);
1304 entry_ = NULL;
1305}
1306
1307TurnChannelBindRequest::TurnChannelBindRequest(
1308 TurnPort* port, TurnEntry* entry,
1309 int channel_id, const rtc::SocketAddress& ext_addr)
1310 : StunRequest(new TurnMessage()),
1311 port_(port),
1312 entry_(entry),
1313 channel_id_(channel_id),
1314 ext_addr_(ext_addr) {
1315 entry_->SignalDestroyed.connect(
1316 this, &TurnChannelBindRequest::OnEntryDestroyed);
1317}
1318
1319void TurnChannelBindRequest::Prepare(StunMessage* request) {
1320 // Create the request as indicated in RFC5766, Section 11.1.
1321 request->SetType(TURN_CHANNEL_BIND_REQUEST);
1322 VERIFY(request->AddAttribute(new StunUInt32Attribute(
1323 STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)));
1324 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1325 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1326 port_->AddRequestAuthInfo(request);
1327}
1328
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001329void TurnChannelBindRequest::OnSent() {
1330 LOG_J(LS_INFO, port_) << "TURN channel bind request sent"
1331 << ", id=" << rtc::hex_encode(id());
1332 StunRequest::OnSent();
1333}
1334
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001335void TurnChannelBindRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001336 LOG_J(LS_INFO, port_) << "TURN channel bind requested successfully"
1337 << ", id=" << rtc::hex_encode(id())
1338 << ", code=0" // Makes logging easier to parse.
1339 << ", rtt=" << Elapsed();
1340
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001341 if (entry_) {
1342 entry_->OnChannelBindSuccess();
1343 // Refresh the channel binding just under the permission timeout
1344 // threshold. The channel binding has a longer lifetime, but
1345 // this is the easiest way to keep both the channel and the
1346 // permission from expiring.
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001347 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1348 entry_->SendChannelBindRequest(delay);
1349 LOG_J(LS_INFO, port_) << "Scheduled channel bind in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001350 }
1351}
1352
1353void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001354 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
1355 LOG_J(LS_WARNING, port_) << "Received TURN channel bind error response"
1356 << ", id=" << rtc::hex_encode(id())
1357 << ", code=" << error_code->code()
1358 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001359 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001360 entry_->OnChannelBindError(response, error_code->code());
1361 }
1362}
1363
1364void TurnChannelBindRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001365 LOG_J(LS_WARNING, port_) << "TURN channel bind timeout "
1366 << rtc::hex_encode(id());
Honghai Zhangf67c5482015-12-11 15:16:54 -08001367 if (entry_) {
1368 entry_->OnChannelBindTimeout();
1369 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001370}
1371
1372void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
1373 ASSERT(entry_ == entry);
1374 entry_ = NULL;
1375}
1376
1377TurnEntry::TurnEntry(TurnPort* port, int channel_id,
1378 const rtc::SocketAddress& ext_addr)
1379 : port_(port),
1380 channel_id_(channel_id),
1381 ext_addr_(ext_addr),
1382 state_(STATE_UNBOUND) {
1383 // Creating permission for |ext_addr_|.
Honghai Zhang85975432015-11-12 11:07:12 -08001384 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001385}
1386
Honghai Zhang85975432015-11-12 11:07:12 -08001387void TurnEntry::SendCreatePermissionRequest(int delay) {
1388 port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
1389 delay);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001390}
1391
1392void TurnEntry::SendChannelBindRequest(int delay) {
1393 port_->SendRequest(new TurnChannelBindRequest(
1394 port_, this, channel_id_, ext_addr_), delay);
1395}
1396
1397int TurnEntry::Send(const void* data, size_t size, bool payload,
1398 const rtc::PacketOptions& options) {
1399 rtc::ByteBuffer buf;
1400 if (state_ != STATE_BOUND) {
1401 // If we haven't bound the channel yet, we have to use a Send Indication.
1402 TurnMessage msg;
1403 msg.SetType(TURN_SEND_INDICATION);
1404 msg.SetTransactionID(
1405 rtc::CreateRandomString(kStunTransactionIdLength));
1406 VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
1407 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1408 VERIFY(msg.AddAttribute(new StunByteStringAttribute(
1409 STUN_ATTR_DATA, data, size)));
1410 VERIFY(msg.Write(&buf));
1411
1412 // If we're sending real data, request a channel bind that we can use later.
1413 if (state_ == STATE_UNBOUND && payload) {
1414 SendChannelBindRequest(0);
1415 state_ = STATE_BINDING;
1416 }
1417 } else {
1418 // If the channel is bound, we can send the data as a Channel Message.
1419 buf.WriteUInt16(channel_id_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001420 buf.WriteUInt16(static_cast<uint16_t>(size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001421 buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1422 }
1423 return port_->Send(buf.Data(), buf.Length(), options);
1424}
1425
1426void TurnEntry::OnCreatePermissionSuccess() {
1427 LOG_J(LS_INFO, port_) << "Create permission for "
1428 << ext_addr_.ToSensitiveString()
1429 << " succeeded";
Honghai Zhangf67c5482015-12-11 15:16:54 -08001430 port_->SignalCreatePermissionResult(port_, ext_addr_,
1431 TURN_SUCCESS_RESULT_CODE);
Honghai Zhang85975432015-11-12 11:07:12 -08001432
1433 // If |state_| is STATE_BOUND, the permission will be refreshed
1434 // by ChannelBindRequest.
1435 if (state_ != STATE_BOUND) {
1436 // Refresh the permission request about 1 minute before the permission
1437 // times out.
1438 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1439 SendCreatePermissionRequest(delay);
1440 LOG_J(LS_INFO, port_) << "Scheduled create-permission-request in "
1441 << delay << "ms.";
1442 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001443}
1444
1445void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001446 if (code == STUN_ERROR_STALE_NONCE) {
1447 if (port_->UpdateNonce(response)) {
Honghai Zhang85975432015-11-12 11:07:12 -08001448 SendCreatePermissionRequest(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001449 }
1450 } else {
Honghai Zhangf67c5482015-12-11 15:16:54 -08001451 port_->DestroyConnection(ext_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001452 // Send signal with error code.
1453 port_->SignalCreatePermissionResult(port_, ext_addr_, code);
deadbeef376e1232015-11-25 09:00:08 -08001454 Connection* c = port_->GetConnection(ext_addr_);
1455 if (c) {
1456 LOG_J(LS_ERROR, c) << "Received TURN CreatePermission error response, "
1457 << "code=" << code << "; killing connection.";
1458 c->FailAndDestroy();
1459 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001460 }
1461}
1462
Honghai Zhangf67c5482015-12-11 15:16:54 -08001463void TurnEntry::OnCreatePermissionTimeout() {
1464 port_->DestroyConnection(ext_addr_);
1465}
1466
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001467void TurnEntry::OnChannelBindSuccess() {
1468 LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
1469 << " succeeded";
1470 ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND);
1471 state_ = STATE_BOUND;
1472}
1473
1474void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
Honghai Zhangf67c5482015-12-11 15:16:54 -08001475 // If the channel bind fails due to errors other than STATE_NONCE,
1476 // we just destroy the connection and rely on ICE restart to re-establish
1477 // the connection.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001478 if (code == STUN_ERROR_STALE_NONCE) {
1479 if (port_->UpdateNonce(response)) {
1480 // Send channel bind request with fresh nonce.
1481 SendChannelBindRequest(0);
1482 }
Honghai Zhangf67c5482015-12-11 15:16:54 -08001483 } else {
1484 state_ = STATE_UNBOUND;
1485 port_->DestroyConnection(ext_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001486 }
1487}
Honghai Zhangf67c5482015-12-11 15:16:54 -08001488void TurnEntry::OnChannelBindTimeout() {
1489 state_ = STATE_UNBOUND;
1490 port_->DestroyConnection(ext_addr_);
1491}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001492} // namespace cricket