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