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/transport.h" 29#include "talk/p2p/base/transportchannelimpl.h" 30#include "talk/p2p/base/transportchannelproxy.h" 31#include "webrtc/base/common.h" 32#include "webrtc/base/logging.h" 33#include "webrtc/base/thread.h" 34 35namespace cricket { 36 37enum { 38 MSG_UPDATESTATE, 39}; 40 41TransportChannelProxy::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_ = rtc::Thread::Current(); 48} 49 50TransportChannelProxy::~TransportChannelProxy() { 51 // Clearing any pending signal. 52 worker_thread_->Clear(this); 53 if (impl_) 54 impl_->GetTransport()->DestroyChannel(impl_->component()); 55} 56 57void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) { 58 ASSERT(rtc::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 103int TransportChannelProxy::SendPacket(const char* data, size_t len, 104 const rtc::PacketOptions& options, 105 int flags) { 106 ASSERT(rtc::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 114int TransportChannelProxy::SetOption(rtc::Socket::Option opt, int value) { 115 ASSERT(rtc::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 123int TransportChannelProxy::GetError() { 124 ASSERT(rtc::Thread::Current() == worker_thread_); 125 if (!impl_) { 126 return 0; 127 } 128 return impl_->GetError(); 129} 130 131bool TransportChannelProxy::GetStats(ConnectionInfos* infos) { 132 ASSERT(rtc::Thread::Current() == worker_thread_); 133 if (!impl_) { 134 return false; 135 } 136 return impl_->GetStats(infos); 137} 138 139bool TransportChannelProxy::IsDtlsActive() const { 140 ASSERT(rtc::Thread::Current() == worker_thread_); 141 if (!impl_) { 142 return false; 143 } 144 return impl_->IsDtlsActive(); 145} 146 147bool TransportChannelProxy::GetSslRole(rtc::SSLRole* role) const { 148 ASSERT(rtc::Thread::Current() == worker_thread_); 149 if (!impl_) { 150 return false; 151 } 152 return impl_->GetSslRole(role); 153} 154 155bool TransportChannelProxy::SetSslRole(rtc::SSLRole role) { 156 ASSERT(rtc::Thread::Current() == worker_thread_); 157 if (!impl_) { 158 return false; 159 } 160 return impl_->SetSslRole(role); 161} 162 163bool TransportChannelProxy::SetSrtpCiphers(const std::vector<std::string>& 164 ciphers) { 165 ASSERT(rtc::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 174bool TransportChannelProxy::GetSrtpCipher(std::string* cipher) { 175 ASSERT(rtc::Thread::Current() == worker_thread_); 176 if (!impl_) { 177 return false; 178 } 179 return impl_->GetSrtpCipher(cipher); 180} 181 182bool TransportChannelProxy::GetLocalIdentity( 183 rtc::SSLIdentity** identity) const { 184 ASSERT(rtc::Thread::Current() == worker_thread_); 185 if (!impl_) { 186 return false; 187 } 188 return impl_->GetLocalIdentity(identity); 189} 190 191bool TransportChannelProxy::GetRemoteCertificate( 192 rtc::SSLCertificate** cert) const { 193 ASSERT(rtc::Thread::Current() == worker_thread_); 194 if (!impl_) { 195 return false; 196 } 197 return impl_->GetRemoteCertificate(cert); 198} 199 200bool 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(rtc::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 214IceRole TransportChannelProxy::GetIceRole() const { 215 ASSERT(rtc::Thread::Current() == worker_thread_); 216 if (!impl_) { 217 return ICEROLE_UNKNOWN; 218 } 219 return impl_->GetIceRole(); 220} 221 222void TransportChannelProxy::OnReadableState(TransportChannel* channel) { 223 ASSERT(rtc::Thread::Current() == worker_thread_); 224 ASSERT(channel == impl_); 225 set_readable(impl_->readable()); 226 // Note: SignalReadableState fired by set_readable. 227} 228 229void TransportChannelProxy::OnWritableState(TransportChannel* channel) { 230 ASSERT(rtc::Thread::Current() == worker_thread_); 231 ASSERT(channel == impl_); 232 set_writable(impl_->writable()); 233 // Note: SignalWritableState fired by set_readable. 234} 235 236void TransportChannelProxy::OnReadPacket( 237 TransportChannel* channel, const char* data, size_t size, 238 const rtc::PacketTime& packet_time, int flags) { 239 ASSERT(rtc::Thread::Current() == worker_thread_); 240 ASSERT(channel == impl_); 241 SignalReadPacket(this, data, size, packet_time, flags); 242} 243 244void TransportChannelProxy::OnReadyToSend(TransportChannel* channel) { 245 ASSERT(rtc::Thread::Current() == worker_thread_); 246 ASSERT(channel == impl_); 247 SignalReadyToSend(this); 248} 249 250void TransportChannelProxy::OnRouteChange(TransportChannel* channel, 251 const Candidate& candidate) { 252 ASSERT(rtc::Thread::Current() == worker_thread_); 253 ASSERT(channel == impl_); 254 SignalRouteChange(this, candidate); 255} 256 257void TransportChannelProxy::OnMessage(rtc::Message* msg) { 258 ASSERT(rtc::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