Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / base / transportchannelproxy.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 "talk/p2p/base/transportchannelproxy.h"
29 #include "talk/base/common.h"
30 #include "talk/base/logging.h"
31 #include "talk/base/thread.h"
32 #include "talk/p2p/base/transport.h"
33 #include "talk/p2p/base/transportchannelimpl.h"
34
35 namespace cricket {
36
37 enum {
38   MSG_UPDATESTATE,
39 };
40
41 TransportChannelProxy::TransportChannelProxy(const std::string& content_name,
42                                              const std::string& name,
43                                              int component)
44     : TransportChannel(content_name, component),
45       name_(name),
46       impl_(NULL) {
47   worker_thread_ = talk_base::Thread::Current();
48 }
49
50 TransportChannelProxy::~TransportChannelProxy() {
51   // Clearing any pending signal.
52   worker_thread_->Clear(this);
53   if (impl_)
54     impl_->GetTransport()->DestroyChannel(impl_->component());
55 }
56
57 void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) {
58   ASSERT(talk_base::Thread::Current() == worker_thread_);
59
60   if (impl == impl_) {
61     ASSERT(false);
62     // Ignore if the |impl| has already been set.
63     LOG(LS_WARNING) << "Ignored TransportChannelProxy::SetImplementation call "
64                     << "with a same impl as the existing one.";
65     return;
66   }
67
68   // Destroy any existing impl_.
69   if (impl_) {
70     impl_->GetTransport()->DestroyChannel(impl_->component());
71   }
72
73   // Adopt the supplied impl, and connect to its signals.
74   impl_ = impl;
75
76   if (impl_) {
77     impl_->SignalReadableState.connect(
78         this, &TransportChannelProxy::OnReadableState);
79     impl_->SignalWritableState.connect(
80         this, &TransportChannelProxy::OnWritableState);
81     impl_->SignalReadPacket.connect(
82         this, &TransportChannelProxy::OnReadPacket);
83     impl_->SignalReadyToSend.connect(
84         this, &TransportChannelProxy::OnReadyToSend);
85     impl_->SignalRouteChange.connect(
86         this, &TransportChannelProxy::OnRouteChange);
87     for (OptionList::iterator it = pending_options_.begin();
88          it != pending_options_.end();
89          ++it) {
90       impl_->SetOption(it->first, it->second);
91     }
92
93     // Push down the SRTP ciphers, if any were set.
94     if (!pending_srtp_ciphers_.empty()) {
95       impl_->SetSrtpCiphers(pending_srtp_ciphers_);
96     }
97     pending_options_.clear();
98   }
99
100   // Post ourselves a message to see if we need to fire state callbacks.
101   worker_thread_->Post(this, MSG_UPDATESTATE);
102 }
103
104 int TransportChannelProxy::SendPacket(const char* data, size_t len,
105                                       const talk_base::PacketOptions& options,
106                                       int flags) {
107   ASSERT(talk_base::Thread::Current() == worker_thread_);
108   // Fail if we don't have an impl yet.
109   if (!impl_) {
110     return -1;
111   }
112   return impl_->SendPacket(data, len, options, flags);
113 }
114
115 int TransportChannelProxy::SetOption(talk_base::Socket::Option opt, int value) {
116   ASSERT(talk_base::Thread::Current() == worker_thread_);
117   if (!impl_) {
118     pending_options_.push_back(OptionPair(opt, value));
119     return 0;
120   }
121   return impl_->SetOption(opt, value);
122 }
123
124 int TransportChannelProxy::GetError() {
125   ASSERT(talk_base::Thread::Current() == worker_thread_);
126   if (!impl_) {
127     return 0;
128   }
129   return impl_->GetError();
130 }
131
132 bool TransportChannelProxy::GetStats(ConnectionInfos* infos) {
133   ASSERT(talk_base::Thread::Current() == worker_thread_);
134   if (!impl_) {
135     return false;
136   }
137   return impl_->GetStats(infos);
138 }
139
140 bool TransportChannelProxy::IsDtlsActive() const {
141   ASSERT(talk_base::Thread::Current() == worker_thread_);
142   if (!impl_) {
143     return false;
144   }
145   return impl_->IsDtlsActive();
146 }
147
148 bool TransportChannelProxy::GetSslRole(talk_base::SSLRole* role) const {
149   ASSERT(talk_base::Thread::Current() == worker_thread_);
150   if (!impl_) {
151     return false;
152   }
153   return impl_->GetSslRole(role);
154 }
155
156 bool TransportChannelProxy::SetSslRole(talk_base::SSLRole role) {
157   ASSERT(talk_base::Thread::Current() == worker_thread_);
158   if (!impl_) {
159     return false;
160   }
161   return impl_->SetSslRole(role);
162 }
163
164 bool TransportChannelProxy::SetSrtpCiphers(const std::vector<std::string>&
165                                            ciphers) {
166   ASSERT(talk_base::Thread::Current() == worker_thread_);
167   pending_srtp_ciphers_ = ciphers;  // Cache so we can send later, but always
168                                     // set so it stays consistent.
169   if (impl_) {
170     return impl_->SetSrtpCiphers(ciphers);
171   }
172   return true;
173 }
174
175 bool TransportChannelProxy::GetSrtpCipher(std::string* cipher) {
176   ASSERT(talk_base::Thread::Current() == worker_thread_);
177   if (!impl_) {
178     return false;
179   }
180   return impl_->GetSrtpCipher(cipher);
181 }
182
183 bool TransportChannelProxy::GetLocalIdentity(
184     talk_base::SSLIdentity** identity) const {
185   ASSERT(talk_base::Thread::Current() == worker_thread_);
186   if (!impl_) {
187     return false;
188   }
189   return impl_->GetLocalIdentity(identity);
190 }
191
192 bool TransportChannelProxy::GetRemoteCertificate(
193     talk_base::SSLCertificate** cert) const {
194   ASSERT(talk_base::Thread::Current() == worker_thread_);
195   if (!impl_) {
196     return false;
197   }
198   return impl_->GetRemoteCertificate(cert);
199 }
200
201 bool TransportChannelProxy::ExportKeyingMaterial(const std::string& label,
202                                                  const uint8* context,
203                                                  size_t context_len,
204                                                  bool use_context,
205                                                  uint8* result,
206                                                  size_t result_len) {
207   ASSERT(talk_base::Thread::Current() == worker_thread_);
208   if (!impl_) {
209     return false;
210   }
211   return impl_->ExportKeyingMaterial(label, context, context_len, use_context,
212                                      result, result_len);
213 }
214
215 IceRole TransportChannelProxy::GetIceRole() const {
216   ASSERT(talk_base::Thread::Current() == worker_thread_);
217   if (!impl_) {
218     return ICEROLE_UNKNOWN;
219   }
220   return impl_->GetIceRole();
221 }
222
223 void TransportChannelProxy::OnReadableState(TransportChannel* channel) {
224   ASSERT(talk_base::Thread::Current() == worker_thread_);
225   ASSERT(channel == impl_);
226   set_readable(impl_->readable());
227   // Note: SignalReadableState fired by set_readable.
228 }
229
230 void TransportChannelProxy::OnWritableState(TransportChannel* channel) {
231   ASSERT(talk_base::Thread::Current() == worker_thread_);
232   ASSERT(channel == impl_);
233   set_writable(impl_->writable());
234   // Note: SignalWritableState fired by set_readable.
235 }
236
237 void TransportChannelProxy::OnReadPacket(
238     TransportChannel* channel, const char* data, size_t size,
239     const talk_base::PacketTime& packet_time, int flags) {
240   ASSERT(talk_base::Thread::Current() == worker_thread_);
241   ASSERT(channel == impl_);
242   SignalReadPacket(this, data, size, packet_time, flags);
243 }
244
245 void TransportChannelProxy::OnReadyToSend(TransportChannel* channel) {
246   ASSERT(talk_base::Thread::Current() == worker_thread_);
247   ASSERT(channel == impl_);
248   SignalReadyToSend(this);
249 }
250
251 void TransportChannelProxy::OnRouteChange(TransportChannel* channel,
252                                           const Candidate& candidate) {
253   ASSERT(talk_base::Thread::Current() == worker_thread_);
254   ASSERT(channel == impl_);
255   SignalRouteChange(this, candidate);
256 }
257
258 void TransportChannelProxy::OnMessage(talk_base::Message* msg) {
259   ASSERT(talk_base::Thread::Current() == worker_thread_);
260   if (msg->message_id == MSG_UPDATESTATE) {
261      // If impl_ is already readable or writable, push up those signals.
262      set_readable(impl_ ? impl_->readable() : false);
263      set_writable(impl_ ? impl_->writable() : false);
264   }
265 }
266
267 }  // namespace cricket