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