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