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