1269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org/*
2269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
3269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *
4269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
5269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
6269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
7269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
8269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org */
10269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
11269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/turnport.h"
12269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
13269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include <functional>
14269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
15269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/common.h"
16269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/stun.h"
17269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/asyncpacketsocket.h"
18269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/byteorder.h"
19269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/common.h"
20269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/logging.h"
21269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/nethelpers.h"
22269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/socketaddress.h"
23269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/stringencode.h"
24269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
25269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgnamespace cricket {
26269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
27269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// TODO(juberti): Move to stun.h when relay messages have been renamed.
28269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
29269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
30269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// TODO(juberti): Extract to turnmessage.h
31269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic const int TURN_DEFAULT_PORT = 3478;
32269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic const int TURN_CHANNEL_NUMBER_START = 0x4000;
33269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000;  // 5 minutes
34269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
35269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
36269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
37269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// Retry at most twice (i.e. three different ALLOCATE requests) on
38269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
39269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
40269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
41f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhangstatic const int TURN_SUCCESS_RESULT_CODE = 0;
42f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang
430c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströminline bool IsTurnChannelData(uint16_t msg_type) {
44269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return ((msg_type & 0xC000) == 0x4000);  // MSB are 0b01
45269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
46269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
47269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic int GetRelayPreference(cricket::ProtocolType proto, bool secure) {
48269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int relay_preference = ICE_TYPE_PREFERENCE_RELAY;
49269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (proto == cricket::PROTO_TCP) {
50269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    relay_preference -= 1;
51269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (secure)
52269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      relay_preference -= 1;
53269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
54269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
55269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(relay_preference >= 0);
56269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return relay_preference;
57269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
58269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
59269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgclass TurnAllocateRequest : public StunRequest {
60269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org public:
61269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  explicit TurnAllocateRequest(TurnPort* port);
621cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void Prepare(StunMessage* request) override;
631cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnSent() override;
641cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnResponse(StunMessage* response) override;
651cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnErrorResponse(StunMessage* response) override;
661cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnTimeout() override;
67269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
68269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org private:
69269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Handles authentication challenge from the server.
70269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnAuthChallenge(StunMessage* response, int code);
71269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnTryAlternate(StunMessage* response, int code);
72269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnUnknownAttribute(StunMessage* response);
73269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
74269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnPort* port_;
75269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
76269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
77269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgclass TurnRefreshRequest : public StunRequest {
78269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org public:
79269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  explicit TurnRefreshRequest(TurnPort* port);
801cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void Prepare(StunMessage* request) override;
811cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnSent() override;
821cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnResponse(StunMessage* response) override;
831cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnErrorResponse(StunMessage* response) override;
841cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnTimeout() override;
85fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  void set_lifetime(int lifetime) { lifetime_ = lifetime; }
86269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
87269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org private:
88269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnPort* port_;
89fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  int lifetime_;
90269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
91269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
92269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgclass TurnCreatePermissionRequest : public StunRequest,
93269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                    public sigslot::has_slots<> {
94269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org public:
95269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
96269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                              const rtc::SocketAddress& ext_addr);
971cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void Prepare(StunMessage* request) override;
981cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnSent() override;
991cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnResponse(StunMessage* response) override;
1001cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnErrorResponse(StunMessage* response) override;
1011cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnTimeout() override;
102269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
103269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org private:
104269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnEntryDestroyed(TurnEntry* entry);
105269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
106269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnPort* port_;
107269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnEntry* entry_;
108269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress ext_addr_;
109269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
110269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
111269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgclass TurnChannelBindRequest : public StunRequest,
112269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                               public sigslot::has_slots<> {
113269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org public:
114269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
115269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                         const rtc::SocketAddress& ext_addr);
1161cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void Prepare(StunMessage* request) override;
1171cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnSent() override;
1181cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnResponse(StunMessage* response) override;
1191cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnErrorResponse(StunMessage* response) override;
1201cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  void OnTimeout() override;
121269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
122269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org private:
123269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnEntryDestroyed(TurnEntry* entry);
124269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
125269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnPort* port_;
126269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnEntry* entry_;
127269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int channel_id_;
128269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress ext_addr_;
129269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
130269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
131269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// Manages a "connection" to a remote destination. We will attempt to bring up
132269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// a channel for this remote destination to reduce the overhead of sending data.
133269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgclass TurnEntry : public sigslot::has_slots<> {
134269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org public:
135269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
136269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnEntry(TurnPort* port, int channel_id,
137269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org            const rtc::SocketAddress& ext_addr);
138269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
139269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnPort* port() { return port_; }
140269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
141269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int channel_id() const { return channel_id_; }
142f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  // For testing only.
143f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  void set_channel_id(int channel_id) { channel_id_ = channel_id; }
144f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang
145269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const rtc::SocketAddress& address() const { return ext_addr_; }
146269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  BindState state() const { return state_; }
147269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
14832f39968ce79cfca5146069e410ded2f104bba23honghaiz  uint32_t destruction_timestamp() { return destruction_timestamp_; }
14932f39968ce79cfca5146069e410ded2f104bba23honghaiz  void set_destruction_timestamp(uint32_t destruction_timestamp) {
15032f39968ce79cfca5146069e410ded2f104bba23honghaiz    destruction_timestamp_ = destruction_timestamp;
15132f39968ce79cfca5146069e410ded2f104bba23honghaiz  }
15232f39968ce79cfca5146069e410ded2f104bba23honghaiz
153269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Helper methods to send permission and channel bind requests.
1548597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  void SendCreatePermissionRequest(int delay);
155269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void SendChannelBindRequest(int delay);
156269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Sends a packet to the given destination address.
157269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // This will wrap the packet in STUN if necessary.
158269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int Send(const void* data, size_t size, bool payload,
159269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org           const rtc::PacketOptions& options);
160269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
161269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnCreatePermissionSuccess();
162269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnCreatePermissionError(StunMessage* response, int code);
163f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  void OnCreatePermissionTimeout();
164269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnChannelBindSuccess();
165269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  void OnChannelBindError(StunMessage* response, int code);
166f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  void OnChannelBindTimeout();
167269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Signal sent when TurnEntry is destroyed.
168269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  sigslot::signal1<TurnEntry*> SignalDestroyed;
169269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
170269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org private:
171269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnPort* port_;
172269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int channel_id_;
173269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress ext_addr_;
174269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  BindState state_;
17532f39968ce79cfca5146069e410ded2f104bba23honghaiz  // A non-zero value indicates that this entry is scheduled to be destroyed.
17632f39968ce79cfca5146069e410ded2f104bba23honghaiz  // It is also used as an ID of the event scheduling. When the destruction
17732f39968ce79cfca5146069e410ded2f104bba23honghaiz  // event actually fires, the TurnEntry will be destroyed only if the
17832f39968ce79cfca5146069e410ded2f104bba23honghaiz  // timestamp here matches the one in the firing event.
17932f39968ce79cfca5146069e410ded2f104bba23honghaiz  uint32_t destruction_timestamp_ = 0;
180269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
181269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
182269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnPort::TurnPort(rtc::Thread* thread,
183269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   rtc::PacketSocketFactory* factory,
184269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   rtc::Network* network,
185269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   rtc::AsyncPacketSocket* socket,
186269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const std::string& username,
187269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const std::string& password,
188269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const ProtocolAddress& server_address,
189269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const RelayCredentials& credentials,
1900ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org                   int server_priority,
1910ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org                   const std::string& origin)
192b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    : Port(thread,
193b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           factory,
194b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           network,
195b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           socket->GetLocalAddress().ipaddr(),
196b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           username,
197b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           password),
198269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      server_address_(server_address),
199269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      credentials_(credentials),
200269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      socket_(socket),
201269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      resolver_(NULL),
202269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      error_(0),
203269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      request_manager_(thread),
204269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      next_channel_number_(TURN_CHANNEL_NUMBER_START),
205b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz      state_(STATE_CONNECTING),
206269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      server_priority_(server_priority),
207269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      allocate_mismatch_retries_(0) {
208269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
2090ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org  request_manager_.set_origin(origin);
210269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
211269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
212269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnPort::TurnPort(rtc::Thread* thread,
213269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   rtc::PacketSocketFactory* factory,
214269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   rtc::Network* network,
215269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const rtc::IPAddress& ip,
2160c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström                   uint16_t min_port,
2170c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström                   uint16_t max_port,
218269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const std::string& username,
219269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const std::string& password,
220269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const ProtocolAddress& server_address,
221269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const RelayCredentials& credentials,
2220ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org                   int server_priority,
2230ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org                   const std::string& origin)
224b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    : Port(thread,
225b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           RELAY_PORT_TYPE,
226b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           factory,
227b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           network,
228b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           ip,
229b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           min_port,
230b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           max_port,
231b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           username,
232b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz           password),
233269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      server_address_(server_address),
234269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      credentials_(credentials),
235269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      socket_(NULL),
236269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      resolver_(NULL),
237269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      error_(0),
238269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      request_manager_(thread),
239269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      next_channel_number_(TURN_CHANNEL_NUMBER_START),
240b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz      state_(STATE_CONNECTING),
241269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      server_priority_(server_priority),
242269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      allocate_mismatch_retries_(0) {
243269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
2440ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org  request_manager_.set_origin(origin);
245269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
246269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
247269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnPort::~TurnPort() {
248269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // TODO(juberti): Should this even be necessary?
249fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org
250fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  // release the allocation by sending a refresh with
251fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  // lifetime 0.
252b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  if (ready()) {
253fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org    TurnRefreshRequest bye(this);
254fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org    bye.set_lifetime(0);
255fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org    SendRequest(&bye, 0);
256fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  }
257fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org
258269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  while (!entries_.empty()) {
25932f39968ce79cfca5146069e410ded2f104bba23honghaiz    DestroyEntry(entries_.front());
260269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
261269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (resolver_) {
262269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    resolver_->Destroy(false);
263269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
264269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!SharedSocket()) {
265269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    delete socket_;
266269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
267269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
268269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
2690ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.orgrtc::SocketAddress TurnPort::GetLocalAddress() const {
2700ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org  return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress();
2710ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org}
2720ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org
273269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::PrepareAddress() {
274269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (credentials_.username.empty() ||
275269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      credentials_.password.empty()) {
276269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG(LS_ERROR) << "Allocation can't be started without setting the"
277269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                  << " TURN server credentials for the user.";
278269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    OnAllocateError();
279269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
280269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
281269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
282269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!server_address_.address.port()) {
283269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // We will set default TURN port, if no port is set in the address.
284269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    server_address_.address.SetPort(TURN_DEFAULT_PORT);
285269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
286269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
28720a34619080005c3b0e49d85b307113ea2b180c3tfarina  if (server_address_.address.IsUnresolvedIP()) {
288269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ResolveTurnAddress(server_address_.address);
289269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
290269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If protocol family of server address doesn't match with local, return.
291269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!IsCompatibleAddress(server_address_.address)) {
292b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz      LOG(LS_ERROR) << "IP address family does not match: "
293b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz                    << "server: " << server_address_.address.family()
294b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz                    << "local: " << ip().family();
295269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      OnAllocateError();
296269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return;
297269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
298269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
299269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // Insert the current address to prevent redirection pingpong.
300269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    attempted_server_addresses_.insert(server_address_.address);
301269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
302269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
303269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                         << ProtoToString(server_address_.proto) << " @ "
304269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                         << server_address_.address.ToSensitiveString();
305269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!CreateTurnClientSocket()) {
306b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz      LOG(LS_ERROR) << "Failed to create TURN client socket";
307269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      OnAllocateError();
308b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz      return;
309b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    }
310b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    if (server_address_.proto == PROTO_UDP) {
311269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // If its UDP, send AllocateRequest now.
312269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
313269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      SendRequest(new TurnAllocateRequest(this), 0);
314269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
315269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
316269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
317269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
318269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool TurnPort::CreateTurnClientSocket() {
319269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(!socket_ || SharedSocket());
320269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
321269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
322269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_ = socket_factory()->CreateUdpSocket(
323269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        rtc::SocketAddress(ip(), 0), min_port(), max_port());
324269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else if (server_address_.proto == PROTO_TCP) {
325269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ASSERT(!SharedSocket());
326269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    int opts = rtc::PacketSocketFactory::OPT_STUN;
327269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If secure bit is enabled in server address, use TLS over TCP.
328269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (server_address_.secure) {
329269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      opts |= rtc::PacketSocketFactory::OPT_TLS;
330269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
331269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_ = socket_factory()->CreateClientTcpSocket(
332269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        rtc::SocketAddress(ip(), 0), server_address_.address,
333269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        proxy(), user_agent(), opts);
334269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
335269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
336269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!socket_) {
337269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    error_ = SOCKET_ERROR;
338269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
339269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
340269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
341269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Apply options if any.
342269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (SocketOptionsMap::iterator iter = socket_options_.begin();
343269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org       iter != socket_options_.end(); ++iter) {
344269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_->SetOption(iter->first, iter->second);
345269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
346269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
347269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!SharedSocket()) {
348269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If socket is shared, AllocationSequence will receive the packet.
349269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
350269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
351269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
352269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
353269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
35455674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer  socket_->SignalSentPacket.connect(this, &TurnPort::OnSentPacket);
35555674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer
356b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  // TCP port is ready to send stun requests after the socket is connected,
357b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  // while UDP port is ready to do so once the socket is created.
358269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (server_address_.proto == PROTO_TCP) {
359269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
360269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
361b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  } else {
362b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    state_ = STATE_CONNECTED;
363269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
364269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
365269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
366269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
367269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
368269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(server_address_.proto == PROTO_TCP);
369269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Do not use this port if the socket bound to a different address than
370269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
371269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // given a binding address, and the platform is expected to pick the
372269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // correct local address.
3734fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org
3747f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh  // However, there are two situations in which we allow the bound address to
3757f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh  // differ from the requested address: 1. The bound address is the loopback
3767f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh  // address.  This happens when a proxy forces TCP to bind to only the
3777f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh  // localhost address (see issue 3927). 2. The bound address is the "any
3787f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh  // address".  This happens when multiple_routes is disabled (see issue 4780).
379269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (socket->GetLocalAddress().ipaddr() != ip()) {
3804fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org    if (socket->GetLocalAddress().IsLoopbackIP()) {
3814fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org      LOG(LS_WARNING) << "Socket is bound to a different address:"
3824fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org                      << socket->GetLocalAddress().ipaddr().ToString()
3834fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org                      << ", rather then the local port:" << ip().ToString()
3844fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org                      << ". Still allowing it since it's localhost.";
3857f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh    } else if (IPIsAny(ip())) {
3867f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh      LOG(LS_WARNING) << "Socket is bound to a different address:"
3877f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh                      << socket->GetLocalAddress().ipaddr().ToString()
3887f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh                      << ", rather then the local port:" << ip().ToString()
3897f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh                      << ". Still allowing it since it's any address"
3907f04b08d3b31c732c66965a09803f6c3e4210a65Guo-wei Shieh                      << ", possibly caused by multiple_routes being disabled.";
3914fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org    } else {
3924fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org      LOG(LS_WARNING) << "Socket is bound to a different address:"
3934fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org                      << socket->GetLocalAddress().ipaddr().ToString()
3944fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org                      << ", rather then the local port:" << ip().ToString()
3954fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org                      << ". Discarding TURN port.";
3964fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org      OnAllocateError();
3974fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org      return;
3984fba293c87c366a3fd38ea94e88c3d38021f0dfaguoweis@webrtc.org    }
399269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
400269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
401b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  state_ = STATE_CONNECTED;  // It is ready to send stun requests.
40220a34619080005c3b0e49d85b307113ea2b180c3tfarina  if (server_address_.address.IsUnresolvedIP()) {
403269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    server_address_.address = socket_->GetRemoteAddress();
404269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
405269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
406269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
407269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org               << " using tcp.";
408269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  SendRequest(new TurnAllocateRequest(this), 0);
409269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
410269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
411269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
412269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
41319e4e8d751478d34c05bc2d73e065429ed65a1c1guoweis@webrtc.org  ASSERT(socket == socket_);
4146b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  Close();
415269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
416269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
417269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnAllocateMismatch() {
418269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
419269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Giving up on the port after "
420269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << allocate_mismatch_retries_
421269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
422269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    OnAllocateError();
423269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
424269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
425269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
426269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LOG_J(LS_INFO, this) << "Allocating a new socket after "
427269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                       << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
428269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                       << allocate_mismatch_retries_ + 1;
429269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (SharedSocket()) {
430269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ResetSharedSocket();
431269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
432269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    delete socket_;
433269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
434269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  socket_ = NULL;
435269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
436269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  PrepareAddress();
437269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ++allocate_mismatch_retries_;
438269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
439269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
440269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgConnection* TurnPort::CreateConnection(const Candidate& address,
441269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                       CandidateOrigin origin) {
442269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // TURN-UDP can only connect to UDP candidates.
443f9945b2d1aa2d78b19987219ea872605167d7b5fHonghai Zhang  if (!SupportsProtocol(address.protocol())) {
444269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return NULL;
445269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
446269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
447269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!IsCompatibleAddress(address.address())) {
448269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return NULL;
449269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
450269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
451b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  if (state_ == STATE_DISCONNECTED) {
452b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    return NULL;
453b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  }
454b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz
455269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Create an entry, if needed, so we can get our permissions set up correctly.
45632f39968ce79cfca5146069e410ded2f104bba23honghaiz  CreateOrRefreshEntry(address.address());
457269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
458269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // A TURN port will have two candiates, STUN and TURN. STUN may not
459269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // present in all cases. If present stun candidate will be added first
460269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // and TURN candidate later.
461269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (size_t index = 0; index < Candidates().size(); ++index) {
462269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (Candidates()[index].type() == RELAY_PORT_TYPE) {
463269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      ProxyConnection* conn = new ProxyConnection(this, index, address);
464269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
465269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      AddConnection(conn);
466269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return conn;
467269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
468269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
469269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return NULL;
470269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
471269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
472f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhangbool TurnPort::DestroyConnection(const rtc::SocketAddress& address) {
473f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  Connection* conn = GetConnection(address);
474f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  if (conn != nullptr) {
475f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    conn->Destroy();
476f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    return true;
477f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  }
478f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  return false;
479f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang}
480f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang
481269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint TurnPort::SetOption(rtc::Socket::Option opt, int value) {
482269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!socket_) {
483269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If socket is not created yet, these options will be applied during socket
484269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // creation.
485269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_options_[opt] = value;
486269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return 0;
487269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
488269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return socket_->SetOption(opt, value);
489269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
490269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
491269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
492269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!socket_) {
493269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    SocketOptionsMap::const_iterator it = socket_options_.find(opt);
494269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (it == socket_options_.end()) {
495269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return -1;
496269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
497269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    *value = it->second;
498269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return 0;
499269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
500269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
501269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return socket_->GetOption(opt, value);
502269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
503269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
504269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint TurnPort::GetError() {
505269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return error_;
506269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
507269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
508269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint TurnPort::SendTo(const void* data, size_t size,
509269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                     const rtc::SocketAddress& addr,
510269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                     const rtc::PacketOptions& options,
511269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                     bool payload) {
512269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Try to find an entry for this specific address; we should have one.
513269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnEntry* entry = FindEntry(addr);
514269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!entry) {
515b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz    LOG(LS_ERROR) << "Did not find the TurnEntry for address " << addr;
516269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return 0;
517269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
518269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
519b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  if (!ready()) {
520269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    error_ = EWOULDBLOCK;
521269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return SOCKET_ERROR;
522269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
523269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
524269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Send the actual contents to the server using the usual mechanism.
525269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int sent = entry->Send(data, size, payload, options);
526269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (sent <= 0) {
527269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return SOCKET_ERROR;
528269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
529269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
530269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // The caller of the function is expecting the number of user data bytes,
531269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // rather than the size of the packet.
532269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return static_cast<int>(size);
533269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
534269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
535269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnReadPacket(
536269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    rtc::AsyncPacketSocket* socket, const char* data, size_t size,
537269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& remote_addr,
538269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::PacketTime& packet_time) {
539269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(socket == socket_);
540c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org
541c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org  // This is to guard against a STUN response from previous server after
542c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org  // alternative server redirection. TODO(guoweis): add a unit test for this
543c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org  // race condition.
544c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org  if (remote_addr != server_address_.address) {
545c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org    LOG_J(LS_WARNING, this) << "Discarding TURN message from unknown address:"
546c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org                            << remote_addr.ToString()
547c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org                            << ", server_address_:"
548c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org                            << server_address_.address.ToString();
549c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org    return;
550c51fb9348df603f64dc37c88cb973cfed84394f7guoweis@webrtc.org  }
551269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
552269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // The message must be at least the size of a channel header.
553269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (size < TURN_CHANNEL_HEADER_SIZE) {
554269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
555269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
556269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
557269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
558269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check the message type, to see if is a Channel Data message.
559269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // The message will either be channel data, a TURN data indication, or
560269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // a response to a previous request.
5610c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint16_t msg_type = rtc::GetBE16(data);
562269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (IsTurnChannelData(msg_type)) {
563269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    HandleChannelData(msg_type, data, size, packet_time);
564269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else if (msg_type == TURN_DATA_INDICATION) {
565269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    HandleDataIndication(data, size, packet_time);
566269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
567511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org    if (SharedSocket() &&
568511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org        (msg_type == STUN_BINDING_RESPONSE ||
569511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org         msg_type == STUN_BINDING_ERROR_RESPONSE)) {
570511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org      LOG_J(LS_VERBOSE, this) <<
571511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org          "Ignoring STUN binding response message on shared socket.";
572511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org      return;
573511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org    }
574511f8a8ef2242781d1541daf4854910229690bf8jiayl@webrtc.org
575269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // This must be a response for one of our requests.
576269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // Check success responses, but not errors, for MESSAGE-INTEGRITY.
577269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (IsStunSuccessResponseType(msg_type) &&
578269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
579269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
580269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                              << "message integrity, msg_type=" << msg_type;
581269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return;
582269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
583269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    request_manager_.CheckResponse(data, size);
584269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
585269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
586269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
58755674ffb32307c6f3efaab442340d3c5c075073bStefan Holmervoid TurnPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
58855674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer                            const rtc::SentPacket& sent_packet) {
58955674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer  PortInterface::SignalSentPacket(sent_packet);
59055674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer}
59155674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer
592269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
593b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  if (ready()) {
594269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    Port::OnReadyToSend();
595269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
596269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
597269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
598269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
599269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// Update current server address port with the alternate server address port.
600269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
601269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check if we have seen this address before and reject if we did.
602269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
603269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (iter != attempted_server_addresses_.end()) {
604269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Redirection to ["
605269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << address.ToSensitiveString()
606269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "] ignored, allocation failed.";
607269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
608269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
609269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
610269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // If protocol family of server address doesn't match with local, return.
611269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!IsCompatibleAddress(address)) {
612269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG(LS_WARNING) << "Server IP address family does not match with "
613269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                    << "local host address family type";
614269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
615269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
616269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
617269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
618269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                       << server_address_.address.ToSensitiveString()
619269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                       << "] to TURN server ["
620269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                       << address.ToSensitiveString()
621269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                       << "]";
622269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  server_address_ = ProtocolAddress(address, server_address_.proto,
623269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                    server_address_.secure);
624269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
625269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Insert the current address to prevent redirection pingpong.
626269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  attempted_server_addresses_.insert(server_address_.address);
627269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
628269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
629269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
630269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
631269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (resolver_)
632269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
633269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
6340f490a5b8609c1f10dba37d7a7b0b2fc055543ebHonghai Zhang  LOG_J(LS_INFO, this) << "Starting TURN host lookup for "
6350f490a5b8609c1f10dba37d7a7b0b2fc055543ebHonghai Zhang                       << address.ToSensitiveString();
636269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolver_ = socket_factory()->CreateAsyncResolver();
637269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
638269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolver_->Start(address);
639269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
640269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
641269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
642269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(resolver == resolver_);
643269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // If DNS resolve is failed when trying to connect to the server using TCP,
644269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // one of the reason could be due to DNS queries blocked by firewall.
645269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // In such cases we will try to connect to the server with hostname, assuming
646269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // socket layer will resolve the hostname through a HTTP proxy (if any).
647269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
648269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!CreateTurnClientSocket()) {
649269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      OnAllocateError();
650269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
651269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
652269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
653269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
654269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Copy the original server address in |resolved_address|. For TLS based
655269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // sockets we need hostname along with resolved address.
656269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress resolved_address = server_address_.address;
657269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (resolver_->GetError() != 0 ||
658269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
659269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "TURN host lookup received error "
660269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << resolver_->GetError();
661269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    error_ = resolver_->GetError();
662269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    OnAllocateError();
663269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
664269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
665269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Signal needs both resolved and unresolved address. After signal is sent
666269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // we can copy resolved address back into |server_address_|.
667269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  SignalResolvedServerAddress(this, server_address_.address,
668269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                              resolved_address);
669269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  server_address_.address = resolved_address;
670269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  PrepareAddress();
671269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
672269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
673269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnSendStunPacket(const void* data, size_t size,
674269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                StunRequest* request) {
675b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  ASSERT(connected());
676269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::PacketOptions options(DefaultDscpValue());
677269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (Send(data, size, options) < 0) {
678269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
679269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                          << socket_->GetError();
680269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
681269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
682269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
683269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
684269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // STUN Port will discover STUN candidate, as it's supplied with first TURN
685269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // server address.
686269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Why not using this address? - P2PTransportChannel will start creating
687269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // connections after first candidate, which means it could start creating the
688269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // connections before TURN candidate added. For that to handle, we need to
689269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // supply STUN candidate from this port to UDPPort, and TurnPort should have
690269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // handle to UDPPort to pass back the address.
691269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
692269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
693269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
694269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                 const rtc::SocketAddress& stun_address) {
695b19eba3d4bbc70ece91d524e21e2e9d4253ff7a9honghaiz  state_ = STATE_READY;
696269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
697269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress related_address = stun_address;
698269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!(candidate_filter() & CF_REFLEXIVE)) {
699269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If candidate filter only allows relay type of address, empty raddr to
700269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // avoid local address leakage.
701269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    related_address = rtc::EmptySocketAddressWithFamily(stun_address.family());
702269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
703269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
704269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // For relayed candidate, Base is the candidate itself.
705269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  AddAddress(address,          // Candidate address.
706269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             address,          // Base address.
707269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             related_address,  // Related address.
708269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             UDP_PROTOCOL_NAME,
7093d564c10157d7de1d2d4236f4e2a13ff1363d52bGuo-wei Shieh             ProtoToString(server_address_.proto),  // The first hop protocol.
710269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             "",  // TCP canddiate type, empty for turn candidates.
711269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             RELAY_PORT_TYPE,
712269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             GetRelayPreference(server_address_.proto, server_address_.secure),
7133d564c10157d7de1d2d4236f4e2a13ff1363d52bGuo-wei Shieh             server_priority_, true);
714269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
715269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
716269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnAllocateError() {
717269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // We will send SignalPortError asynchronously as this can be sent during
718269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // port initialization. This way it will not be blocking other port
719269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // creation.
720f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  thread()->Post(this, MSG_ALLOCATE_ERROR);
721f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang}
722f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang
7236b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaizvoid TurnPort::OnTurnRefreshError() {
7246b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  // Need to Close the port asynchronously because otherwise, the refresh
7256b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  // request may be deleted twice: once at the end of the message processing
7266b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  // and the other in Close().
7276b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  thread()->Post(this, MSG_REFRESH_ERROR);
7286b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz}
7296b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz
730f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhangvoid TurnPort::Close() {
7316b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  if (!ready()) {
7326b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz    OnAllocateError();
7336b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  }
7346b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz  request_manager_.Clear();
735f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  // Stop the port from creating new connections.
736f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  state_ = STATE_DISCONNECTED;
737f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  // Delete all existing connections; stop sending data.
738f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  for (auto kv : connections()) {
739f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    kv.second->Destroy();
740f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  }
741269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
742269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
743269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnMessage(rtc::Message* message) {
744f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  switch (message->message_id) {
745f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    case MSG_ALLOCATE_ERROR:
746f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      SignalPortError(this);
747f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      break;
748f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    case MSG_ALLOCATE_MISMATCH:
749f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      OnAllocateMismatch();
750f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      break;
7516b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz    case MSG_REFRESH_ERROR:
7526b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz      Close();
7536b9ab9204b9e0891cb0be2595a0d7ada92945ceahonghaiz      break;
754f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    case MSG_TRY_ALTERNATE_SERVER:
755f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      if (server_address().proto == PROTO_UDP) {
756f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        // Send another allocate request to alternate server, with the received
757f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        // realm and nonce values.
758f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        SendRequest(new TurnAllocateRequest(this), 0);
759f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      } else {
760f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        // Since it's TCP, we have to delete the connected socket and reconnect
761f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        // with the alternate server. PrepareAddress will send stun binding once
762f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        // the new socket is connected.
763f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        ASSERT(server_address().proto == PROTO_TCP);
764f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        ASSERT(!SharedSocket());
765f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        delete socket_;
766f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        socket_ = NULL;
767f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang        PrepareAddress();
768f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      }
769f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      break;
770f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    default:
771f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang      Port::OnMessage(message);
772269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
773269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
774269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
775269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnAllocateRequestTimeout() {
776269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  OnAllocateError();
777269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
778269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
779269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::HandleDataIndication(const char* data, size_t size,
780269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                    const rtc::PacketTime& packet_time) {
781269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Read in the message, and process according to RFC5766, Section 10.4.
782269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::ByteBuffer buf(data, size);
783269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnMessage msg;
784269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!msg.Read(&buf)) {
785269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
786269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
787269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
788269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
789269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check mandatory attributes.
790269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunAddressAttribute* addr_attr =
791269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
792269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!addr_attr) {
793269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
794269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "in data indication.";
795269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
796269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
797269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
798269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* data_attr =
799269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      msg.GetByteString(STUN_ATTR_DATA);
800269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!data_attr) {
801269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
802269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "data indication.";
803269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
804269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
805269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
806269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Verify that the data came from somewhere we think we have a permission for.
807269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress ext_addr(addr_attr->GetAddress());
808269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!HasPermission(ext_addr.ipaddr())) {
809269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
810269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "peer address, addr="
811269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << ext_addr.ToSensitiveString();
812269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
813269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
814269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
815269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
816269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 PROTO_UDP, packet_time);
817269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
818269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
819269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::HandleChannelData(int channel_id, const char* data,
820269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                 size_t size,
821269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                 const rtc::PacketTime& packet_time) {
822269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Read the message, and process according to RFC5766, Section 11.6.
823269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //    0                   1                   2                   3
824269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@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
825269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
826269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   |         Channel Number        |            Length             |
827269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
828269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   |                                                               |
829269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   /                       Application Data                        /
830269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   /                                                               /
831269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   |                                                               |
832269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   |                               +-------------------------------+
833269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   |                               |
834269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  //   +-------------------------------+
835269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
836269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Extract header fields from the message.
8370c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint16_t len = rtc::GetBE16(data + 2);
838269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (len > size - TURN_CHANNEL_HEADER_SIZE) {
839269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
840269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "incorrect length, len=" << len;
841269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
842269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
843269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Allowing messages larger than |len|, as ChannelData can be padded.
844269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
845269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  TurnEntry* entry = FindEntry(channel_id);
846269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!entry) {
847269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
848269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "channel, channel_id=" << channel_id;
849269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
850269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
851269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
852269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
853269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 PROTO_UDP, packet_time);
854269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
855269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
856269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::DispatchPacket(const char* data, size_t size,
857269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& remote_addr,
858269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ProtocolType proto, const rtc::PacketTime& packet_time) {
859269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (Connection* conn = GetConnection(remote_addr)) {
860269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    conn->OnReadPacket(data, size, packet_time);
861269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
862269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    Port::OnReadPacket(data, size, remote_addr, proto);
863269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
864269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
865269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
866269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool TurnPort::ScheduleRefresh(int lifetime) {
867269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Lifetime is in seconds; we schedule a refresh for one minute less.
868269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (lifetime < 2 * 60) {
869269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
870269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << "too short, lifetime=" << lifetime;
871269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
872269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
873269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
874b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher  int delay = (lifetime - 60) * 1000;
875b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher  SendRequest(new TurnRefreshRequest(this), delay);
876b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher  LOG_J(LS_INFO, this) << "Scheduled refresh in " << delay << "ms.";
877269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
878269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
879269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
880269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::SendRequest(StunRequest* req, int delay) {
881269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request_manager_.SendDelayed(req, delay);
882269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
883269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
884269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::AddRequestAuthInfo(StunMessage* msg) {
885269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // If we've gotten the necessary data from the server, add it to our request.
886269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(!hash_.empty());
887269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(msg->AddAttribute(new StunByteStringAttribute(
888269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_USERNAME, credentials_.username)));
889269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(msg->AddAttribute(new StunByteStringAttribute(
890269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_REALM, realm_)));
891269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(msg->AddAttribute(new StunByteStringAttribute(
892269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_NONCE, nonce_)));
893269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(msg->AddMessageIntegrity(hash()));
894269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
895269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
896269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint TurnPort::Send(const void* data, size_t len,
897269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                   const rtc::PacketOptions& options) {
898269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return socket_->SendTo(data, len, server_address_.address, options);
899269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
900269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
901269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::UpdateHash() {
902269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
903269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                   credentials_.password, &hash_));
904269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
905269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
906269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool TurnPort::UpdateNonce(StunMessage* response) {
907269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // When stale nonce error received, we should update
908269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // hash and store realm and nonce.
909269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check the mandatory attributes.
910269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* realm_attr =
911269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetByteString(STUN_ATTR_REALM);
912269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!realm_attr) {
913269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
914269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                  << "stale nonce error response.";
915269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
916269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
917269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  set_realm(realm_attr->GetString());
918269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
919269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* nonce_attr =
920269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetByteString(STUN_ATTR_NONCE);
921269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!nonce_attr) {
922269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
923269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                  << "stale nonce error response.";
924269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
925269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
926269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  set_nonce(nonce_attr->GetString());
927269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
928269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
929269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
930269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
931269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return e->address().ipaddr() == ipaddr;
932269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
933269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
934269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return (std::find_if(entries_.begin(), entries_.end(),
935269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
936269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
937269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
938269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
939269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return e->address() == addr;
940269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
941269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
942269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
943269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      std::bind2nd(std::ptr_fun(MatchesAddress), addr));
944269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return (it != entries_.end()) ? *it : NULL;
945269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
946269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
947269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgstatic bool MatchesChannelId(TurnEntry* e, int id) {
948269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return e->channel_id() == id;
949269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
950269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnEntry* TurnPort::FindEntry(int channel_id) const {
951269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
952269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
953269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return (it != entries_.end()) ? *it : NULL;
954269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
955269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
956c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaizbool TurnPort::EntryExists(TurnEntry* e) {
957c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz  auto it = std::find(entries_.begin(), entries_.end(), e);
958c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz  return it != entries_.end();
959c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz}
960c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz
96132f39968ce79cfca5146069e410ded2f104bba23honghaizvoid TurnPort::CreateOrRefreshEntry(const rtc::SocketAddress& addr) {
96232f39968ce79cfca5146069e410ded2f104bba23honghaiz  TurnEntry* entry = FindEntry(addr);
96332f39968ce79cfca5146069e410ded2f104bba23honghaiz  if (entry == nullptr) {
96432f39968ce79cfca5146069e410ded2f104bba23honghaiz    entry = new TurnEntry(this, next_channel_number_++, addr);
96532f39968ce79cfca5146069e410ded2f104bba23honghaiz    entries_.push_back(entry);
96632f39968ce79cfca5146069e410ded2f104bba23honghaiz  } else {
96732f39968ce79cfca5146069e410ded2f104bba23honghaiz    // The channel binding request for the entry will be refreshed automatically
96832f39968ce79cfca5146069e410ded2f104bba23honghaiz    // until the entry is destroyed.
96932f39968ce79cfca5146069e410ded2f104bba23honghaiz    CancelEntryDestruction(entry);
97032f39968ce79cfca5146069e410ded2f104bba23honghaiz  }
971269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
972269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
97332f39968ce79cfca5146069e410ded2f104bba23honghaizvoid TurnPort::DestroyEntry(TurnEntry* entry) {
974269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(entry != NULL);
975269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  entry->SignalDestroyed(entry);
976269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  entries_.remove(entry);
977269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  delete entry;
978269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
979269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
98032f39968ce79cfca5146069e410ded2f104bba23honghaizvoid TurnPort::DestroyEntryIfNotCancelled(TurnEntry* entry,
98132f39968ce79cfca5146069e410ded2f104bba23honghaiz                                          uint32_t timestamp) {
982c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz  if (!EntryExists(entry)) {
983c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz    return;
984c3e0fe7c21a6c6c367ce38b54634dc38f6222693honghaiz  }
98532f39968ce79cfca5146069e410ded2f104bba23honghaiz  bool cancelled = timestamp != entry->destruction_timestamp();
98632f39968ce79cfca5146069e410ded2f104bba23honghaiz  if (!cancelled) {
98732f39968ce79cfca5146069e410ded2f104bba23honghaiz    DestroyEntry(entry);
98832f39968ce79cfca5146069e410ded2f104bba23honghaiz  }
98932f39968ce79cfca5146069e410ded2f104bba23honghaiz}
99032f39968ce79cfca5146069e410ded2f104bba23honghaiz
991269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnPort::OnConnectionDestroyed(Connection* conn) {
99232f39968ce79cfca5146069e410ded2f104bba23honghaiz  // Schedule an event to destroy TurnEntry for the connection, which is
99332f39968ce79cfca5146069e410ded2f104bba23honghaiz  // already destroyed.
99432f39968ce79cfca5146069e410ded2f104bba23honghaiz  const rtc::SocketAddress& remote_address = conn->remote_candidate().address();
99532f39968ce79cfca5146069e410ded2f104bba23honghaiz  TurnEntry* entry = FindEntry(remote_address);
99632f39968ce79cfca5146069e410ded2f104bba23honghaiz  ASSERT(entry != NULL);
99732f39968ce79cfca5146069e410ded2f104bba23honghaiz  ScheduleEntryDestruction(entry);
99832f39968ce79cfca5146069e410ded2f104bba23honghaiz}
99932f39968ce79cfca5146069e410ded2f104bba23honghaiz
100032f39968ce79cfca5146069e410ded2f104bba23honghaizvoid TurnPort::ScheduleEntryDestruction(TurnEntry* entry) {
100132f39968ce79cfca5146069e410ded2f104bba23honghaiz  ASSERT(entry->destruction_timestamp() == 0);
100232f39968ce79cfca5146069e410ded2f104bba23honghaiz  uint32_t timestamp = rtc::Time();
100332f39968ce79cfca5146069e410ded2f104bba23honghaiz  entry->set_destruction_timestamp(timestamp);
100432f39968ce79cfca5146069e410ded2f104bba23honghaiz  invoker_.AsyncInvokeDelayed<void>(
100532f39968ce79cfca5146069e410ded2f104bba23honghaiz      thread(),
100632f39968ce79cfca5146069e410ded2f104bba23honghaiz      rtc::Bind(&TurnPort::DestroyEntryIfNotCancelled, this, entry, timestamp),
100732f39968ce79cfca5146069e410ded2f104bba23honghaiz      TURN_PERMISSION_TIMEOUT);
100832f39968ce79cfca5146069e410ded2f104bba23honghaiz}
100932f39968ce79cfca5146069e410ded2f104bba23honghaiz
101032f39968ce79cfca5146069e410ded2f104bba23honghaizvoid TurnPort::CancelEntryDestruction(TurnEntry* entry) {
101132f39968ce79cfca5146069e410ded2f104bba23honghaiz  ASSERT(entry->destruction_timestamp() != 0);
101232f39968ce79cfca5146069e410ded2f104bba23honghaiz  entry->set_destruction_timestamp(0);
1013269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1014269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1015f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhangbool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address,
1016f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang                                 int channel_id) {
1017f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  TurnEntry* entry = FindEntry(address);
1018f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  if (!entry) {
1019f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    return false;
1020f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  }
1021f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  entry->set_channel_id(channel_id);
1022f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  return true;
1023f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang}
1024f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang
1025269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
1026269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    : StunRequest(new TurnMessage()),
1027269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_(port) {
1028269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1029269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1030269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnAllocateRequest::Prepare(StunMessage* request) {
1031269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Create the request as indicated in RFC 5766, Section 6.1.
1032269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request->SetType(TURN_ALLOCATE_REQUEST);
1033269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
1034269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_REQUESTED_TRANSPORT);
1035269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  transport_attr->SetValue(IPPROTO_UDP << 24);
1036269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(request->AddAttribute(transport_attr));
1037269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!port_->hash().empty()) {
1038269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->AddRequestAuthInfo(request);
1039269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1040269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1041269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
10421cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatchervoid TurnAllocateRequest::OnSent() {
10431cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN allocate request sent"
10441cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id());
10451cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  StunRequest::OnSent();
10461cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher}
10471cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1048269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnAllocateRequest::OnResponse(StunMessage* response) {
10491cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN allocate requested successfully"
10501cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id())
10511cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", code=0"  // Makes logging easier to parse.
10521cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", rtt=" << Elapsed();
10531cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1054269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check mandatory attributes as indicated in RFC5766, Section 6.3.
1055269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunAddressAttribute* mapped_attr =
1056269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1057269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!mapped_attr) {
1058269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
1059269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "attribute in allocate success response";
1060269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1061269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1062269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Using XOR-Mapped-Address for stun.
1063269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->OnStunAddress(mapped_attr->GetAddress());
1064269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1065269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunAddressAttribute* relayed_attr =
1066269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
1067269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!relayed_attr) {
1068269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
1069269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "attribute in allocate success response";
1070269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1071269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1072269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1073269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunUInt32Attribute* lifetime_attr =
1074269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1075269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!lifetime_attr) {
1076269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1077269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "allocate success response";
1078269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1079269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1080269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Notify the port the allocate succeeded, and schedule a refresh request.
1081269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->OnAllocateSuccess(relayed_attr->GetAddress(),
1082269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                           mapped_attr->GetAddress());
1083269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->ScheduleRefresh(lifetime_attr->value());
1084269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1085269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1086269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
1087269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Process error response according to RFC5766, Section 6.4.
1088269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunErrorCodeAttribute* error_code = response->GetErrorCode();
10891cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
10901cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "Received TURN allocate error response"
10911cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id())
10921cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", code=" << error_code->code()
10931cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", rtt=" << Elapsed();
10941cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1095269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  switch (error_code->code()) {
1096269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    case STUN_ERROR_UNAUTHORIZED:       // Unauthrorized.
1097269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      OnAuthChallenge(response, error_code->code());
1098269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      break;
1099269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    case STUN_ERROR_TRY_ALTERNATE:
1100269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      OnTryAlternate(response, error_code->code());
1101269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      break;
1102269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    case STUN_ERROR_ALLOCATION_MISMATCH:
1103269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // We must handle this error async because trying to delete the socket in
1104269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // OnErrorResponse will cause a deadlock on the socket.
1105269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH);
1106269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      break;
1107269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    default:
11081cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher      LOG_J(LS_WARNING, port_) << "Received TURN allocate error response"
11091cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                               << ", id=" << rtc::hex_encode(id())
11101cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                               << ", code=" << error_code->code()
11111cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                               << ", rtt=" << Elapsed();
1112269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_->OnAllocateError();
1113269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1114269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1115269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1116269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnAllocateRequest::OnTimeout() {
11171cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_WARNING, port_) << "TURN allocate request "
11181cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << rtc::hex_encode(id()) << " timout";
1119269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->OnAllocateRequestTimeout();
1120269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1121269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1122269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
1123269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // If we failed to authenticate even after we sent our credentials, fail hard.
1124269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
1125269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
1126269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "after challenge.";
1127269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->OnAllocateError();
1128269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1129269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1130269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1131269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check the mandatory attributes.
1132269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* realm_attr =
1133269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetByteString(STUN_ATTR_REALM);
1134269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!realm_attr) {
1135269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
1136269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "allocate unauthorized response.";
1137269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1138269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1139269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->set_realm(realm_attr->GetString());
1140269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1141269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* nonce_attr =
1142269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetByteString(STUN_ATTR_NONCE);
1143269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!nonce_attr) {
1144269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
1145269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "allocate unauthorized response.";
1146269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1147269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1148269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->set_nonce(nonce_attr->GetString());
1149269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1150269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Send another allocate request, with the received realm and nonce values.
1151269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->SendRequest(new TurnAllocateRequest(port_), 0);
1152269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1153269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1154269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
1155269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1156269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // According to RFC 5389 section 11, there are use cases where
1157269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // authentication of response is not possible, we're not validating
1158269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // message integrity.
1159269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1160269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Get the alternate server address attribute value.
1161269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunAddressAttribute* alternate_server_attr =
1162269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
1163269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!alternate_server_attr) {
1164269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
1165269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "attribute in try alternate error response";
1166269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->OnAllocateError();
1167269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1168269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1169269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
1170269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->OnAllocateError();
1171269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1172269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1173269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1174269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check the attributes.
1175269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* realm_attr =
1176269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetByteString(STUN_ATTR_REALM);
1177269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (realm_attr) {
1178269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
1179269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                          << "try alternate error response.";
1180269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->set_realm(realm_attr->GetString());
1181269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1182269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1183269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunByteStringAttribute* nonce_attr =
1184269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetByteString(STUN_ATTR_NONCE);
1185269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (nonce_attr) {
1186269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
1187269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                          << "try alternate error response.";
1188269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->set_nonce(nonce_attr->GetString());
1189269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1190269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
119119e4e8d751478d34c05bc2d73e065429ed65a1c1guoweis@webrtc.org  // For TCP, we can't close the original Tcp socket during handling a 300 as
119219e4e8d751478d34c05bc2d73e065429ed65a1c1guoweis@webrtc.org  // we're still inside that socket's event handler. Doing so will cause
119319e4e8d751478d34c05bc2d73e065429ed65a1c1guoweis@webrtc.org  // deadlock.
119419e4e8d751478d34c05bc2d73e065429ed65a1c1guoweis@webrtc.org  port_->thread()->Post(port_, TurnPort::MSG_TRY_ALTERNATE_SERVER);
1195269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1196269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1197269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
1198269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    : StunRequest(new TurnMessage()),
1199fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org      port_(port),
1200fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org      lifetime_(-1) {
1201269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1202269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1203269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnRefreshRequest::Prepare(StunMessage* request) {
1204269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Create the request as indicated in RFC 5766, Section 7.1.
1205269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // No attributes need to be included.
1206269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request->SetType(TURN_REFRESH_REQUEST);
1207fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  if (lifetime_ > -1) {
1208fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org    VERIFY(request->AddAttribute(new StunUInt32Attribute(
1209fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org        STUN_ATTR_LIFETIME, lifetime_)));
1210fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org  }
1211fe672e3839004350403423b74764d42396a0edabpthatcher@webrtc.org
1212269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->AddRequestAuthInfo(request);
1213269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1214269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
12151cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatchervoid TurnRefreshRequest::OnSent() {
12161cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN refresh request sent"
12171cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id());
12181cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  StunRequest::OnSent();
12191cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher}
12201cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1221269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnRefreshRequest::OnResponse(StunMessage* response) {
12221cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN refresh requested successfully"
12231cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id())
12241cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", code=0"  // Makes logging easier to parse.
12251cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", rtt=" << Elapsed();
1226b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher
1227269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Check mandatory attributes as indicated in RFC5766, Section 7.3.
1228269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunUInt32Attribute* lifetime_attr =
1229269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
1230269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!lifetime_attr) {
1231269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
1232269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                             << "refresh success response.";
1233269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
1234269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1235269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1236269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Schedule a refresh based on the returned lifetime value.
1237269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->ScheduleRefresh(lifetime_attr->value());
1238f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  port_->SignalTurnRefreshResult(port_, TURN_SUCCESS_RESULT_CODE);
1239269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1240269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1241269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
1242269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const StunErrorCodeAttribute* error_code = response->GetErrorCode();
12431cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1244269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (error_code->code() == STUN_ERROR_STALE_NONCE) {
1245269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (port_->UpdateNonce(response)) {
1246269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // Send RefreshRequest immediately.
1247269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_->SendRequest(new TurnRefreshRequest(port_), 0);
1248269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
12491cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  } else {
12501cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher    LOG_J(LS_WARNING, port_) << "Received TURN refresh error response"
12511cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                             << ", id=" << rtc::hex_encode(id())
12521cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                             << ", code=" << error_code->code()
12531cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                             << ", rtt=" << Elapsed();
1254f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    port_->OnTurnRefreshError();
1255f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    port_->SignalTurnRefreshResult(port_, error_code->code());
1256269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1257269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1258269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1259269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnRefreshRequest::OnTimeout() {
12601cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id());
1261f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  port_->OnTurnRefreshError();
1262269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1263269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1264269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnCreatePermissionRequest::TurnCreatePermissionRequest(
1265269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    TurnPort* port, TurnEntry* entry,
1266269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& ext_addr)
1267269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    : StunRequest(new TurnMessage()),
1268269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_(port),
1269269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      entry_(entry),
1270269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      ext_addr_(ext_addr) {
1271269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  entry_->SignalDestroyed.connect(
1272269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      this, &TurnCreatePermissionRequest::OnEntryDestroyed);
1273269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1274269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1275269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnCreatePermissionRequest::Prepare(StunMessage* request) {
1276269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Create the request as indicated in RFC5766, Section 9.1.
1277269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request->SetType(TURN_CREATE_PERMISSION_REQUEST);
1278269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1279269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1280269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->AddRequestAuthInfo(request);
1281269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1282269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
12831cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatchervoid TurnCreatePermissionRequest::OnSent() {
12841cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN create permission request sent"
12851cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id());
12861cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  StunRequest::OnSent();
12871cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher}
12881cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1289269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
12901cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN permission requested successfully"
12911cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id())
12921cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", code=0"  // Makes logging easier to parse.
12931cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", rtt=" << Elapsed();
12941cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1295269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (entry_) {
1296269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    entry_->OnCreatePermissionSuccess();
1297269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1298269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1299269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1300269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
1301b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher  const StunErrorCodeAttribute* error_code = response->GetErrorCode();
13021cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_WARNING, port_) << "Received TURN create permission error response"
13031cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << ", id=" << rtc::hex_encode(id())
13041cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << ", code=" << error_code->code()
13051cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << ", rtt=" << Elapsed();
1306269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (entry_) {
1307269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    entry_->OnCreatePermissionError(response, error_code->code());
1308269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1309269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1310269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1311269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnCreatePermissionRequest::OnTimeout() {
13121cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_WARNING, port_) << "TURN create permission timeout "
13131cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << rtc::hex_encode(id());
1314f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  if (entry_) {
1315f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    entry_->OnCreatePermissionTimeout();
1316f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  }
1317269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1318269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1319269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
1320269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(entry_ == entry);
1321269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  entry_ = NULL;
1322269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1323269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1324269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnChannelBindRequest::TurnChannelBindRequest(
1325269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    TurnPort* port, TurnEntry* entry,
1326269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    int channel_id, const rtc::SocketAddress& ext_addr)
1327269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    : StunRequest(new TurnMessage()),
1328269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_(port),
1329269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      entry_(entry),
1330269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      channel_id_(channel_id),
1331269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      ext_addr_(ext_addr) {
1332269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  entry_->SignalDestroyed.connect(
1333269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      this, &TurnChannelBindRequest::OnEntryDestroyed);
1334269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1335269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1336269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnChannelBindRequest::Prepare(StunMessage* request) {
1337269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Create the request as indicated in RFC5766, Section 11.1.
1338269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  request->SetType(TURN_CHANNEL_BIND_REQUEST);
1339269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(request->AddAttribute(new StunUInt32Attribute(
1340269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)));
1341269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  VERIFY(request->AddAttribute(new StunXorAddressAttribute(
1342269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1343269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->AddRequestAuthInfo(request);
1344269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1345269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
13461cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatchervoid TurnChannelBindRequest::OnSent() {
13471cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN channel bind request sent"
13481cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id());
13491cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  StunRequest::OnSent();
13501cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher}
13511cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1352269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnChannelBindRequest::OnResponse(StunMessage* response) {
13531cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_INFO, port_) << "TURN channel bind requested successfully"
13541cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", id=" << rtc::hex_encode(id())
13551cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", code=0"  // Makes logging easier to parse.
13561cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                        << ", rtt=" << Elapsed();
13571cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher
1358269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (entry_) {
1359269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    entry_->OnChannelBindSuccess();
1360269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // Refresh the channel binding just under the permission timeout
1361269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // threshold. The channel binding has a longer lifetime, but
1362269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // this is the easiest way to keep both the channel and the
1363269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // permission from expiring.
1364b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher    int delay = TURN_PERMISSION_TIMEOUT - 60000;
1365b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher    entry_->SendChannelBindRequest(delay);
1366b32a5c48d3d0b17f564fe680c7e1e45d5b76eefdPeter Thatcher    LOG_J(LS_INFO, port_) << "Scheduled channel bind in " << delay << "ms.";
1367269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1368269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1369269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1370269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
13711cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  const StunErrorCodeAttribute* error_code = response->GetErrorCode();
13721cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_WARNING, port_) << "Received TURN channel bind error response"
13731cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << ", id=" << rtc::hex_encode(id())
13741cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << ", code=" << error_code->code()
13751cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << ", rtt=" << Elapsed();
1376269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (entry_) {
1377269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    entry_->OnChannelBindError(response, error_code->code());
1378269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1379269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1380269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1381269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnChannelBindRequest::OnTimeout() {
13821cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  LOG_J(LS_WARNING, port_) << "TURN channel bind timeout "
13831cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher                           << rtc::hex_encode(id());
1384f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  if (entry_) {
1385f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    entry_->OnChannelBindTimeout();
1386f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  }
1387269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1388269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1389269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
1390269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(entry_ == entry);
1391269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  entry_ = NULL;
1392269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1393269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1394269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgTurnEntry::TurnEntry(TurnPort* port, int channel_id,
1395269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                     const rtc::SocketAddress& ext_addr)
1396269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    : port_(port),
1397269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      channel_id_(channel_id),
1398269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      ext_addr_(ext_addr),
1399269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      state_(STATE_UNBOUND) {
1400269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Creating permission for |ext_addr_|.
14018597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  SendCreatePermissionRequest(0);
1402269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1403269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
14048597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhangvoid TurnEntry::SendCreatePermissionRequest(int delay) {
14058597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
14068597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang                     delay);
1407269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1408269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1409269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnEntry::SendChannelBindRequest(int delay) {
1410269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  port_->SendRequest(new TurnChannelBindRequest(
1411269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_, this, channel_id_, ext_addr_), delay);
1412269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1413269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1414269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint TurnEntry::Send(const void* data, size_t size, bool payload,
1415269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                    const rtc::PacketOptions& options) {
1416269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::ByteBuffer buf;
1417269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (state_ != STATE_BOUND) {
1418269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If we haven't bound the channel yet, we have to use a Send Indication.
1419269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    TurnMessage msg;
1420269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    msg.SetType(TURN_SEND_INDICATION);
1421269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    msg.SetTransactionID(
1422269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        rtc::CreateRandomString(kStunTransactionIdLength));
1423269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
1424269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
1425269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    VERIFY(msg.AddAttribute(new StunByteStringAttribute(
1426269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        STUN_ATTR_DATA, data, size)));
1427269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    VERIFY(msg.Write(&buf));
1428269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1429269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If we're sending real data, request a channel bind that we can use later.
1430269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (state_ == STATE_UNBOUND && payload) {
1431269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      SendChannelBindRequest(0);
1432269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      state_ = STATE_BINDING;
1433269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
1434269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
1435269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // If the channel is bound, we can send the data as a Channel Message.
1436269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    buf.WriteUInt16(channel_id_);
14370c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    buf.WriteUInt16(static_cast<uint16_t>(size));
1438269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    buf.WriteBytes(reinterpret_cast<const char*>(data), size);
1439269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1440269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return port_->Send(buf.Data(), buf.Length(), options);
1441269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1442269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1443269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnEntry::OnCreatePermissionSuccess() {
1444269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LOG_J(LS_INFO, port_) << "Create permission for "
1445269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                        << ext_addr_.ToSensitiveString()
1446269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                        << " succeeded";
1447f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  port_->SignalCreatePermissionResult(port_, ext_addr_,
1448f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang                                      TURN_SUCCESS_RESULT_CODE);
14498597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang
14508597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  // If |state_| is STATE_BOUND, the permission will be refreshed
14518597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  // by ChannelBindRequest.
14528597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  if (state_ != STATE_BOUND) {
14538597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang    // Refresh the permission request about 1 minute before the permission
14548597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang    // times out.
14558597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang    int delay = TURN_PERMISSION_TIMEOUT - 60000;
14568597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang    SendCreatePermissionRequest(delay);
14578597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang    LOG_J(LS_INFO, port_) << "Scheduled create-permission-request in "
14588597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang                          << delay << "ms.";
14598597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang  }
1460269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1461269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1462269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
1463269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (code == STUN_ERROR_STALE_NONCE) {
1464269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (port_->UpdateNonce(response)) {
14658597543ae845073ca32876bfaaff207017b6c0ebHonghai Zhang      SendCreatePermissionRequest(0);
1466269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
1467269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
1468f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    port_->DestroyConnection(ext_addr_);
1469269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // Send signal with error code.
1470269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->SignalCreatePermissionResult(port_, ext_addr_, code);
1471376e1235c7b602e86afe9f36eb81289e42643718deadbeef    Connection* c = port_->GetConnection(ext_addr_);
1472376e1235c7b602e86afe9f36eb81289e42643718deadbeef    if (c) {
1473376e1235c7b602e86afe9f36eb81289e42643718deadbeef      LOG_J(LS_ERROR, c) << "Received TURN CreatePermission error response, "
1474376e1235c7b602e86afe9f36eb81289e42643718deadbeef                         << "code=" << code << "; killing connection.";
1475376e1235c7b602e86afe9f36eb81289e42643718deadbeef      c->FailAndDestroy();
1476376e1235c7b602e86afe9f36eb81289e42643718deadbeef    }
1477269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1478269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1479269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1480f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhangvoid TurnEntry::OnCreatePermissionTimeout() {
1481f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  port_->DestroyConnection(ext_addr_);
1482f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang}
1483f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang
1484269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnEntry::OnChannelBindSuccess() {
1485269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
1486269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                        << " succeeded";
1487269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND);
1488269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  state_ = STATE_BOUND;
1489269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1490269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
1491269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid TurnEntry::OnChannelBindError(StunMessage* response, int code) {
1492f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  // If the channel bind fails due to errors other than STATE_NONCE,
1493f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  // we just destroy the connection and rely on ICE restart to re-establish
1494f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  // the connection.
1495269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (code == STUN_ERROR_STALE_NONCE) {
1496269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (port_->UpdateNonce(response)) {
1497269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // Send channel bind request with fresh nonce.
1498269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      SendChannelBindRequest(0);
1499269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
1500f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  } else {
1501f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    state_ = STATE_UNBOUND;
1502f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang    port_->DestroyConnection(ext_addr_);
1503269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
1504269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
1505f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhangvoid TurnEntry::OnChannelBindTimeout() {
1506f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  state_ = STATE_UNBOUND;
1507f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang  port_->DestroyConnection(ext_addr_);
1508f67c548576ad957a1e9c3196e11d45f41e320424Honghai Zhang}
1509269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}  // namespace cricket
1510