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 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_ = talk_base::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(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 104int TransportChannelProxy::SendPacket(const char* data, size_t len, 105 talk_base::DiffServCodePoint dscp, 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, dscp, flags); 113} 114 115int 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 124int TransportChannelProxy::GetError() { 125 ASSERT(talk_base::Thread::Current() == worker_thread_); 126 if (!impl_) { 127 return 0; 128 } 129 return impl_->GetError(); 130} 131 132bool 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 140bool TransportChannelProxy::IsDtlsActive() const { 141 ASSERT(talk_base::Thread::Current() == worker_thread_); 142 if (!impl_) { 143 return false; 144 } 145 return impl_->IsDtlsActive(); 146} 147 148bool 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 156bool 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 164bool 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 175bool 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 183bool 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 192bool 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 201bool 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 215IceRole 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 223void 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 230void 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 237void 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 245void TransportChannelProxy::OnReadyToSend(TransportChannel* channel) { 246 ASSERT(talk_base::Thread::Current() == worker_thread_); 247 ASSERT(channel == impl_); 248 SignalReadyToSend(this); 249} 250 251void 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 258void 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 268