Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / base / rawtransportchannel.cc
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "webrtc/p2p/base/rawtransportchannel.h"
29
30 #include <string>
31 #include <vector>
32 #include "webrtc/p2p/base/constants.h"
33 #include "webrtc/p2p/base/portallocator.h"
34 #include "webrtc/p2p/base/portinterface.h"
35 #include "webrtc/p2p/base/rawtransport.h"
36 #include "webrtc/p2p/base/relayport.h"
37 #include "webrtc/p2p/base/sessionmanager.h"
38 #include "webrtc/p2p/base/stunport.h"
39 #include "webrtc/libjingle/xmllite/qname.h"
40 #include "webrtc/libjingle/xmllite/xmlelement.h"
41 #include "webrtc/libjingle/xmpp/constants.h"
42 #include "webrtc/base/common.h"
43
44 #if defined(FEATURE_ENABLE_PSTN)
45
46 namespace {
47
48 const uint32 MSG_DESTROY_RTC_UNUSED_PORTS = 1;
49
50 }  // namespace
51
52 namespace cricket {
53
54 RawTransportChannel::RawTransportChannel(const std::string& content_name,
55                                          int component,
56                                          RawTransport* transport,
57                                          rtc::Thread *worker_thread,
58                                          PortAllocator *allocator)
59   : TransportChannelImpl(content_name, component),
60     raw_transport_(transport),
61     allocator_(allocator),
62     allocator_session_(NULL),
63     stun_port_(NULL),
64     relay_port_(NULL),
65     port_(NULL),
66     use_relay_(false) {
67   if (worker_thread == NULL)
68     worker_thread_ = raw_transport_->worker_thread();
69   else
70     worker_thread_ = worker_thread;
71 }
72
73 RawTransportChannel::~RawTransportChannel() {
74   delete allocator_session_;
75 }
76
77 int RawTransportChannel::SendPacket(const char *data, size_t size,
78                                     const rtc::PacketOptions& options,
79                                     int flags) {
80   if (port_ == NULL)
81     return -1;
82   if (remote_address_.IsNil())
83     return -1;
84   if (flags != 0)
85     return -1;
86   return port_->SendTo(data, size, remote_address_, options, true);
87 }
88
89 int RawTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
90   // TODO: allow these to be set before we have a port
91   if (port_ == NULL)
92     return -1;
93   return port_->SetOption(opt, value);
94 }
95
96 int RawTransportChannel::GetError() {
97   return (port_ != NULL) ? port_->GetError() : 0;
98 }
99
100 void RawTransportChannel::Connect() {
101   // Create an allocator that only returns stun and relay ports.
102   // Use empty string for ufrag and pwd here. There won't be any STUN or relay
103   // interactions when using RawTC.
104   // TODO: Change raw to only use local udp ports.
105   allocator_session_ = allocator_->CreateSession(
106       SessionId(), content_name(), component(), "", "");
107
108   uint32 flags = PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP;
109
110 #if !defined(FEATURE_ENABLE_STUN_CLASSIFICATION)
111   flags |= PORTALLOCATOR_DISABLE_RELAY;
112 #endif
113   allocator_session_->set_flags(flags);
114   allocator_session_->SignalPortReady.connect(
115       this, &RawTransportChannel::OnPortReady);
116   allocator_session_->SignalCandidatesReady.connect(
117       this, &RawTransportChannel::OnCandidatesReady);
118
119   // The initial ports will include stun.
120   allocator_session_->StartGettingPorts();
121 }
122
123 void RawTransportChannel::Reset() {
124   set_readable(false);
125   set_writable(false);
126
127   delete allocator_session_;
128
129   allocator_session_ = NULL;
130   stun_port_ = NULL;
131   relay_port_ = NULL;
132   port_ = NULL;
133   remote_address_ = rtc::SocketAddress();
134 }
135
136 void RawTransportChannel::OnCandidate(const Candidate& candidate) {
137   remote_address_ = candidate.address();
138   ASSERT(!remote_address_.IsNil());
139   set_readable(true);
140
141   // We can write once we have a port and a remote address.
142   if (port_ != NULL)
143     SetWritable();
144 }
145
146 void RawTransportChannel::OnRemoteAddress(
147     const rtc::SocketAddress& remote_address) {
148   remote_address_ = remote_address;
149   set_readable(true);
150
151   if (port_ != NULL)
152     SetWritable();
153 }
154
155 // Note about stun classification
156 // Code to classify our NAT type and use the relay port if we are behind an
157 // asymmetric NAT is under a FEATURE_ENABLE_STUN_CLASSIFICATION #define.
158 // To turn this one we will have to enable a second stun address and make sure
159 // that the relay server works for raw UDP.
160 //
161 // Another option is to classify the NAT type early and not offer the raw
162 // transport type at all if we can't support it.
163
164 void RawTransportChannel::OnPortReady(
165     PortAllocatorSession* session, PortInterface* port) {
166   ASSERT(session == allocator_session_);
167
168   if (port->Type() == STUN_PORT_TYPE) {
169     stun_port_ = static_cast<StunPort*>(port);
170   } else if (port->Type() == RELAY_PORT_TYPE) {
171     relay_port_ = static_cast<RelayPort*>(port);
172   } else {
173     ASSERT(false);
174   }
175 }
176
177 void RawTransportChannel::OnCandidatesReady(
178     PortAllocatorSession *session, const std::vector<Candidate>& candidates) {
179   ASSERT(session == allocator_session_);
180   ASSERT(candidates.size() >= 1);
181
182   // The most recent candidate is the one we haven't seen yet.
183   Candidate c = candidates[candidates.size() - 1];
184
185   if (c.type() == STUN_PORT_TYPE) {
186     ASSERT(stun_port_ != NULL);
187
188 #if defined(FEATURE_ENABLE_STUN_CLASSIFICATION)
189     // We need to wait until we have two addresses.
190     if (stun_port_->candidates().size() < 2)
191       return;
192
193     // This is the second address.  If these addresses are the same, then we
194     // are not behind a symmetric NAT.  Hence, a stun port should be sufficient.
195     if (stun_port_->candidates()[0].address() ==
196         stun_port_->candidates()[1].address()) {
197       SetPort(stun_port_);
198       return;
199     }
200
201     // We will need to use relay.
202     use_relay_ = true;
203
204     // If we already have a relay address, we're good.  Otherwise, we will need
205     // to wait until one arrives.
206     if (relay_port_->candidates().size() > 0)
207       SetPort(relay_port_);
208 #else  // defined(FEATURE_ENABLE_STUN_CLASSIFICATION)
209     // Always use the stun port.  We don't classify right now so just assume it
210     // will work fine.
211     SetPort(stun_port_);
212 #endif
213   } else if (c.type() == RELAY_PORT_TYPE) {
214     if (use_relay_)
215       SetPort(relay_port_);
216   } else {
217     ASSERT(false);
218   }
219 }
220
221 void RawTransportChannel::SetPort(PortInterface* port) {
222   ASSERT(port_ == NULL);
223   port_ = port;
224
225   // We don't need any ports other than the one we picked.
226   allocator_session_->StopGettingPorts();
227   worker_thread_->Post(
228       this, MSG_DESTROY_RTC_UNUSED_PORTS, NULL);
229
230   // Send a message to the other client containing our address.
231
232   ASSERT(port_->Candidates().size() >= 1);
233   ASSERT(port_->Candidates()[0].protocol() == "udp");
234   SignalCandidateReady(this, port_->Candidates()[0]);
235
236   // Read all packets from this port.
237   port_->EnablePortPackets();
238   port_->SignalReadPacket.connect(this, &RawTransportChannel::OnReadPacket);
239
240   // We can write once we have a port and a remote address.
241   if (!remote_address_.IsAny())
242     SetWritable();
243 }
244
245 void RawTransportChannel::SetWritable() {
246   ASSERT(port_ != NULL);
247   ASSERT(!remote_address_.IsAny());
248
249   set_writable(true);
250
251   Candidate remote_candidate;
252   remote_candidate.set_address(remote_address_);
253   SignalRouteChange(this, remote_candidate);
254 }
255
256 void RawTransportChannel::OnReadPacket(
257     PortInterface* port, const char* data, size_t size,
258     const rtc::SocketAddress& addr) {
259   ASSERT(port_ == port);
260   SignalReadPacket(this, data, size, rtc::CreatePacketTime(0), 0);
261 }
262
263 void RawTransportChannel::OnMessage(rtc::Message* msg) {
264   ASSERT(msg->message_id == MSG_DESTROY_RTC_UNUSED_PORTS);
265   ASSERT(port_ != NULL);
266   if (port_ != stun_port_) {
267     stun_port_->Destroy();
268     stun_port_ = NULL;
269   }
270   if (port_ != relay_port_ && relay_port_ != NULL) {
271     relay_port_->Destroy();
272     relay_port_ = NULL;
273   }
274 }
275
276 }  // namespace cricket
277 #endif  // defined(FEATURE_ENABLE_PSTN)