blob: 58fb01a4e81c9d14632a51e5f438e672c6c1c784 [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
41inline bool IsTurnChannelData(uint16 msg_type) {
42 return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
43}
44
45static int GetRelayPreference(cricket::ProtocolType proto, bool secure) {
46 int relay_preference = ICE_TYPE_PREFERENCE_RELAY;
47 if (proto == cricket::PROTO_TCP) {
48 relay_preference -= 1;
49 if (secure)
50 relay_preference -= 1;
51 }
52
53 ASSERT(relay_preference >= 0);
54 return relay_preference;
55}
56
57class TurnAllocateRequest : public StunRequest {
58 public:
59 explicit TurnAllocateRequest(TurnPort* port);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070060 void Prepare(StunMessage* request) override;
61 void OnSent() override;
62 void OnResponse(StunMessage* response) override;
63 void OnErrorResponse(StunMessage* response) override;
64 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000065
66 private:
67 // Handles authentication challenge from the server.
68 void OnAuthChallenge(StunMessage* response, int code);
69 void OnTryAlternate(StunMessage* response, int code);
70 void OnUnknownAttribute(StunMessage* response);
71
72 TurnPort* port_;
73};
74
75class TurnRefreshRequest : public StunRequest {
76 public:
77 explicit TurnRefreshRequest(TurnPort* port);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070078 void Prepare(StunMessage* request) override;
79 void OnSent() override;
80 void OnResponse(StunMessage* response) override;
81 void OnErrorResponse(StunMessage* response) override;
82 void OnTimeout() override;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000083 void set_lifetime(int lifetime) { lifetime_ = lifetime; }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000084
85 private:
86 TurnPort* port_;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000087 int lifetime_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000088};
89
90class TurnCreatePermissionRequest : public StunRequest,
91 public sigslot::has_slots<> {
92 public:
93 TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
94 const rtc::SocketAddress& ext_addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070095 void Prepare(StunMessage* request) override;
96 void OnSent() override;
97 void OnResponse(StunMessage* response) override;
98 void OnErrorResponse(StunMessage* response) override;
99 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000100
101 private:
102 void OnEntryDestroyed(TurnEntry* entry);
103
104 TurnPort* port_;
105 TurnEntry* entry_;
106 rtc::SocketAddress ext_addr_;
107};
108
109class TurnChannelBindRequest : public StunRequest,
110 public sigslot::has_slots<> {
111 public:
112 TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
113 const rtc::SocketAddress& ext_addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700114 void Prepare(StunMessage* request) override;
115 void OnSent() override;
116 void OnResponse(StunMessage* response) override;
117 void OnErrorResponse(StunMessage* response) override;
118 void OnTimeout() override;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000119
120 private:
121 void OnEntryDestroyed(TurnEntry* entry);
122
123 TurnPort* port_;
124 TurnEntry* entry_;
125 int channel_id_;
126 rtc::SocketAddress ext_addr_;
127};
128
129// Manages a "connection" to a remote destination. We will attempt to bring up
130// a channel for this remote destination to reduce the overhead of sending data.
131class TurnEntry : public sigslot::has_slots<> {
132 public:
133 enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
134 TurnEntry(TurnPort* port, int channel_id,
135 const rtc::SocketAddress& ext_addr);
136
137 TurnPort* port() { return port_; }
138
139 int channel_id() const { return channel_id_; }
140 const rtc::SocketAddress& address() const { return ext_addr_; }
141 BindState state() const { return state_; }
142
143 // Helper methods to send permission and channel bind requests.
144 void SendCreatePermissionRequest();
145 void SendChannelBindRequest(int delay);
146 // Sends a packet to the given destination address.
147 // This will wrap the packet in STUN if necessary.
148 int Send(const void* data, size_t size, bool payload,
149 const rtc::PacketOptions& options);
150
151 void OnCreatePermissionSuccess();
152 void OnCreatePermissionError(StunMessage* response, int code);
153 void OnChannelBindSuccess();
154 void OnChannelBindError(StunMessage* response, int code);
155 // Signal sent when TurnEntry is destroyed.
156 sigslot::signal1<TurnEntry*> SignalDestroyed;
157
158 private:
159 TurnPort* port_;
160 int channel_id_;
161 rtc::SocketAddress ext_addr_;
162 BindState state_;
163};
164
165TurnPort::TurnPort(rtc::Thread* thread,
166 rtc::PacketSocketFactory* factory,
167 rtc::Network* network,
168 rtc::AsyncPacketSocket* socket,
169 const std::string& username,
170 const std::string& password,
171 const ProtocolAddress& server_address,
172 const RelayCredentials& credentials,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000173 int server_priority,
174 const std::string& origin)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175 : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
176 username, password),
177 server_address_(server_address),
178 credentials_(credentials),
179 socket_(socket),
180 resolver_(NULL),
181 error_(0),
182 request_manager_(thread),
183 next_channel_number_(TURN_CHANNEL_NUMBER_START),
184 connected_(false),
185 server_priority_(server_priority),
186 allocate_mismatch_retries_(0) {
187 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000188 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000189}
190
191TurnPort::TurnPort(rtc::Thread* thread,
192 rtc::PacketSocketFactory* factory,
193 rtc::Network* network,
194 const rtc::IPAddress& ip,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000195 uint16 min_port,
196 uint16 max_port,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000197 const std::string& username,
198 const std::string& password,
199 const ProtocolAddress& server_address,
200 const RelayCredentials& credentials,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000201 int server_priority,
202 const std::string& origin)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000203 : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port,
204 username, password),
205 server_address_(server_address),
206 credentials_(credentials),
207 socket_(NULL),
208 resolver_(NULL),
209 error_(0),
210 request_manager_(thread),
211 next_channel_number_(TURN_CHANNEL_NUMBER_START),
212 connected_(false),
213 server_priority_(server_priority),
214 allocate_mismatch_retries_(0) {
215 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000216 request_manager_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000217}
218
219TurnPort::~TurnPort() {
220 // TODO(juberti): Should this even be necessary?
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000221
222 // release the allocation by sending a refresh with
223 // lifetime 0.
224 if (connected_) {
225 TurnRefreshRequest bye(this);
226 bye.set_lifetime(0);
227 SendRequest(&bye, 0);
228 }
229
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000230 while (!entries_.empty()) {
231 DestroyEntry(entries_.front()->address());
232 }
233 if (resolver_) {
234 resolver_->Destroy(false);
235 }
236 if (!SharedSocket()) {
237 delete socket_;
238 }
239}
240
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000241rtc::SocketAddress TurnPort::GetLocalAddress() const {
242 return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress();
243}
244
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245void TurnPort::PrepareAddress() {
246 if (credentials_.username.empty() ||
247 credentials_.password.empty()) {
248 LOG(LS_ERROR) << "Allocation can't be started without setting the"
249 << " TURN server credentials for the user.";
250 OnAllocateError();
251 return;
252 }
253
254 if (!server_address_.address.port()) {
255 // We will set default TURN port, if no port is set in the address.
256 server_address_.address.SetPort(TURN_DEFAULT_PORT);
257 }
258
259 if (server_address_.address.IsUnresolved()) {
260 ResolveTurnAddress(server_address_.address);
261 } else {
262 // If protocol family of server address doesn't match with local, return.
263 if (!IsCompatibleAddress(server_address_.address)) {
264 LOG(LS_ERROR) << "Server IP address family does not match with "
265 << "local host address family type";
266 OnAllocateError();
267 return;
268 }
269
270 // Insert the current address to prevent redirection pingpong.
271 attempted_server_addresses_.insert(server_address_.address);
272
273 LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
274 << ProtoToString(server_address_.proto) << " @ "
275 << server_address_.address.ToSensitiveString();
276 if (!CreateTurnClientSocket()) {
277 OnAllocateError();
278 } else if (server_address_.proto == PROTO_UDP) {
279 // If its UDP, send AllocateRequest now.
280 // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
281 SendRequest(new TurnAllocateRequest(this), 0);
282 }
283 }
284}
285
286bool TurnPort::CreateTurnClientSocket() {
287 ASSERT(!socket_ || SharedSocket());
288
289 if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
290 socket_ = socket_factory()->CreateUdpSocket(
291 rtc::SocketAddress(ip(), 0), min_port(), max_port());
292 } else if (server_address_.proto == PROTO_TCP) {
293 ASSERT(!SharedSocket());
294 int opts = rtc::PacketSocketFactory::OPT_STUN;
295 // If secure bit is enabled in server address, use TLS over TCP.
296 if (server_address_.secure) {
297 opts |= rtc::PacketSocketFactory::OPT_TLS;
298 }
299 socket_ = socket_factory()->CreateClientTcpSocket(
300 rtc::SocketAddress(ip(), 0), server_address_.address,
301 proxy(), user_agent(), opts);
302 }
303
304 if (!socket_) {
305 error_ = SOCKET_ERROR;
306 return false;
307 }
308
309 // Apply options if any.
310 for (SocketOptionsMap::iterator iter = socket_options_.begin();
311 iter != socket_options_.end(); ++iter) {
312 socket_->SetOption(iter->first, iter->second);
313 }
314
315 if (!SharedSocket()) {
316 // If socket is shared, AllocationSequence will receive the packet.
317 socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
318 }
319
320 socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
321
322 if (server_address_.proto == PROTO_TCP) {
323 socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
324 socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
325 }
326 return true;
327}
328
329void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
330 ASSERT(server_address_.proto == PROTO_TCP);
331 // Do not use this port if the socket bound to a different address than
332 // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
333 // given a binding address, and the platform is expected to pick the
334 // correct local address.
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000335
336 // Further, to workaround issue 3927 in which a proxy is forcing TCP bound to
337 // localhost only, we're allowing Loopback IP even if it's not the same as the
338 // local Turn port.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000339 if (socket->GetLocalAddress().ipaddr() != ip()) {
guoweis@webrtc.org4fba2932014-12-18 04:45:05 +0000340 if (socket->GetLocalAddress().IsLoopbackIP()) {
341 LOG(LS_WARNING) << "Socket is bound to a different address:"
342 << socket->GetLocalAddress().ipaddr().ToString()
343 << ", rather then the local port:" << ip().ToString()
344 << ". Still allowing it since it's localhost.";
345 } else {
346 LOG(LS_WARNING) << "Socket is bound to a different address:"
347 << socket->GetLocalAddress().ipaddr().ToString()
348 << ", rather then the local port:" << ip().ToString()
349 << ". Discarding TURN port.";
350 OnAllocateError();
351 return;
352 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 }
354
355 if (server_address_.address.IsUnresolved()) {
356 server_address_.address = socket_->GetRemoteAddress();
357 }
358
359 LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
360 << " using tcp.";
361 SendRequest(new TurnAllocateRequest(this), 0);
362}
363
364void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
365 LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +0000366 ASSERT(socket == socket_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367 if (!connected_) {
368 OnAllocateError();
369 }
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +0000370 connected_ = false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371}
372
373void TurnPort::OnAllocateMismatch() {
374 if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
375 LOG_J(LS_WARNING, this) << "Giving up on the port after "
376 << allocate_mismatch_retries_
377 << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
378 OnAllocateError();
379 return;
380 }
381
382 LOG_J(LS_INFO, this) << "Allocating a new socket after "
383 << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
384 << allocate_mismatch_retries_ + 1;
385 if (SharedSocket()) {
386 ResetSharedSocket();
387 } else {
388 delete socket_;
389 }
390 socket_ = NULL;
391
392 PrepareAddress();
393 ++allocate_mismatch_retries_;
394}
395
396Connection* TurnPort::CreateConnection(const Candidate& address,
397 CandidateOrigin origin) {
398 // TURN-UDP can only connect to UDP candidates.
399 if (address.protocol() != UDP_PROTOCOL_NAME) {
400 return NULL;
401 }
402
403 if (!IsCompatibleAddress(address.address())) {
404 return NULL;
405 }
406
407 // Create an entry, if needed, so we can get our permissions set up correctly.
408 CreateEntry(address.address());
409
410 // A TURN port will have two candiates, STUN and TURN. STUN may not
411 // present in all cases. If present stun candidate will be added first
412 // and TURN candidate later.
413 for (size_t index = 0; index < Candidates().size(); ++index) {
414 if (Candidates()[index].type() == RELAY_PORT_TYPE) {
415 ProxyConnection* conn = new ProxyConnection(this, index, address);
416 conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
417 AddConnection(conn);
418 return conn;
419 }
420 }
421 return NULL;
422}
423
424int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
425 if (!socket_) {
426 // If socket is not created yet, these options will be applied during socket
427 // creation.
428 socket_options_[opt] = value;
429 return 0;
430 }
431 return socket_->SetOption(opt, value);
432}
433
434int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
435 if (!socket_) {
436 SocketOptionsMap::const_iterator it = socket_options_.find(opt);
437 if (it == socket_options_.end()) {
438 return -1;
439 }
440 *value = it->second;
441 return 0;
442 }
443
444 return socket_->GetOption(opt, value);
445}
446
447int TurnPort::GetError() {
448 return error_;
449}
450
451int TurnPort::SendTo(const void* data, size_t size,
452 const rtc::SocketAddress& addr,
453 const rtc::PacketOptions& options,
454 bool payload) {
455 // Try to find an entry for this specific address; we should have one.
456 TurnEntry* entry = FindEntry(addr);
457 ASSERT(entry != NULL);
458 if (!entry) {
459 return 0;
460 }
461
462 if (!connected()) {
463 error_ = EWOULDBLOCK;
464 return SOCKET_ERROR;
465 }
466
467 // Send the actual contents to the server using the usual mechanism.
468 int sent = entry->Send(data, size, payload, options);
469 if (sent <= 0) {
470 return SOCKET_ERROR;
471 }
472
473 // The caller of the function is expecting the number of user data bytes,
474 // rather than the size of the packet.
475 return static_cast<int>(size);
476}
477
478void TurnPort::OnReadPacket(
479 rtc::AsyncPacketSocket* socket, const char* data, size_t size,
480 const rtc::SocketAddress& remote_addr,
481 const rtc::PacketTime& packet_time) {
482 ASSERT(socket == socket_);
guoweis@webrtc.orgc51fb932014-12-18 00:30:55 +0000483
484 // This is to guard against a STUN response from previous server after
485 // alternative server redirection. TODO(guoweis): add a unit test for this
486 // race condition.
487 if (remote_addr != server_address_.address) {
488 LOG_J(LS_WARNING, this) << "Discarding TURN message from unknown address:"
489 << remote_addr.ToString()
490 << ", server_address_:"
491 << server_address_.address.ToString();
492 return;
493 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494
495 // The message must be at least the size of a channel header.
496 if (size < TURN_CHANNEL_HEADER_SIZE) {
497 LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
498 return;
499 }
500
501 // Check the message type, to see if is a Channel Data message.
502 // The message will either be channel data, a TURN data indication, or
503 // a response to a previous request.
504 uint16 msg_type = rtc::GetBE16(data);
505 if (IsTurnChannelData(msg_type)) {
506 HandleChannelData(msg_type, data, size, packet_time);
507 } else if (msg_type == TURN_DATA_INDICATION) {
508 HandleDataIndication(data, size, packet_time);
509 } else {
jiayl@webrtc.org511f8a82014-12-03 02:17:07 +0000510 if (SharedSocket() &&
511 (msg_type == STUN_BINDING_RESPONSE ||
512 msg_type == STUN_BINDING_ERROR_RESPONSE)) {
513 LOG_J(LS_VERBOSE, this) <<
514 "Ignoring STUN binding response message on shared socket.";
515 return;
516 }
517
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000518 // This must be a response for one of our requests.
519 // Check success responses, but not errors, for MESSAGE-INTEGRITY.
520 if (IsStunSuccessResponseType(msg_type) &&
521 !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
522 LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
523 << "message integrity, msg_type=" << msg_type;
524 return;
525 }
526 request_manager_.CheckResponse(data, size);
527 }
528}
529
530void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
531 if (connected_) {
532 Port::OnReadyToSend();
533 }
534}
535
536
537// Update current server address port with the alternate server address port.
538bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
539 // Check if we have seen this address before and reject if we did.
540 AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
541 if (iter != attempted_server_addresses_.end()) {
542 LOG_J(LS_WARNING, this) << "Redirection to ["
543 << address.ToSensitiveString()
544 << "] ignored, allocation failed.";
545 return false;
546 }
547
548 // If protocol family of server address doesn't match with local, return.
549 if (!IsCompatibleAddress(address)) {
550 LOG(LS_WARNING) << "Server IP address family does not match with "
551 << "local host address family type";
552 return false;
553 }
554
555 LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
556 << server_address_.address.ToSensitiveString()
557 << "] to TURN server ["
558 << address.ToSensitiveString()
559 << "]";
560 server_address_ = ProtocolAddress(address, server_address_.proto,
561 server_address_.secure);
562
563 // Insert the current address to prevent redirection pingpong.
564 attempted_server_addresses_.insert(server_address_.address);
565 return true;
566}
567
568void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
569 if (resolver_)
570 return;
571
572 resolver_ = socket_factory()->CreateAsyncResolver();
573 resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
574 resolver_->Start(address);
575}
576
577void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
578 ASSERT(resolver == resolver_);
579 // If DNS resolve is failed when trying to connect to the server using TCP,
580 // one of the reason could be due to DNS queries blocked by firewall.
581 // In such cases we will try to connect to the server with hostname, assuming
582 // socket layer will resolve the hostname through a HTTP proxy (if any).
583 if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
584 if (!CreateTurnClientSocket()) {
585 OnAllocateError();
586 }
587 return;
588 }
589
590 // Copy the original server address in |resolved_address|. For TLS based
591 // sockets we need hostname along with resolved address.
592 rtc::SocketAddress resolved_address = server_address_.address;
593 if (resolver_->GetError() != 0 ||
594 !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
595 LOG_J(LS_WARNING, this) << "TURN host lookup received error "
596 << resolver_->GetError();
597 error_ = resolver_->GetError();
598 OnAllocateError();
599 return;
600 }
601 // Signal needs both resolved and unresolved address. After signal is sent
602 // we can copy resolved address back into |server_address_|.
603 SignalResolvedServerAddress(this, server_address_.address,
604 resolved_address);
605 server_address_.address = resolved_address;
606 PrepareAddress();
607}
608
609void TurnPort::OnSendStunPacket(const void* data, size_t size,
610 StunRequest* request) {
611 rtc::PacketOptions options(DefaultDscpValue());
612 if (Send(data, size, options) < 0) {
613 LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
614 << socket_->GetError();
615 }
616}
617
618void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
619 // STUN Port will discover STUN candidate, as it's supplied with first TURN
620 // server address.
621 // Why not using this address? - P2PTransportChannel will start creating
622 // connections after first candidate, which means it could start creating the
623 // connections before TURN candidate added. For that to handle, we need to
624 // supply STUN candidate from this port to UDPPort, and TurnPort should have
625 // handle to UDPPort to pass back the address.
626}
627
628void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
629 const rtc::SocketAddress& stun_address) {
630 connected_ = true;
631
632 rtc::SocketAddress related_address = stun_address;
633 if (!(candidate_filter() & CF_REFLEXIVE)) {
634 // If candidate filter only allows relay type of address, empty raddr to
635 // avoid local address leakage.
636 related_address = rtc::EmptySocketAddressWithFamily(stun_address.family());
637 }
638
639 // For relayed candidate, Base is the candidate itself.
640 AddAddress(address, // Candidate address.
641 address, // Base address.
642 related_address, // Related address.
643 UDP_PROTOCOL_NAME,
644 "", // TCP canddiate type, empty for turn candidates.
645 RELAY_PORT_TYPE,
646 GetRelayPreference(server_address_.proto, server_address_.secure),
647 server_priority_,
648 true);
649}
650
651void TurnPort::OnAllocateError() {
652 // We will send SignalPortError asynchronously as this can be sent during
653 // port initialization. This way it will not be blocking other port
654 // creation.
655 thread()->Post(this, MSG_ERROR);
656}
657
658void TurnPort::OnMessage(rtc::Message* message) {
659 if (message->message_id == MSG_ERROR) {
660 SignalPortError(this);
661 return;
662 } else if (message->message_id == MSG_ALLOCATE_MISMATCH) {
663 OnAllocateMismatch();
664 return;
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +0000665 } else if (message->message_id == MSG_TRY_ALTERNATE_SERVER) {
666 if (server_address().proto == PROTO_UDP) {
667 // Send another allocate request to alternate server, with the received
668 // realm and nonce values.
669 SendRequest(new TurnAllocateRequest(this), 0);
670 } else {
671 // Since it's TCP, we have to delete the connected socket and reconnect
672 // with the alternate server. PrepareAddress will send stun binding once
673 // the new socket is connected.
674 ASSERT(server_address().proto == PROTO_TCP);
675 ASSERT(!SharedSocket());
676 delete socket_;
677 socket_ = NULL;
678 PrepareAddress();
679 }
680 return;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000681 }
682
683 Port::OnMessage(message);
684}
685
686void TurnPort::OnAllocateRequestTimeout() {
687 OnAllocateError();
688}
689
690void TurnPort::HandleDataIndication(const char* data, size_t size,
691 const rtc::PacketTime& packet_time) {
692 // Read in the message, and process according to RFC5766, Section 10.4.
693 rtc::ByteBuffer buf(data, size);
694 TurnMessage msg;
695 if (!msg.Read(&buf)) {
696 LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
697 return;
698 }
699
700 // Check mandatory attributes.
701 const StunAddressAttribute* addr_attr =
702 msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
703 if (!addr_attr) {
704 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
705 << "in data indication.";
706 return;
707 }
708
709 const StunByteStringAttribute* data_attr =
710 msg.GetByteString(STUN_ATTR_DATA);
711 if (!data_attr) {
712 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
713 << "data indication.";
714 return;
715 }
716
717 // Verify that the data came from somewhere we think we have a permission for.
718 rtc::SocketAddress ext_addr(addr_attr->GetAddress());
719 if (!HasPermission(ext_addr.ipaddr())) {
720 LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
721 << "peer address, addr="
722 << ext_addr.ToSensitiveString();
723 return;
724 }
725
726 DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
727 PROTO_UDP, packet_time);
728}
729
730void TurnPort::HandleChannelData(int channel_id, const char* data,
731 size_t size,
732 const rtc::PacketTime& packet_time) {
733 // Read the message, and process according to RFC5766, Section 11.6.
734 // 0 1 2 3
735 // 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
736 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737 // | Channel Number | Length |
738 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
739 // | |
740 // / Application Data /
741 // / /
742 // | |
743 // | +-------------------------------+
744 // | |
745 // +-------------------------------+
746
747 // Extract header fields from the message.
748 uint16 len = rtc::GetBE16(data + 2);
749 if (len > size - TURN_CHANNEL_HEADER_SIZE) {
750 LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
751 << "incorrect length, len=" << len;
752 return;
753 }
754 // Allowing messages larger than |len|, as ChannelData can be padded.
755
756 TurnEntry* entry = FindEntry(channel_id);
757 if (!entry) {
758 LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
759 << "channel, channel_id=" << channel_id;
760 return;
761 }
762
763 DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
764 PROTO_UDP, packet_time);
765}
766
767void TurnPort::DispatchPacket(const char* data, size_t size,
768 const rtc::SocketAddress& remote_addr,
769 ProtocolType proto, const rtc::PacketTime& packet_time) {
770 if (Connection* conn = GetConnection(remote_addr)) {
771 conn->OnReadPacket(data, size, packet_time);
772 } else {
773 Port::OnReadPacket(data, size, remote_addr, proto);
774 }
775}
776
777bool TurnPort::ScheduleRefresh(int lifetime) {
778 // Lifetime is in seconds; we schedule a refresh for one minute less.
779 if (lifetime < 2 * 60) {
780 LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
781 << "too short, lifetime=" << lifetime;
782 return false;
783 }
784
Peter Thatcherb32a5c42015-04-10 14:04:42 -0700785 int delay = (lifetime - 60) * 1000;
786 SendRequest(new TurnRefreshRequest(this), delay);
787 LOG_J(LS_INFO, this) << "Scheduled refresh in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000788 return true;
789}
790
791void TurnPort::SendRequest(StunRequest* req, int delay) {
792 request_manager_.SendDelayed(req, delay);
793}
794
795void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
796 // If we've gotten the necessary data from the server, add it to our request.
797 VERIFY(!hash_.empty());
798 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
799 STUN_ATTR_USERNAME, credentials_.username)));
800 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
801 STUN_ATTR_REALM, realm_)));
802 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
803 STUN_ATTR_NONCE, nonce_)));
804 VERIFY(msg->AddMessageIntegrity(hash()));
805}
806
807int TurnPort::Send(const void* data, size_t len,
808 const rtc::PacketOptions& options) {
809 return socket_->SendTo(data, len, server_address_.address, options);
810}
811
812void TurnPort::UpdateHash() {
813 VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
814 credentials_.password, &hash_));
815}
816
817bool TurnPort::UpdateNonce(StunMessage* response) {
818 // When stale nonce error received, we should update
819 // hash and store realm and nonce.
820 // Check the mandatory attributes.
821 const StunByteStringAttribute* realm_attr =
822 response->GetByteString(STUN_ATTR_REALM);
823 if (!realm_attr) {
824 LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
825 << "stale nonce error response.";
826 return false;
827 }
828 set_realm(realm_attr->GetString());
829
830 const StunByteStringAttribute* nonce_attr =
831 response->GetByteString(STUN_ATTR_NONCE);
832 if (!nonce_attr) {
833 LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
834 << "stale nonce error response.";
835 return false;
836 }
837 set_nonce(nonce_attr->GetString());
838 return true;
839}
840
841static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
842 return e->address().ipaddr() == ipaddr;
843}
844bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
845 return (std::find_if(entries_.begin(), entries_.end(),
846 std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
847}
848
849static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
850 return e->address() == addr;
851}
852TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
853 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
854 std::bind2nd(std::ptr_fun(MatchesAddress), addr));
855 return (it != entries_.end()) ? *it : NULL;
856}
857
858static bool MatchesChannelId(TurnEntry* e, int id) {
859 return e->channel_id() == id;
860}
861TurnEntry* TurnPort::FindEntry(int channel_id) const {
862 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
863 std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
864 return (it != entries_.end()) ? *it : NULL;
865}
866
867TurnEntry* TurnPort::CreateEntry(const rtc::SocketAddress& addr) {
868 ASSERT(FindEntry(addr) == NULL);
869 TurnEntry* entry = new TurnEntry(this, next_channel_number_++, addr);
870 entries_.push_back(entry);
871 return entry;
872}
873
874void TurnPort::DestroyEntry(const rtc::SocketAddress& addr) {
875 TurnEntry* entry = FindEntry(addr);
876 ASSERT(entry != NULL);
877 entry->SignalDestroyed(entry);
878 entries_.remove(entry);
879 delete entry;
880}
881
882void TurnPort::OnConnectionDestroyed(Connection* conn) {
883 // Destroying TurnEntry for the connection, which is already destroyed.
884 DestroyEntry(conn->remote_candidate().address());
885}
886
887TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
888 : StunRequest(new TurnMessage()),
889 port_(port) {
890}
891
892void TurnAllocateRequest::Prepare(StunMessage* request) {
893 // Create the request as indicated in RFC 5766, Section 6.1.
894 request->SetType(TURN_ALLOCATE_REQUEST);
895 StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
896 STUN_ATTR_REQUESTED_TRANSPORT);
897 transport_attr->SetValue(IPPROTO_UDP << 24);
898 VERIFY(request->AddAttribute(transport_attr));
899 if (!port_->hash().empty()) {
900 port_->AddRequestAuthInfo(request);
901 }
902}
903
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700904void TurnAllocateRequest::OnSent() {
905 LOG_J(LS_INFO, port_) << "TURN allocate request sent"
906 << ", id=" << rtc::hex_encode(id());
907 StunRequest::OnSent();
908}
909
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000910void TurnAllocateRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700911 LOG_J(LS_INFO, port_) << "TURN allocate requested successfully"
912 << ", id=" << rtc::hex_encode(id())
913 << ", code=0" // Makes logging easier to parse.
914 << ", rtt=" << Elapsed();
915
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000916 // Check mandatory attributes as indicated in RFC5766, Section 6.3.
917 const StunAddressAttribute* mapped_attr =
918 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
919 if (!mapped_attr) {
920 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
921 << "attribute in allocate success response";
922 return;
923 }
924 // Using XOR-Mapped-Address for stun.
925 port_->OnStunAddress(mapped_attr->GetAddress());
926
927 const StunAddressAttribute* relayed_attr =
928 response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
929 if (!relayed_attr) {
930 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
931 << "attribute in allocate success response";
932 return;
933 }
934
935 const StunUInt32Attribute* lifetime_attr =
936 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
937 if (!lifetime_attr) {
938 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
939 << "allocate success response";
940 return;
941 }
942 // Notify the port the allocate succeeded, and schedule a refresh request.
943 port_->OnAllocateSuccess(relayed_attr->GetAddress(),
944 mapped_attr->GetAddress());
945 port_->ScheduleRefresh(lifetime_attr->value());
946}
947
948void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
949 // Process error response according to RFC5766, Section 6.4.
950 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700951
952 LOG_J(LS_INFO, port_) << "Received TURN allocate error response"
953 << ", id=" << rtc::hex_encode(id())
954 << ", code=" << error_code->code()
955 << ", rtt=" << Elapsed();
956
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000957 switch (error_code->code()) {
958 case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
959 OnAuthChallenge(response, error_code->code());
960 break;
961 case STUN_ERROR_TRY_ALTERNATE:
962 OnTryAlternate(response, error_code->code());
963 break;
964 case STUN_ERROR_ALLOCATION_MISMATCH:
965 // We must handle this error async because trying to delete the socket in
966 // OnErrorResponse will cause a deadlock on the socket.
967 port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH);
968 break;
969 default:
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700970 LOG_J(LS_WARNING, port_) << "Received TURN allocate error response"
971 << ", id=" << rtc::hex_encode(id())
972 << ", code=" << error_code->code()
973 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000974 port_->OnAllocateError();
975 }
976}
977
978void TurnAllocateRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700979 LOG_J(LS_WARNING, port_) << "TURN allocate request "
980 << rtc::hex_encode(id()) << " timout";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000981 port_->OnAllocateRequestTimeout();
982}
983
984void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
985 // If we failed to authenticate even after we sent our credentials, fail hard.
986 if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
987 LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
988 << "after challenge.";
989 port_->OnAllocateError();
990 return;
991 }
992
993 // Check the mandatory attributes.
994 const StunByteStringAttribute* realm_attr =
995 response->GetByteString(STUN_ATTR_REALM);
996 if (!realm_attr) {
997 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
998 << "allocate unauthorized response.";
999 return;
1000 }
1001 port_->set_realm(realm_attr->GetString());
1002
1003 const StunByteStringAttribute* nonce_attr =
1004 response->GetByteString(STUN_ATTR_NONCE);
1005 if (!nonce_attr) {
1006 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
1007 << "allocate unauthorized response.";
1008 return;
1009 }
1010 port_->set_nonce(nonce_attr->GetString());
1011
1012 // Send another allocate request, with the received realm and nonce values.
1013 port_->SendRequest(new TurnAllocateRequest(port_), 0);
1014}
1015
1016void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001017
1018 // According to RFC 5389 section 11, there are use cases where
1019 // authentication of response is not possible, we're not validating
1020 // message integrity.
1021
1022 // Get the alternate server address attribute value.
1023 const StunAddressAttribute* alternate_server_attr =
1024 response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1025 if (!alternate_server_attr) {
1026 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
1027 << "attribute in try alternate error response";
1028 port_->OnAllocateError();
1029 return;
1030 }
1031 if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1032 port_->OnAllocateError();
1033 return;
1034 }
1035
1036 // Check the attributes.
1037 const StunByteStringAttribute* realm_attr =
1038 response->GetByteString(STUN_ATTR_REALM);
1039 if (realm_attr) {
1040 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
1041 << "try alternate error response.";
1042 port_->set_realm(realm_attr->GetString());
1043 }
1044
1045 const StunByteStringAttribute* nonce_attr =
1046 response->GetByteString(STUN_ATTR_NONCE);
1047 if (nonce_attr) {
1048 LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
1049 << "try alternate error response.";
1050 port_->set_nonce(nonce_attr->GetString());
1051 }
1052
guoweis@webrtc.org19e4e8d2015-01-10 02:41:32 +00001053 // For TCP, we can't close the original Tcp socket during handling a 300 as
1054 // we're still inside that socket's event handler. Doing so will cause
1055 // deadlock.
1056 port_->thread()->Post(port_, TurnPort::MSG_TRY_ALTERNATE_SERVER);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001057}
1058
1059TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
1060 : StunRequest(new TurnMessage()),
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001061 port_(port),
1062 lifetime_(-1) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001063}
1064
1065void TurnRefreshRequest::Prepare(StunMessage* request) {
1066 // Create the request as indicated in RFC 5766, Section 7.1.
1067 // No attributes need to be included.
1068 request->SetType(TURN_REFRESH_REQUEST);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +00001069 if (lifetime_ > -1) {
1070 VERIFY(request->AddAttribute(new StunUInt32Attribute(
1071 STUN_ATTR_LIFETIME, lifetime_)));
1072 }
1073
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001074 port_->AddRequestAuthInfo(request);
1075}
1076
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001077void TurnRefreshRequest::OnSent() {
1078 LOG_J(LS_INFO, port_) << "TURN refresh request sent"
1079 << ", id=" << rtc::hex_encode(id());
1080 StunRequest::OnSent();
1081}
1082
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001083void TurnRefreshRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001084 LOG_J(LS_INFO, port_) << "TURN refresh requested successfully"
1085 << ", id=" << rtc::hex_encode(id())
1086 << ", code=0" // Makes logging easier to parse.
1087 << ", rtt=" << Elapsed();
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001088
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001089 // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1090 const StunUInt32Attribute* lifetime_attr =
1091 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1092 if (!lifetime_attr) {
1093 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1094 << "refresh success response.";
1095 return;
1096 }
1097
1098 // Schedule a refresh based on the returned lifetime value.
1099 port_->ScheduleRefresh(lifetime_attr->value());
1100}
1101
1102void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
1103 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001104
1105 LOG_J(LS_INFO, port_) << "Received TURN refresh error response"
1106 << ", id=" << rtc::hex_encode(id())
1107 << ", code=" << error_code->code()
1108 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001109
1110 if (error_code->code() == STUN_ERROR_STALE_NONCE) {
1111 if (port_->UpdateNonce(response)) {
1112 // Send RefreshRequest immediately.
1113 port_->SendRequest(new TurnRefreshRequest(port_), 0);
1114 }
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001115 } else {
1116 LOG_J(LS_WARNING, port_) << "Received TURN refresh error response"
1117 << ", id=" << rtc::hex_encode(id())
1118 << ", code=" << error_code->code()
1119 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001120 }
1121}
1122
1123void TurnRefreshRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001124 LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001125}
1126
1127TurnCreatePermissionRequest::TurnCreatePermissionRequest(
1128 TurnPort* port, TurnEntry* entry,
1129 const rtc::SocketAddress& ext_addr)
1130 : StunRequest(new TurnMessage()),
1131 port_(port),
1132 entry_(entry),
1133 ext_addr_(ext_addr) {
1134 entry_->SignalDestroyed.connect(
1135 this, &TurnCreatePermissionRequest::OnEntryDestroyed);
1136}
1137
1138void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
1139 // Create the request as indicated in RFC5766, Section 9.1.
1140 request->SetType(TURN_CREATE_PERMISSION_REQUEST);
1141 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1142 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1143 port_->AddRequestAuthInfo(request);
1144}
1145
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001146void TurnCreatePermissionRequest::OnSent() {
1147 LOG_J(LS_INFO, port_) << "TURN create permission request sent"
1148 << ", id=" << rtc::hex_encode(id());
1149 StunRequest::OnSent();
1150}
1151
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001152void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001153 LOG_J(LS_INFO, port_) << "TURN permission requested successfully"
1154 << ", id=" << rtc::hex_encode(id())
1155 << ", code=0" // Makes logging easier to parse.
1156 << ", rtt=" << Elapsed();
1157
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001158 if (entry_) {
1159 entry_->OnCreatePermissionSuccess();
1160 }
1161}
1162
1163void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001164 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001165 LOG_J(LS_WARNING, port_) << "Received TURN create permission error response"
1166 << ", id=" << rtc::hex_encode(id())
1167 << ", code=" << error_code->code()
1168 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001169 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001170 entry_->OnCreatePermissionError(response, error_code->code());
1171 }
1172}
1173
1174void TurnCreatePermissionRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001175 LOG_J(LS_WARNING, port_) << "TURN create permission timeout "
1176 << rtc::hex_encode(id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001177}
1178
1179void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
1180 ASSERT(entry_ == entry);
1181 entry_ = NULL;
1182}
1183
1184TurnChannelBindRequest::TurnChannelBindRequest(
1185 TurnPort* port, TurnEntry* entry,
1186 int channel_id, const rtc::SocketAddress& ext_addr)
1187 : StunRequest(new TurnMessage()),
1188 port_(port),
1189 entry_(entry),
1190 channel_id_(channel_id),
1191 ext_addr_(ext_addr) {
1192 entry_->SignalDestroyed.connect(
1193 this, &TurnChannelBindRequest::OnEntryDestroyed);
1194}
1195
1196void TurnChannelBindRequest::Prepare(StunMessage* request) {
1197 // Create the request as indicated in RFC5766, Section 11.1.
1198 request->SetType(TURN_CHANNEL_BIND_REQUEST);
1199 VERIFY(request->AddAttribute(new StunUInt32Attribute(
1200 STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)));
1201 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1202 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1203 port_->AddRequestAuthInfo(request);
1204}
1205
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001206void TurnChannelBindRequest::OnSent() {
1207 LOG_J(LS_INFO, port_) << "TURN channel bind request sent"
1208 << ", id=" << rtc::hex_encode(id());
1209 StunRequest::OnSent();
1210}
1211
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001212void TurnChannelBindRequest::OnResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001213 LOG_J(LS_INFO, port_) << "TURN channel bind requested successfully"
1214 << ", id=" << rtc::hex_encode(id())
1215 << ", code=0" // Makes logging easier to parse.
1216 << ", rtt=" << Elapsed();
1217
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001218 if (entry_) {
1219 entry_->OnChannelBindSuccess();
1220 // Refresh the channel binding just under the permission timeout
1221 // threshold. The channel binding has a longer lifetime, but
1222 // this is the easiest way to keep both the channel and the
1223 // permission from expiring.
Peter Thatcherb32a5c42015-04-10 14:04:42 -07001224 int delay = TURN_PERMISSION_TIMEOUT - 60000;
1225 entry_->SendChannelBindRequest(delay);
1226 LOG_J(LS_INFO, port_) << "Scheduled channel bind in " << delay << "ms.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001227 }
1228}
1229
1230void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001231 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
1232 LOG_J(LS_WARNING, port_) << "Received TURN channel bind error response"
1233 << ", id=" << rtc::hex_encode(id())
1234 << ", code=" << error_code->code()
1235 << ", rtt=" << Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001236 if (entry_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001237 entry_->OnChannelBindError(response, error_code->code());
1238 }
1239}
1240
1241void TurnChannelBindRequest::OnTimeout() {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001242 LOG_J(LS_WARNING, port_) << "TURN channel bind timeout "
1243 << rtc::hex_encode(id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001244}
1245
1246void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
1247 ASSERT(entry_ == entry);
1248 entry_ = NULL;
1249}
1250
1251TurnEntry::TurnEntry(TurnPort* port, int channel_id,
1252 const rtc::SocketAddress& ext_addr)
1253 : port_(port),
1254 channel_id_(channel_id),
1255 ext_addr_(ext_addr),
1256 state_(STATE_UNBOUND) {
1257 // Creating permission for |ext_addr_|.
1258 SendCreatePermissionRequest();
1259}
1260
1261void TurnEntry::SendCreatePermissionRequest() {
1262 port_->SendRequest(new TurnCreatePermissionRequest(
1263 port_, this, ext_addr_), 0);
1264}
1265
1266void TurnEntry::SendChannelBindRequest(int delay) {
1267 port_->SendRequest(new TurnChannelBindRequest(
1268 port_, this, channel_id_, ext_addr_), delay);
1269}
1270
1271int TurnEntry::Send(const void* data, size_t size, bool payload,
1272 const rtc::PacketOptions& options) {
1273 rtc::ByteBuffer buf;
1274 if (state_ != STATE_BOUND) {
1275 // If we haven't bound the channel yet, we have to use a Send Indication.
1276 TurnMessage msg;
1277 msg.SetType(TURN_SEND_INDICATION);
1278 msg.SetTransactionID(
1279 rtc::CreateRandomString(kStunTransactionIdLength));
1280 VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
1281 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1282 VERIFY(msg.AddAttribute(new StunByteStringAttribute(
1283 STUN_ATTR_DATA, data, size)));
1284 VERIFY(msg.Write(&buf));
1285
1286 // If we're sending real data, request a channel bind that we can use later.
1287 if (state_ == STATE_UNBOUND && payload) {
1288 SendChannelBindRequest(0);
1289 state_ = STATE_BINDING;
1290 }
1291 } else {
1292 // If the channel is bound, we can send the data as a Channel Message.
1293 buf.WriteUInt16(channel_id_);
1294 buf.WriteUInt16(static_cast<uint16>(size));
1295 buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1296 }
1297 return port_->Send(buf.Data(), buf.Length(), options);
1298}
1299
1300void TurnEntry::OnCreatePermissionSuccess() {
1301 LOG_J(LS_INFO, port_) << "Create permission for "
1302 << ext_addr_.ToSensitiveString()
1303 << " succeeded";
1304 // For success result code will be 0.
1305 port_->SignalCreatePermissionResult(port_, ext_addr_, 0);
1306}
1307
1308void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001309 if (code == STUN_ERROR_STALE_NONCE) {
1310 if (port_->UpdateNonce(response)) {
1311 SendCreatePermissionRequest();
1312 }
1313 } else {
1314 // Send signal with error code.
1315 port_->SignalCreatePermissionResult(port_, ext_addr_, code);
1316 }
1317}
1318
1319void TurnEntry::OnChannelBindSuccess() {
1320 LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
1321 << " succeeded";
1322 ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND);
1323 state_ = STATE_BOUND;
1324}
1325
1326void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
1327 // TODO(mallinath) - Implement handling of error response for channel
1328 // bind request as per http://tools.ietf.org/html/rfc5766#section-11.3
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001329 if (code == STUN_ERROR_STALE_NONCE) {
1330 if (port_->UpdateNonce(response)) {
1331 // Send channel bind request with fresh nonce.
1332 SendChannelBindRequest(0);
1333 }
1334 }
1335}
1336
1337} // namespace cricket