3 * Copyright 2012, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "talk/p2p/base/turnport.h"
32 #include "talk/base/asyncpacketsocket.h"
33 #include "talk/base/byteorder.h"
34 #include "talk/base/common.h"
35 #include "talk/base/logging.h"
36 #include "talk/base/nethelpers.h"
37 #include "talk/base/socketaddress.h"
38 #include "talk/base/stringencode.h"
39 #include "talk/p2p/base/common.h"
40 #include "talk/p2p/base/stun.h"
44 // TODO(juberti): Move to stun.h when relay messages have been renamed.
45 static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
46 static const int TURN_ALLOCATE_ERROR_RESPONSE = STUN_ALLOCATE_ERROR_RESPONSE;
48 // TODO(juberti): Extract to turnmessage.h
49 static const int TURN_DEFAULT_PORT = 3478;
50 static const int TURN_CHANNEL_NUMBER_START = 0x4000;
51 static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
53 static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
55 inline bool IsTurnChannelData(uint16 msg_type) {
56 return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
59 static int GetRelayPreference(cricket::ProtocolType proto, bool secure) {
60 int relay_preference = ICE_TYPE_PREFERENCE_RELAY;
61 if (proto == cricket::PROTO_TCP) {
62 relay_preference -= 1;
64 relay_preference -= 1;
67 ASSERT(relay_preference >= 0);
68 return relay_preference;
71 class TurnAllocateRequest : public StunRequest {
73 explicit TurnAllocateRequest(TurnPort* port);
74 virtual void Prepare(StunMessage* request);
75 virtual void OnResponse(StunMessage* response);
76 virtual void OnErrorResponse(StunMessage* response);
77 virtual void OnTimeout();
80 // Handles authentication challenge from the server.
81 void OnAuthChallenge(StunMessage* response, int code);
82 void OnUnknownAttribute(StunMessage* response);
87 class TurnRefreshRequest : public StunRequest {
89 explicit TurnRefreshRequest(TurnPort* port);
90 virtual void Prepare(StunMessage* request);
91 virtual void OnResponse(StunMessage* response);
92 virtual void OnErrorResponse(StunMessage* response);
93 virtual void OnTimeout();
99 class TurnCreatePermissionRequest : public StunRequest,
100 public sigslot::has_slots<> {
102 TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
103 const talk_base::SocketAddress& ext_addr);
104 virtual void Prepare(StunMessage* request);
105 virtual void OnResponse(StunMessage* response);
106 virtual void OnErrorResponse(StunMessage* response);
107 virtual void OnTimeout();
110 void OnEntryDestroyed(TurnEntry* entry);
114 talk_base::SocketAddress ext_addr_;
117 class TurnChannelBindRequest : public StunRequest,
118 public sigslot::has_slots<> {
120 TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
121 const talk_base::SocketAddress& ext_addr);
122 virtual void Prepare(StunMessage* request);
123 virtual void OnResponse(StunMessage* response);
124 virtual void OnErrorResponse(StunMessage* response);
125 virtual void OnTimeout();
128 void OnEntryDestroyed(TurnEntry* entry);
133 talk_base::SocketAddress ext_addr_;
136 // Manages a "connection" to a remote destination. We will attempt to bring up
137 // a channel for this remote destination to reduce the overhead of sending data.
138 class TurnEntry : public sigslot::has_slots<> {
140 enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
141 TurnEntry(TurnPort* port, int channel_id,
142 const talk_base::SocketAddress& ext_addr);
144 TurnPort* port() { return port_; }
146 int channel_id() const { return channel_id_; }
147 const talk_base::SocketAddress& address() const { return ext_addr_; }
148 BindState state() const { return state_; }
150 // Helper methods to send permission and channel bind requests.
151 void SendCreatePermissionRequest();
152 void SendChannelBindRequest(int delay);
153 // Sends a packet to the given destination address.
154 // This will wrap the packet in STUN if necessary.
155 int Send(const void* data, size_t size, bool payload,
156 const talk_base::PacketOptions& options);
158 void OnCreatePermissionSuccess();
159 void OnCreatePermissionError(StunMessage* response, int code);
160 void OnChannelBindSuccess();
161 void OnChannelBindError(StunMessage* response, int code);
162 // Signal sent when TurnEntry is destroyed.
163 sigslot::signal1<TurnEntry*> SignalDestroyed;
168 talk_base::SocketAddress ext_addr_;
172 TurnPort::TurnPort(talk_base::Thread* thread,
173 talk_base::PacketSocketFactory* factory,
174 talk_base::Network* network,
175 const talk_base::IPAddress& ip,
176 int min_port, int max_port,
177 const std::string& username,
178 const std::string& password,
179 const ProtocolAddress& server_address,
180 const RelayCredentials& credentials)
181 : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port,
183 server_address_(server_address),
184 credentials_(credentials),
187 request_manager_(thread),
188 next_channel_number_(TURN_CHANNEL_NUMBER_START),
190 request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
193 TurnPort::~TurnPort() {
194 // TODO(juberti): Should this even be necessary?
195 while (!entries_.empty()) {
196 DestroyEntry(entries_.front()->address());
199 resolver_->Destroy(false);
203 void TurnPort::PrepareAddress() {
204 if (credentials_.username.empty() ||
205 credentials_.password.empty()) {
206 LOG(LS_ERROR) << "Allocation can't be started without setting the"
207 << " TURN server credentials for the user.";
212 if (!server_address_.address.port()) {
213 // We will set default TURN port, if no port is set in the address.
214 server_address_.address.SetPort(TURN_DEFAULT_PORT);
217 if (server_address_.address.IsUnresolved()) {
218 ResolveTurnAddress(server_address_.address);
220 // If protocol family of server address doesn't match with local, return.
221 if (!IsCompatibleAddress(server_address_.address)) {
222 LOG(LS_ERROR) << "Server IP address family does not match with "
223 << "local host address family type";
228 LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
229 << ProtoToString(server_address_.proto) << " @ "
230 << server_address_.address.ToSensitiveString();
231 if (server_address_.proto == PROTO_UDP) {
232 socket_.reset(socket_factory()->CreateUdpSocket(
233 talk_base::SocketAddress(ip(), 0), min_port(), max_port()));
234 } else if (server_address_.proto == PROTO_TCP) {
235 int opts = talk_base::PacketSocketFactory::OPT_STUN;
236 // If secure bit is enabled in server address, use TLS over TCP.
237 if (server_address_.secure) {
238 opts |= talk_base::PacketSocketFactory::OPT_TLS;
241 socket_.reset(socket_factory()->CreateClientTcpSocket(
242 talk_base::SocketAddress(ip(), 0), server_address_.address,
243 proxy(), user_agent(), opts));
251 // Apply options if any.
252 for (SocketOptionsMap::iterator iter = socket_options_.begin();
253 iter != socket_options_.end(); ++iter) {
254 socket_->SetOption(iter->first, iter->second);
257 socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
258 socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
260 if (server_address_.proto == PROTO_TCP) {
261 socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
262 socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
264 // If its UDP, send AllocateRequest now.
265 // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
266 SendRequest(new TurnAllocateRequest(this), 0);
271 void TurnPort::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
272 LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
274 SendRequest(new TurnAllocateRequest(this), 0);
277 void TurnPort::OnSocketClose(talk_base::AsyncPacketSocket* socket, int error) {
278 LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
284 Connection* TurnPort::CreateConnection(const Candidate& address,
285 CandidateOrigin origin) {
286 // TURN-UDP can only connect to UDP candidates.
287 if (address.protocol() != UDP_PROTOCOL_NAME) {
291 if (!IsCompatibleAddress(address.address())) {
295 // Create an entry, if needed, so we can get our permissions set up correctly.
296 CreateEntry(address.address());
298 // TODO(juberti): The '0' index will need to change if we start gathering STUN
299 // candidates on this port.
300 ProxyConnection* conn = new ProxyConnection(this, 0, address);
301 conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
306 int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
308 // If socket is not created yet, these options will be applied during socket
310 socket_options_[opt] = value;
313 return socket_->SetOption(opt, value);
316 int TurnPort::GetOption(talk_base::Socket::Option opt, int* value) {
318 SocketOptionsMap::const_iterator it = socket_options_.find(opt);
319 if (it == socket_options_.end()) {
326 return socket_->GetOption(opt, value);
329 int TurnPort::GetError() {
333 int TurnPort::SendTo(const void* data, size_t size,
334 const talk_base::SocketAddress& addr,
335 const talk_base::PacketOptions& options,
337 // Try to find an entry for this specific address; we should have one.
338 TurnEntry* entry = FindEntry(addr);
339 ASSERT(entry != NULL);
345 error_ = EWOULDBLOCK;
349 // Send the actual contents to the server using the usual mechanism.
350 int sent = entry->Send(data, size, payload, options);
355 // The caller of the function is expecting the number of user data bytes,
356 // rather than the size of the packet.
357 return static_cast<int>(size);
360 void TurnPort::OnReadPacket(
361 talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
362 const talk_base::SocketAddress& remote_addr,
363 const talk_base::PacketTime& packet_time) {
364 ASSERT(socket == socket_.get());
365 ASSERT(remote_addr == server_address_.address);
367 // The message must be at least the size of a channel header.
368 if (size < TURN_CHANNEL_HEADER_SIZE) {
369 LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
373 // Check the message type, to see if is a Channel Data message.
374 // The message will either be channel data, a TURN data indication, or
375 // a response to a previous request.
376 uint16 msg_type = talk_base::GetBE16(data);
377 if (IsTurnChannelData(msg_type)) {
378 HandleChannelData(msg_type, data, size, packet_time);
379 } else if (msg_type == TURN_DATA_INDICATION) {
380 HandleDataIndication(data, size, packet_time);
382 // This must be a response for one of our requests.
383 // Check success responses, but not errors, for MESSAGE-INTEGRITY.
384 if (IsStunSuccessResponseType(msg_type) &&
385 !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
386 LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
387 << "message integrity, msg_type=" << msg_type;
390 request_manager_.CheckResponse(data, size);
394 void TurnPort::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
396 Port::OnReadyToSend();
400 void TurnPort::ResolveTurnAddress(const talk_base::SocketAddress& address) {
404 resolver_ = socket_factory()->CreateAsyncResolver();
405 resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
406 resolver_->Start(address);
409 void TurnPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
410 ASSERT(resolver == resolver_);
411 if (resolver_->GetError() != 0 ||
412 !resolver_->GetResolvedAddress(ip().family(), &server_address_.address)) {
413 LOG_J(LS_WARNING, this) << "TURN host lookup received error "
414 << resolver_->GetError();
422 void TurnPort::OnSendStunPacket(const void* data, size_t size,
423 StunRequest* request) {
424 talk_base::PacketOptions options(DefaultDscpValue());
425 if (Send(data, size, options) < 0) {
426 LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
427 << socket_->GetError();
431 void TurnPort::OnStunAddress(const talk_base::SocketAddress& address) {
432 // For relay, mapped address is rel-addr.
433 set_related_address(address);
436 void TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address) {
439 socket_->GetLocalAddress(),
442 GetRelayPreference(server_address_.proto, server_address_.secure),
446 void TurnPort::OnAllocateError() {
447 // We will send SignalPortError asynchronously as this can be sent during
448 // port initialization. This way it will not be blocking other port
450 thread()->Post(this, MSG_ERROR);
453 void TurnPort::OnMessage(talk_base::Message* message) {
454 if (message->message_id == MSG_ERROR) {
455 SignalPortError(this);
459 Port::OnMessage(message);
462 void TurnPort::OnAllocateRequestTimeout() {
466 void TurnPort::HandleDataIndication(const char* data, size_t size,
467 const talk_base::PacketTime& packet_time) {
468 // Read in the message, and process according to RFC5766, Section 10.4.
469 talk_base::ByteBuffer buf(data, size);
471 if (!msg.Read(&buf)) {
472 LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
476 // Check mandatory attributes.
477 const StunAddressAttribute* addr_attr =
478 msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
480 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
481 << "in data indication.";
485 const StunByteStringAttribute* data_attr =
486 msg.GetByteString(STUN_ATTR_DATA);
488 LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
489 << "data indication.";
493 // Verify that the data came from somewhere we think we have a permission for.
494 talk_base::SocketAddress ext_addr(addr_attr->GetAddress());
495 if (!HasPermission(ext_addr.ipaddr())) {
496 LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
497 << "peer address, addr="
498 << ext_addr.ToSensitiveString();
502 DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
503 PROTO_UDP, packet_time);
506 void TurnPort::HandleChannelData(int channel_id, const char* data,
508 const talk_base::PacketTime& packet_time) {
509 // Read the message, and process according to RFC5766, Section 11.6.
511 // 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
512 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513 // | Channel Number | Length |
514 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516 // / Application Data /
519 // | +-------------------------------+
521 // +-------------------------------+
523 // Extract header fields from the message.
524 uint16 len = talk_base::GetBE16(data + 2);
525 if (len > size - TURN_CHANNEL_HEADER_SIZE) {
526 LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
527 << "incorrect length, len=" << len;
530 // Allowing messages larger than |len|, as ChannelData can be padded.
532 TurnEntry* entry = FindEntry(channel_id);
534 LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
535 << "channel, channel_id=" << channel_id;
539 DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
540 PROTO_UDP, packet_time);
543 void TurnPort::DispatchPacket(const char* data, size_t size,
544 const talk_base::SocketAddress& remote_addr,
545 ProtocolType proto, const talk_base::PacketTime& packet_time) {
546 if (Connection* conn = GetConnection(remote_addr)) {
547 conn->OnReadPacket(data, size, packet_time);
549 Port::OnReadPacket(data, size, remote_addr, proto);
553 bool TurnPort::ScheduleRefresh(int lifetime) {
554 // Lifetime is in seconds; we schedule a refresh for one minute less.
555 if (lifetime < 2 * 60) {
556 LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
557 << "too short, lifetime=" << lifetime;
561 SendRequest(new TurnRefreshRequest(this), (lifetime - 60) * 1000);
565 void TurnPort::SendRequest(StunRequest* req, int delay) {
566 request_manager_.SendDelayed(req, delay);
569 void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
570 // If we've gotten the necessary data from the server, add it to our request.
571 VERIFY(!hash_.empty());
572 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
573 STUN_ATTR_USERNAME, credentials_.username)));
574 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
575 STUN_ATTR_REALM, realm_)));
576 VERIFY(msg->AddAttribute(new StunByteStringAttribute(
577 STUN_ATTR_NONCE, nonce_)));
578 VERIFY(msg->AddMessageIntegrity(hash()));
581 int TurnPort::Send(const void* data, size_t len,
582 const talk_base::PacketOptions& options) {
583 return socket_->SendTo(data, len, server_address_.address, options);
586 void TurnPort::UpdateHash() {
587 VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
588 credentials_.password, &hash_));
591 bool TurnPort::UpdateNonce(StunMessage* response) {
592 // When stale nonce error received, we should update
593 // hash and store realm and nonce.
594 // Check the mandatory attributes.
595 const StunByteStringAttribute* realm_attr =
596 response->GetByteString(STUN_ATTR_REALM);
598 LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
599 << "stale nonce error response.";
602 set_realm(realm_attr->GetString());
604 const StunByteStringAttribute* nonce_attr =
605 response->GetByteString(STUN_ATTR_NONCE);
607 LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
608 << "stale nonce error response.";
611 set_nonce(nonce_attr->GetString());
615 static bool MatchesIP(TurnEntry* e, talk_base::IPAddress ipaddr) {
616 return e->address().ipaddr() == ipaddr;
618 bool TurnPort::HasPermission(const talk_base::IPAddress& ipaddr) const {
619 return (std::find_if(entries_.begin(), entries_.end(),
620 std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
623 static bool MatchesAddress(TurnEntry* e, talk_base::SocketAddress addr) {
624 return e->address() == addr;
626 TurnEntry* TurnPort::FindEntry(const talk_base::SocketAddress& addr) const {
627 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
628 std::bind2nd(std::ptr_fun(MatchesAddress), addr));
629 return (it != entries_.end()) ? *it : NULL;
632 static bool MatchesChannelId(TurnEntry* e, int id) {
633 return e->channel_id() == id;
635 TurnEntry* TurnPort::FindEntry(int channel_id) const {
636 EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
637 std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
638 return (it != entries_.end()) ? *it : NULL;
641 TurnEntry* TurnPort::CreateEntry(const talk_base::SocketAddress& addr) {
642 ASSERT(FindEntry(addr) == NULL);
643 TurnEntry* entry = new TurnEntry(this, next_channel_number_++, addr);
644 entries_.push_back(entry);
648 void TurnPort::DestroyEntry(const talk_base::SocketAddress& addr) {
649 TurnEntry* entry = FindEntry(addr);
650 ASSERT(entry != NULL);
651 entry->SignalDestroyed(entry);
652 entries_.remove(entry);
656 void TurnPort::OnConnectionDestroyed(Connection* conn) {
657 // Destroying TurnEntry for the connection, which is already destroyed.
658 DestroyEntry(conn->remote_candidate().address());
661 TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
662 : StunRequest(new TurnMessage()),
666 void TurnAllocateRequest::Prepare(StunMessage* request) {
667 // Create the request as indicated in RFC 5766, Section 6.1.
668 request->SetType(TURN_ALLOCATE_REQUEST);
669 StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
670 STUN_ATTR_REQUESTED_TRANSPORT);
671 transport_attr->SetValue(IPPROTO_UDP << 24);
672 VERIFY(request->AddAttribute(transport_attr));
673 if (!port_->hash().empty()) {
674 port_->AddRequestAuthInfo(request);
678 void TurnAllocateRequest::OnResponse(StunMessage* response) {
679 // Check mandatory attributes as indicated in RFC5766, Section 6.3.
680 const StunAddressAttribute* mapped_attr =
681 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
683 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
684 << "attribute in allocate success response";
688 // TODO(mallinath) - Use mapped address for STUN candidate.
689 port_->OnStunAddress(mapped_attr->GetAddress());
691 const StunAddressAttribute* relayed_attr =
692 response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
694 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
695 << "attribute in allocate success response";
699 const StunUInt32Attribute* lifetime_attr =
700 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
701 if (!lifetime_attr) {
702 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
703 << "allocate success response";
706 // Notify the port the allocate succeeded, and schedule a refresh request.
707 port_->OnAllocateSuccess(relayed_attr->GetAddress());
708 port_->ScheduleRefresh(lifetime_attr->value());
711 void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
712 // Process error response according to RFC5766, Section 6.4.
713 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
714 switch (error_code->code()) {
715 case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
716 OnAuthChallenge(response, error_code->code());
719 LOG_J(LS_WARNING, port_) << "Allocate response error, code="
720 << error_code->code();
721 port_->OnAllocateError();
725 void TurnAllocateRequest::OnTimeout() {
726 LOG_J(LS_WARNING, port_) << "Allocate request timeout";
727 port_->OnAllocateRequestTimeout();
730 void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
731 // If we failed to authenticate even after we sent our credentials, fail hard.
732 if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
733 LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
734 << "after challenge.";
735 port_->OnAllocateError();
739 // Check the mandatory attributes.
740 const StunByteStringAttribute* realm_attr =
741 response->GetByteString(STUN_ATTR_REALM);
743 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
744 << "allocate unauthorized response.";
747 port_->set_realm(realm_attr->GetString());
749 const StunByteStringAttribute* nonce_attr =
750 response->GetByteString(STUN_ATTR_NONCE);
752 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
753 << "allocate unauthorized response.";
756 port_->set_nonce(nonce_attr->GetString());
758 // Send another allocate request, with the received realm and nonce values.
759 port_->SendRequest(new TurnAllocateRequest(port_), 0);
762 TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
763 : StunRequest(new TurnMessage()),
767 void TurnRefreshRequest::Prepare(StunMessage* request) {
768 // Create the request as indicated in RFC 5766, Section 7.1.
769 // No attributes need to be included.
770 request->SetType(TURN_REFRESH_REQUEST);
771 port_->AddRequestAuthInfo(request);
774 void TurnRefreshRequest::OnResponse(StunMessage* response) {
775 // Check mandatory attributes as indicated in RFC5766, Section 7.3.
776 const StunUInt32Attribute* lifetime_attr =
777 response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
778 if (!lifetime_attr) {
779 LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
780 << "refresh success response.";
784 // Schedule a refresh based on the returned lifetime value.
785 port_->ScheduleRefresh(lifetime_attr->value());
788 void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
789 // TODO(juberti): Handle 437 error response as a success.
790 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
791 LOG_J(LS_WARNING, port_) << "Refresh response error, code="
792 << error_code->code();
794 if (error_code->code() == STUN_ERROR_STALE_NONCE) {
795 if (port_->UpdateNonce(response)) {
796 // Send RefreshRequest immediately.
797 port_->SendRequest(new TurnRefreshRequest(port_), 0);
802 void TurnRefreshRequest::OnTimeout() {
805 TurnCreatePermissionRequest::TurnCreatePermissionRequest(
806 TurnPort* port, TurnEntry* entry,
807 const talk_base::SocketAddress& ext_addr)
808 : StunRequest(new TurnMessage()),
811 ext_addr_(ext_addr) {
812 entry_->SignalDestroyed.connect(
813 this, &TurnCreatePermissionRequest::OnEntryDestroyed);
816 void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
817 // Create the request as indicated in RFC5766, Section 9.1.
818 request->SetType(TURN_CREATE_PERMISSION_REQUEST);
819 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
820 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
821 port_->AddRequestAuthInfo(request);
824 void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
826 entry_->OnCreatePermissionSuccess();
830 void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
832 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
833 entry_->OnCreatePermissionError(response, error_code->code());
837 void TurnCreatePermissionRequest::OnTimeout() {
838 LOG_J(LS_WARNING, port_) << "Create permission timeout";
841 void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
842 ASSERT(entry_ == entry);
846 TurnChannelBindRequest::TurnChannelBindRequest(
847 TurnPort* port, TurnEntry* entry,
848 int channel_id, const talk_base::SocketAddress& ext_addr)
849 : StunRequest(new TurnMessage()),
852 channel_id_(channel_id),
853 ext_addr_(ext_addr) {
854 entry_->SignalDestroyed.connect(
855 this, &TurnChannelBindRequest::OnEntryDestroyed);
858 void TurnChannelBindRequest::Prepare(StunMessage* request) {
859 // Create the request as indicated in RFC5766, Section 11.1.
860 request->SetType(TURN_CHANNEL_BIND_REQUEST);
861 VERIFY(request->AddAttribute(new StunUInt32Attribute(
862 STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)));
863 VERIFY(request->AddAttribute(new StunXorAddressAttribute(
864 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
865 port_->AddRequestAuthInfo(request);
868 void TurnChannelBindRequest::OnResponse(StunMessage* response) {
870 entry_->OnChannelBindSuccess();
871 // Refresh the channel binding just under the permission timeout
872 // threshold. The channel binding has a longer lifetime, but
873 // this is the easiest way to keep both the channel and the
874 // permission from expiring.
875 entry_->SendChannelBindRequest(TURN_PERMISSION_TIMEOUT - 60 * 1000);
879 void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
881 const StunErrorCodeAttribute* error_code = response->GetErrorCode();
882 entry_->OnChannelBindError(response, error_code->code());
886 void TurnChannelBindRequest::OnTimeout() {
887 LOG_J(LS_WARNING, port_) << "Channel bind timeout";
890 void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
891 ASSERT(entry_ == entry);
895 TurnEntry::TurnEntry(TurnPort* port, int channel_id,
896 const talk_base::SocketAddress& ext_addr)
898 channel_id_(channel_id),
900 state_(STATE_UNBOUND) {
901 // Creating permission for |ext_addr_|.
902 SendCreatePermissionRequest();
905 void TurnEntry::SendCreatePermissionRequest() {
906 port_->SendRequest(new TurnCreatePermissionRequest(
907 port_, this, ext_addr_), 0);
910 void TurnEntry::SendChannelBindRequest(int delay) {
911 port_->SendRequest(new TurnChannelBindRequest(
912 port_, this, channel_id_, ext_addr_), delay);
915 int TurnEntry::Send(const void* data, size_t size, bool payload,
916 const talk_base::PacketOptions& options) {
917 talk_base::ByteBuffer buf;
918 if (state_ != STATE_BOUND) {
919 // If we haven't bound the channel yet, we have to use a Send Indication.
921 msg.SetType(TURN_SEND_INDICATION);
922 msg.SetTransactionID(
923 talk_base::CreateRandomString(kStunTransactionIdLength));
924 VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
925 STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
926 VERIFY(msg.AddAttribute(new StunByteStringAttribute(
927 STUN_ATTR_DATA, data, size)));
928 VERIFY(msg.Write(&buf));
930 // If we're sending real data, request a channel bind that we can use later.
931 if (state_ == STATE_UNBOUND && payload) {
932 SendChannelBindRequest(0);
933 state_ = STATE_BINDING;
936 // If the channel is bound, we can send the data as a Channel Message.
937 buf.WriteUInt16(channel_id_);
938 buf.WriteUInt16(static_cast<uint16>(size));
939 buf.WriteBytes(reinterpret_cast<const char*>(data), size);
941 return port_->Send(buf.Data(), buf.Length(), options);
944 void TurnEntry::OnCreatePermissionSuccess() {
945 LOG_J(LS_INFO, port_) << "Create permission for "
946 << ext_addr_.ToSensitiveString()
948 // For success result code will be 0.
949 port_->SignalCreatePermissionResult(port_, ext_addr_, 0);
952 void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
953 LOG_J(LS_WARNING, port_) << "Create permission for "
954 << ext_addr_.ToSensitiveString()
955 << " failed, code=" << code;
956 if (code == STUN_ERROR_STALE_NONCE) {
957 if (port_->UpdateNonce(response)) {
958 SendCreatePermissionRequest();
961 // Send signal with error code.
962 port_->SignalCreatePermissionResult(port_, ext_addr_, code);
966 void TurnEntry::OnChannelBindSuccess() {
967 LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
969 ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND);
970 state_ = STATE_BOUND;
973 void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
974 // TODO(mallinath) - Implement handling of error response for channel
975 // bind request as per http://tools.ietf.org/html/rfc5766#section-11.3
976 LOG_J(LS_WARNING, port_) << "Channel bind for "
977 << ext_addr_.ToSensitiveString()
978 << " failed, code=" << code;
979 if (code == STUN_ERROR_STALE_NONCE) {
980 if (port_->UpdateNonce(response)) {
981 // Send channel bind request with fresh nonce.
982 SendChannelBindRequest(0);
987 } // namespace cricket