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