15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/* 25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle 35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2012, Google Inc. 45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without 65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met: 75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer. 105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer in the documentation 125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * and/or other materials provided with the distribution. 135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 3. The name of the author may not be used to endorse or promote products 145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * derived from this software without specific prior written permission. 155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */ 275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/turnport.h" 295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <functional> 315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/asyncpacketsocket.h" 335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/byteorder.h" 345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/common.h" 355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h" 365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/nethelpers.h" 375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/socketaddress.h" 385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/stringencode.h" 395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/common.h" 405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/stun.h" 415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket { 435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(juberti): Move to stun.h when relay messages have been renamed. 455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST; 465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int TURN_ALLOCATE_ERROR_RESPONSE = STUN_ALLOCATE_ERROR_RESPONSE; 475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(juberti): Extract to turnmessage.h 495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int TURN_DEFAULT_PORT = 3478; 505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int TURN_CHANNEL_NUMBER_START = 0x4000; 515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes 525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const size_t TURN_CHANNEL_HEADER_SIZE = 4U; 545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgenum { 565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org MSG_PORT_ERROR = 1 575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orginline bool IsTurnChannelData(uint16 msg_type) { 605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01 615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 63e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.orgstatic int GetRelayPreference(cricket::ProtocolType proto, bool secure) { 645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int relay_preference = ICE_TYPE_PREFERENCE_RELAY; 65e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org if (proto == cricket::PROTO_TCP) { 665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org relay_preference -= 1; 67e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org if (secure) 68e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org relay_preference -= 1; 69e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org } 705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(relay_preference >= 0); 725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return relay_preference; 735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass TurnAllocateRequest : public StunRequest { 765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org explicit TurnAllocateRequest(TurnPort* port); 785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void Prepare(StunMessage* request); 795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnResponse(StunMessage* response); 805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnErrorResponse(StunMessage* response); 815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnTimeout(); 825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Handles authentication challenge from the server. 855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnAuthChallenge(StunMessage* response, int code); 865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnUnknownAttribute(StunMessage* response); 875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port_; 895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass TurnRefreshRequest : public StunRequest { 925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org explicit TurnRefreshRequest(TurnPort* port); 945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void Prepare(StunMessage* request); 955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnResponse(StunMessage* response); 965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnErrorResponse(StunMessage* response); 975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnTimeout(); 985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port_; 1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass TurnCreatePermissionRequest : public StunRequest, 1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public sigslot::has_slots<> { 1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry, 1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& ext_addr); 1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void Prepare(StunMessage* request); 1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnResponse(StunMessage* response); 1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnErrorResponse(StunMessage* response); 1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnTimeout(); 1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnEntryDestroyed(TurnEntry* entry); 1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port_; 1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry* entry_; 1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SocketAddress ext_addr_; 1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass TurnChannelBindRequest : public StunRequest, 1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public sigslot::has_slots<> { 1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id, 1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& ext_addr); 1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void Prepare(StunMessage* request); 1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnResponse(StunMessage* response); 1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnErrorResponse(StunMessage* response); 1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void OnTimeout(); 1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnEntryDestroyed(TurnEntry* entry); 1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port_; 1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry* entry_; 1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int channel_id_; 1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SocketAddress ext_addr_; 1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Manages a "connection" to a remote destination. We will attempt to bring up 1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// a channel for this remote destination to reduce the overhead of sending data. 1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass TurnEntry : public sigslot::has_slots<> { 1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND }; 1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry(TurnPort* port, int channel_id, 1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& ext_addr); 1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port() { return port_; } 1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int channel_id() const { return channel_id_; } 1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& address() const { return ext_addr_; } 1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org BindState state() const { return state_; } 1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Helper methods to send permission and channel bind requests. 1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void SendCreatePermissionRequest(); 1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void SendChannelBindRequest(int delay); 1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Sends a packet to the given destination address. 1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // This will wrap the packet in STUN if necessary. 1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int Send(const void* data, size_t size, bool payload); 1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnCreatePermissionSuccess(); 1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnCreatePermissionError(StunMessage* response, int code); 1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnChannelBindSuccess(); 1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org void OnChannelBindError(StunMessage* response, int code); 1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Signal sent when TurnEntry is destroyed. 1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org sigslot::signal1<TurnEntry*> SignalDestroyed; 1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port_; 1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int channel_id_; 1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SocketAddress ext_addr_; 1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org BindState state_; 1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnPort::TurnPort(talk_base::Thread* thread, 1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::PacketSocketFactory* factory, 1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::Network* network, 1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::IPAddress& ip, 1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int min_port, int max_port, 1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const std::string& username, 1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const std::string& password, 1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const ProtocolAddress& server_address, 1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const RelayCredentials& credentials) 1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port, 1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org username, password), 1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org server_address_(server_address), 1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org credentials_(credentials), 1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org resolver_(NULL), 1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org error_(0), 1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request_manager_(thread), 1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org next_channel_number_(TURN_CHANNEL_NUMBER_START), 1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org connected_(false) { 1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); 1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnPort::~TurnPort() { 1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(juberti): Should this even be necessary? 1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org while (!entries_.empty()) { 1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DestroyEntry(entries_.front()->address()); 2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::PrepareAddress() { 2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (credentials_.username.empty() || 2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org credentials_.password.empty()) { 2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "Allocation can't be started without setting the" 2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << " TURN server credentials for the user."; 2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OnAllocateError(); 2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!server_address_.address.port()) { 2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We will set default TURN port, if no port is set in the address. 2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org server_address_.address.SetPort(TURN_DEFAULT_PORT); 2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (server_address_.address.IsUnresolved()) { 2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ResolveTurnAddress(server_address_.address); 2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "Trying to connect to TURN server via " 2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << ProtoToString(server_address_.proto) << " @ " 2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << server_address_.address.ToSensitiveString(); 2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (server_address_.proto == PROTO_UDP) { 2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_.reset(socket_factory()->CreateUdpSocket( 2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SocketAddress(ip(), 0), min_port(), max_port())); 2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else if (server_address_.proto == PROTO_TCP) { 227e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org int opts = talk_base::PacketSocketFactory::OPT_STUN; 228e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org // If secure bit is enabled in server address, use TLS over TCP. 229e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org if (server_address_.secure) { 230e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org opts |= talk_base::PacketSocketFactory::OPT_TLS; 231e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org } 232e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org 2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_.reset(socket_factory()->CreateClientTcpSocket( 2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SocketAddress(ip(), 0), server_address_.address, 235e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org proxy(), user_agent(), opts)); 2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!socket_) { 2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OnAllocateError(); 2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Apply options if any. 2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (SocketOptionsMap::iterator iter = socket_options_.begin(); 2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org iter != socket_options_.end(); ++iter) { 2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_->SetOption(iter->first, iter->second); 2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket); 2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend); 2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (server_address_.proto == PROTO_TCP) { 2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect); 2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_->SignalClose.connect(this, &TurnPort::OnSocketClose); 2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If its UDP, send AllocateRequest now. 2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // For TCP and TLS AllcateRequest will be sent by OnSocketConnect. 2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendRequest(new TurnAllocateRequest(this), 0); 2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnSocketConnect(talk_base::AsyncPacketSocket* socket) { 2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress() 2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << " using tcp."; 2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendRequest(new TurnAllocateRequest(this), 0); 2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnSocketClose(talk_base::AsyncPacketSocket* socket, int error) { 2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error; 2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!connected_) { 2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OnAllocateError(); 2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgConnection* TurnPort::CreateConnection(const Candidate& address, 2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CandidateOrigin origin) { 2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TURN-UDP can only connect to UDP candidates. 2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (address.protocol() != UDP_PROTOCOL_NAME) { 2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return NULL; 2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!IsCompatibleAddress(address.address())) { 2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return NULL; 2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Create an entry, if needed, so we can get our permissions set up correctly. 2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org CreateEntry(address.address()); 2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(juberti): The '0' index will need to change if we start gathering STUN 2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // candidates on this port. 2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ProxyConnection* conn = new ProxyConnection(this, 0, address); 2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed); 2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org AddConnection(conn); 2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return conn; 2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint TurnPort::SetOption(talk_base::Socket::Option opt, int value) { 2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!socket_) { 3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If socket is not created yet, these options will be applied during socket 3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // creation. 3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org socket_options_[opt] = value; 3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return 0; 3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return socket_->SetOption(opt, value); 3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint TurnPort::GetOption(talk_base::Socket::Option opt, int* value) { 3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!socket_) 3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return -1; 3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return socket_->GetOption(opt, value); 3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint TurnPort::GetError() { 3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return error_; 3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint TurnPort::SendTo(const void* data, size_t size, 3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& addr, 3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org bool payload) { 3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Try to find an entry for this specific address; we should have one. 3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry* entry = FindEntry(addr); 3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(entry != NULL); 3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!entry) { 3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return 0; 3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!connected()) { 3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org error_ = EWOULDBLOCK; 3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return SOCKET_ERROR; 3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Send the actual contents to the server using the usual mechanism. 3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int sent = entry->Send(data, size, payload); 3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (sent <= 0) { 3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return SOCKET_ERROR; 3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // The caller of the function is expecting the number of user data bytes, 3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // rather than the size of the packet. 342b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org return static_cast<int>(size); 3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnReadPacket(talk_base::AsyncPacketSocket* socket, 3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const char* data, size_t size, 3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& remote_addr) { 3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(socket == socket_.get()); 3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(remote_addr == server_address_.address); 3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // The message must be at least the size of a channel header. 3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (size < TURN_CHANNEL_HEADER_SIZE) { 3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received TURN message that was too short"; 3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 3555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check the message type, to see if is a Channel Data message. 3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // The message will either be channel data, a TURN data indication, or 3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // a response to a previous request. 3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org uint16 msg_type = talk_base::GetBE16(data); 3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (IsTurnChannelData(msg_type)) { 3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HandleChannelData(msg_type, data, size); 3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else if (msg_type == TURN_DATA_INDICATION) { 3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org HandleDataIndication(data, size); 3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // This must be a response for one of our requests. 3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check success responses, but not errors, for MESSAGE-INTEGRITY. 3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (IsStunSuccessResponseType(msg_type) && 3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org !StunMessage::ValidateMessageIntegrity(data, size, hash())) { 3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received TURN message with invalid " 3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "message integrity, msg_type=" << msg_type; 3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request_manager_.CheckResponse(data, size); 3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnReadyToSend(talk_base::AsyncPacketSocket* socket) { 3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (connected_) { 3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Port::OnReadyToSend(); 3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::ResolveTurnAddress(const talk_base::SocketAddress& address) { 3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (resolver_) 3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org resolver_ = new talk_base::AsyncResolver(); 3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org resolver_->SignalWorkDone.connect(this, &TurnPort::OnResolveResult); 3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org resolver_->set_address(address); 3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org resolver_->Start(); 3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnResolveResult(talk_base::SignalThread* signal_thread) { 3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(signal_thread == resolver_); 3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (resolver_->error() != 0) { 3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "TURN host lookup received error " 3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << resolver_->error(); 3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OnAllocateError(); 4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org server_address_.address = resolver_->address(); 4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org PrepareAddress(); 4055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnSendStunPacket(const void* data, size_t size, 4085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org StunRequest* request) { 4095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (Send(data, size) < 0) { 4105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Failed to send TURN message, err=" 4115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << socket_->GetError(); 4125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnStunAddress(const talk_base::SocketAddress& address) { 4165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // For relay, mapped address is rel-addr. 4175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_related_address(address); 4185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address) { 4215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org connected_ = true; 422e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org AddAddress(address, 423e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org socket_->GetLocalAddress(), 424e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org "udp", 425e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org RELAY_PORT_TYPE, 426e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org GetRelayPreference(server_address_.proto, server_address_.secure), 427e6781b6279d20210a5050a3e55e9c7effd3b144ewu@webrtc.org true); 4285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnAllocateError() { 4315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We will send SignalPortError asynchronously as this can be sent during 4325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // port initialization. This way it will not be blocking other port 4335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // creation. 4345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org thread()->Post(this, MSG_PORT_ERROR); 4355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnMessage(talk_base::Message* message) { 4385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (message->message_id == MSG_PORT_ERROR) { 4395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalPortError(this); 4405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 4415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Port::OnMessage(message); 4425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnAllocateRequestTimeout() { 4465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OnAllocateError(); 4475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::HandleDataIndication(const char* data, size_t size) { 4505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Read in the message, and process according to RFC5766, Section 10.4. 4515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::ByteBuffer buf(data, size); 4525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnMessage msg; 4535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!msg.Read(&buf)) { 4545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received invalid TURN data indication"; 4555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check mandatory attributes. 4595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunAddressAttribute* addr_attr = 4605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS); 4615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!addr_attr) { 4625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute " 4635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "in data indication."; 4645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunByteStringAttribute* data_attr = 4685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org msg.GetByteString(STUN_ATTR_DATA); 4695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!data_attr) { 4705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in " 4715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "data indication."; 4725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Verify that the data came from somewhere we think we have a permission for. 4765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SocketAddress ext_addr(addr_attr->GetAddress()); 4775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!HasPermission(ext_addr.ipaddr())) { 4785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid " 4795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "peer address, addr=" 4805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << ext_addr.ToSensitiveString(); 4815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr, PROTO_UDP); 4855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::HandleChannelData(int channel_id, const char* data, 4885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t size) { 4895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Read the message, and process according to RFC5766, Section 11.6. 4905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // 0 1 2 3 4915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // 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 4925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // | Channel Number | Length | 4945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // | | 4965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // / Application Data / 4975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // / / 4985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // | | 4995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // | +-------------------------------+ 5005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // | | 5015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // +-------------------------------+ 5025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Extract header fields from the message. 5045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org uint16 len = talk_base::GetBE16(data + 2); 5055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (len > size - TURN_CHANNEL_HEADER_SIZE) { 5065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received TURN channel data message with " 5075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "incorrect length, len=" << len; 5085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 5095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Allowing messages larger than |len|, as ChannelData can be padded. 5115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry* entry = FindEntry(channel_id); 5135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!entry) { 5145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid " 5155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "channel, channel_id=" << channel_id; 5165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 5175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(), 5205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org PROTO_UDP); 5215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::DispatchPacket(const char* data, size_t size, 5245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& remote_addr, ProtocolType proto) { 5255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (Connection* conn = GetConnection(remote_addr)) { 5265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org conn->OnReadPacket(data, size); 5275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 5285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Port::OnReadPacket(data, size, remote_addr, proto); 5295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool TurnPort::ScheduleRefresh(int lifetime) { 5335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Lifetime is in seconds; we schedule a refresh for one minute less. 5345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (lifetime < 2 * 60) { 5355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received response with lifetime that was " 5365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "too short, lifetime=" << lifetime; 5375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 5385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendRequest(new TurnRefreshRequest(this), (lifetime - 60) * 1000); 5415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 5425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::SendRequest(StunRequest* req, int delay) { 5455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request_manager_.SendDelayed(req, delay); 5465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::AddRequestAuthInfo(StunMessage* msg) { 5495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If we've gotten the necessary data from the server, add it to our request. 5505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(!hash_.empty()); 5515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg->AddAttribute(new StunByteStringAttribute( 5525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_USERNAME, credentials_.username))); 5535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg->AddAttribute(new StunByteStringAttribute( 5545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_REALM, realm_))); 5555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg->AddAttribute(new StunByteStringAttribute( 5565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_NONCE, nonce_))); 5575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg->AddMessageIntegrity(hash())); 5585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint TurnPort::Send(const void* data, size_t len) { 5615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return socket_->SendTo(data, len, server_address_.address); 5625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::UpdateHash() { 5655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(ComputeStunCredentialHash(credentials_.username, realm_, 5665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org credentials_.password, &hash_)); 5675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool TurnPort::UpdateNonce(StunMessage* response) { 5705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // When stale nonce error received, we should update 5715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // hash and store realm and nonce. 5725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check the mandatory attributes. 5735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunByteStringAttribute* realm_attr = 5745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetByteString(STUN_ATTR_REALM); 5755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!realm_attr) { 5765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in " 5775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "stale nonce error response."; 5785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 5795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_realm(realm_attr->GetString()); 5815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunByteStringAttribute* nonce_attr = 5835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetByteString(STUN_ATTR_NONCE); 5845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!nonce_attr) { 5855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in " 5865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "stale nonce error response."; 5875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 5885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_nonce(nonce_attr->GetString()); 5905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 5915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool MatchesIP(TurnEntry* e, talk_base::IPAddress ipaddr) { 5945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return e->address().ipaddr() == ipaddr; 5955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool TurnPort::HasPermission(const talk_base::IPAddress& ipaddr) const { 5975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return (std::find_if(entries_.begin(), entries_.end(), 5985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end()); 5995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool MatchesAddress(TurnEntry* e, talk_base::SocketAddress addr) { 6025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return e->address() == addr; 6035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnEntry* TurnPort::FindEntry(const talk_base::SocketAddress& addr) const { 6055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(), 6065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::bind2nd(std::ptr_fun(MatchesAddress), addr)); 6075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return (it != entries_.end()) ? *it : NULL; 6085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool MatchesChannelId(TurnEntry* e, int id) { 6115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return e->channel_id() == id; 6125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnEntry* TurnPort::FindEntry(int channel_id) const { 6145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(), 6155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id)); 6165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return (it != entries_.end()) ? *it : NULL; 6175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnEntry* TurnPort::CreateEntry(const talk_base::SocketAddress& addr) { 6205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(FindEntry(addr) == NULL); 6215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry* entry = new TurnEntry(this, next_channel_number_++, addr); 6225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entries_.push_back(entry); 6235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return entry; 6245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::DestroyEntry(const talk_base::SocketAddress& addr) { 6275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnEntry* entry = FindEntry(addr); 6285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(entry != NULL); 6295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry->SignalDestroyed(entry); 6305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entries_.remove(entry); 6315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org delete entry; 6325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnPort::OnConnectionDestroyed(Connection* conn) { 6355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Destroying TurnEntry for the connection, which is already destroyed. 6365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DestroyEntry(conn->remote_candidate().address()); 6375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnAllocateRequest::TurnAllocateRequest(TurnPort* port) 6405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : StunRequest(new TurnMessage()), 6415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_(port) { 6425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnAllocateRequest::Prepare(StunMessage* request) { 6455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Create the request as indicated in RFC 5766, Section 6.1. 6465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request->SetType(TURN_ALLOCATE_REQUEST); 6475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32( 6485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_REQUESTED_TRANSPORT); 6495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org transport_attr->SetValue(IPPROTO_UDP << 24); 6505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(request->AddAttribute(transport_attr)); 6515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!port_->hash().empty()) { 6525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->AddRequestAuthInfo(request); 6535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 6545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnAllocateRequest::OnResponse(StunMessage* response) { 6575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check mandatory attributes as indicated in RFC5766, Section 6.3. 6585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunAddressAttribute* mapped_attr = 6595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); 6605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!mapped_attr) { 6615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS " 6625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "attribute in allocate success response"; 6635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 6645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 6655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(mallinath) - Use mapped address for STUN candidate. 6675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->OnStunAddress(mapped_attr->GetAddress()); 6685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunAddressAttribute* relayed_attr = 6705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS); 6715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!relayed_attr) { 6725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS " 6735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "attribute in allocate success response"; 6745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 6755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 6765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunUInt32Attribute* lifetime_attr = 6785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetUInt32(STUN_ATTR_TURN_LIFETIME); 6795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!lifetime_attr) { 6805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in " 6815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "allocate success response"; 6825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 6835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 6845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Notify the port the allocate succeeded, and schedule a refresh request. 6855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->OnAllocateSuccess(relayed_attr->GetAddress()); 6865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->ScheduleRefresh(lifetime_attr->value()); 6875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 6885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 6895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnAllocateRequest::OnErrorResponse(StunMessage* response) { 6905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Process error response according to RFC5766, Section 6.4. 6915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunErrorCodeAttribute* error_code = response->GetErrorCode(); 6925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org switch (error_code->code()) { 6935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STUN_ERROR_UNAUTHORIZED: // Unauthrorized. 6945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OnAuthChallenge(response, error_code->code()); 6955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 6965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org default: 6975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Allocate response error, code=" 6985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << error_code->code(); 6995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->OnAllocateError(); 7005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnAllocateRequest::OnTimeout() { 7045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Allocate request timeout"; 7055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->OnAllocateRequestTimeout(); 7065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) { 7095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If we failed to authenticate even after we sent our credentials, fail hard. 7105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) { 7115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server " 7125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "after challenge."; 7135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->OnAllocateError(); 7145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 7155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check the mandatory attributes. 7185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunByteStringAttribute* realm_attr = 7195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetByteString(STUN_ATTR_REALM); 7205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!realm_attr) { 7215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in " 7225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "allocate unauthorized response."; 7235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 7245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->set_realm(realm_attr->GetString()); 7265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunByteStringAttribute* nonce_attr = 7285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetByteString(STUN_ATTR_NONCE); 7295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!nonce_attr) { 7305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in " 7315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "allocate unauthorized response."; 7325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 7335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->set_nonce(nonce_attr->GetString()); 7355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Send another allocate request, with the received realm and nonce values. 7375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->SendRequest(new TurnAllocateRequest(port_), 0); 7385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnRefreshRequest::TurnRefreshRequest(TurnPort* port) 7415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : StunRequest(new TurnMessage()), 7425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_(port) { 7435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnRefreshRequest::Prepare(StunMessage* request) { 7465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Create the request as indicated in RFC 5766, Section 7.1. 7475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // No attributes need to be included. 7485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request->SetType(TURN_REFRESH_REQUEST); 7495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->AddRequestAuthInfo(request); 7505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnRefreshRequest::OnResponse(StunMessage* response) { 7535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Check mandatory attributes as indicated in RFC5766, Section 7.3. 7545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunUInt32Attribute* lifetime_attr = 7555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org response->GetUInt32(STUN_ATTR_TURN_LIFETIME); 7565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!lifetime_attr) { 7575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in " 7585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "refresh success response."; 7595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 7605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Schedule a refresh based on the returned lifetime value. 7635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->ScheduleRefresh(lifetime_attr->value()); 7645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnRefreshRequest::OnErrorResponse(StunMessage* response) { 7675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(juberti): Handle 437 error response as a success. 7685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunErrorCodeAttribute* error_code = response->GetErrorCode(); 7695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Refresh response error, code=" 7705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << error_code->code(); 7715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (error_code->code() == STUN_ERROR_STALE_NONCE) { 7735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (port_->UpdateNonce(response)) { 7745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Send RefreshRequest immediately. 7755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->SendRequest(new TurnRefreshRequest(port_), 0); 7765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 7785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnRefreshRequest::OnTimeout() { 7815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnCreatePermissionRequest::TurnCreatePermissionRequest( 7845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port, TurnEntry* entry, 7855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& ext_addr) 7865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : StunRequest(new TurnMessage()), 7875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_(port), 7885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_(entry), 7895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ext_addr_(ext_addr) { 7905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->SignalDestroyed.connect( 7915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org this, &TurnCreatePermissionRequest::OnEntryDestroyed); 7925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 7935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 7945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnCreatePermissionRequest::Prepare(StunMessage* request) { 7955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Create the request as indicated in RFC5766, Section 9.1. 7965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request->SetType(TURN_CREATE_PERMISSION_REQUEST); 7975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(request->AddAttribute(new StunXorAddressAttribute( 7985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_))); 7995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->AddRequestAuthInfo(request); 8005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnCreatePermissionRequest::OnResponse(StunMessage* response) { 8035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (entry_) { 8045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->OnCreatePermissionSuccess(); 8055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 8065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) { 8095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (entry_) { 8105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunErrorCodeAttribute* error_code = response->GetErrorCode(); 8115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->OnCreatePermissionError(response, error_code->code()); 8125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 8135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnCreatePermissionRequest::OnTimeout() { 8165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Create permission timeout"; 8175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) { 8205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(entry_ == entry); 8215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_ = NULL; 8225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnChannelBindRequest::TurnChannelBindRequest( 8255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnPort* port, TurnEntry* entry, 8265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int channel_id, const talk_base::SocketAddress& ext_addr) 8275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : StunRequest(new TurnMessage()), 8285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_(port), 8295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_(entry), 8305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_id_(channel_id), 8315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ext_addr_(ext_addr) { 8325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->SignalDestroyed.connect( 8335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org this, &TurnChannelBindRequest::OnEntryDestroyed); 8345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnChannelBindRequest::Prepare(StunMessage* request) { 8375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Create the request as indicated in RFC5766, Section 11.1. 8385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org request->SetType(TURN_CHANNEL_BIND_REQUEST); 8395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(request->AddAttribute(new StunUInt32Attribute( 8405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16))); 8415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(request->AddAttribute(new StunXorAddressAttribute( 8425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_))); 8435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->AddRequestAuthInfo(request); 8445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnChannelBindRequest::OnResponse(StunMessage* response) { 8475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (entry_) { 8485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->OnChannelBindSuccess(); 8495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Refresh the channel binding just under the permission timeout 8505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // threshold. The channel binding has a longer lifetime, but 8515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // this is the easiest way to keep both the channel and the 8525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // permission from expiring. 8535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->SendChannelBindRequest(TURN_PERMISSION_TIMEOUT - 60 * 1000); 8545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 8555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnChannelBindRequest::OnErrorResponse(StunMessage* response) { 8585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (entry_) { 8595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const StunErrorCodeAttribute* error_code = response->GetErrorCode(); 8605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_->OnChannelBindError(response, error_code->code()); 8615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 8625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnChannelBindRequest::OnTimeout() { 8655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Channel bind timeout"; 8665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) { 8695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(entry_ == entry); 8705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org entry_ = NULL; 8715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgTurnEntry::TurnEntry(TurnPort* port, int channel_id, 8745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const talk_base::SocketAddress& ext_addr) 8755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : port_(port), 8765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_id_(channel_id), 8775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ext_addr_(ext_addr), 8785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org state_(STATE_UNBOUND) { 8795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Creating permission for |ext_addr_|. 8805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendCreatePermissionRequest(); 8815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnEntry::SendCreatePermissionRequest() { 8845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->SendRequest(new TurnCreatePermissionRequest( 8855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_, this, ext_addr_), 0); 8865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnEntry::SendChannelBindRequest(int delay) { 8895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->SendRequest(new TurnChannelBindRequest( 8905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_, this, channel_id_, ext_addr_), delay); 8915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 8925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 8935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint TurnEntry::Send(const void* data, size_t size, bool payload) { 8945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::ByteBuffer buf; 8955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (state_ != STATE_BOUND) { 8965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If we haven't bound the channel yet, we have to use a Send Indication. 8975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TurnMessage msg; 8985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org msg.SetType(TURN_SEND_INDICATION); 8995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org msg.SetTransactionID( 9005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::CreateRandomString(kStunTransactionIdLength)); 9015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg.AddAttribute(new StunXorAddressAttribute( 9025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_))); 9035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg.AddAttribute(new StunByteStringAttribute( 9045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org STUN_ATTR_DATA, data, size))); 9055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org VERIFY(msg.Write(&buf)); 9065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 9075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If we're sending real data, request a channel bind that we can use later. 9085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (state_ == STATE_UNBOUND && payload) { 9095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendChannelBindRequest(0); 9105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org state_ = STATE_BINDING; 9115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 9125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 9135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // If the channel is bound, we can send the data as a Channel Message. 9145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org buf.WriteUInt16(channel_id_); 915b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org buf.WriteUInt16(static_cast<uint16>(size)); 9165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org buf.WriteBytes(reinterpret_cast<const char*>(data), size); 9175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 9185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return port_->Send(buf.Data(), buf.Length()); 9195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 9205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 9215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnEntry::OnCreatePermissionSuccess() { 9225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, port_) << "Create permission for " 9235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << ext_addr_.ToSensitiveString() 9245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << " succeeded"; 9255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // For success result code will be 0. 9265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->SignalCreatePermissionResult(port_, ext_addr_, 0); 9275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 9285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 9295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnEntry::OnCreatePermissionError(StunMessage* response, int code) { 9305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Create permission for " 9315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << ext_addr_.ToSensitiveString() 9325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << " failed, code=" << code; 9335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (code == STUN_ERROR_STALE_NONCE) { 9345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (port_->UpdateNonce(response)) { 9355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendCreatePermissionRequest(); 9365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 9375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 9385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Send signal with error code. 9395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org port_->SignalCreatePermissionResult(port_, ext_addr_, code); 9405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 9415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 9425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 9435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnEntry::OnChannelBindSuccess() { 9445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString() 9455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << " succeeded"; 9465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND); 9475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org state_ = STATE_BOUND; 9485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 9495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 9505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid TurnEntry::OnChannelBindError(StunMessage* response, int code) { 9515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(mallinath) - Implement handling of error response for channel 9525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // bind request as per http://tools.ietf.org/html/rfc5766#section-11.3 9535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, port_) << "Channel bind for " 9545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << ext_addr_.ToSensitiveString() 9555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << " failed, code=" << code; 9565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (code == STUN_ERROR_STALE_NONCE) { 9575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (port_->UpdateNonce(response)) { 9585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Send channel bind request with fresh nonce. 9595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SendChannelBindRequest(0); 9605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 9615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 9625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 9635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 9645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} // namespace cricket 965