1/* 2 * libjingle 3 * Copyright 2004--2011, 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/portallocatorsessionproxy.h" 29 30#include "talk/p2p/base/portallocator.h" 31#include "talk/p2p/base/portproxy.h" 32#include "webrtc/base/thread.h" 33 34namespace cricket { 35 36enum { 37 MSG_SEND_ALLOCATION_DONE = 1, 38 MSG_SEND_ALLOCATED_PORTS, 39}; 40 41typedef rtc::TypedMessageData<PortAllocatorSessionProxy*> ProxyObjData; 42 43PortAllocatorSessionMuxer::PortAllocatorSessionMuxer( 44 PortAllocatorSession* session) 45 : worker_thread_(rtc::Thread::Current()), 46 session_(session), 47 candidate_done_signal_received_(false) { 48 session_->SignalPortReady.connect( 49 this, &PortAllocatorSessionMuxer::OnPortReady); 50 session_->SignalCandidatesAllocationDone.connect( 51 this, &PortAllocatorSessionMuxer::OnCandidatesAllocationDone); 52} 53 54PortAllocatorSessionMuxer::~PortAllocatorSessionMuxer() { 55 for (size_t i = 0; i < session_proxies_.size(); ++i) 56 delete session_proxies_[i]; 57 58 SignalDestroyed(this); 59} 60 61void PortAllocatorSessionMuxer::RegisterSessionProxy( 62 PortAllocatorSessionProxy* session_proxy) { 63 session_proxies_.push_back(session_proxy); 64 session_proxy->SignalDestroyed.connect( 65 this, &PortAllocatorSessionMuxer::OnSessionProxyDestroyed); 66 session_proxy->set_impl(session_.get()); 67 68 // Populate new proxy session with the information available in the actual 69 // implementation. 70 if (!ports_.empty()) { 71 worker_thread_->Post( 72 this, MSG_SEND_ALLOCATED_PORTS, new ProxyObjData(session_proxy)); 73 } 74 75 if (candidate_done_signal_received_) { 76 worker_thread_->Post( 77 this, MSG_SEND_ALLOCATION_DONE, new ProxyObjData(session_proxy)); 78 } 79} 80 81void PortAllocatorSessionMuxer::OnCandidatesAllocationDone( 82 PortAllocatorSession* session) { 83 candidate_done_signal_received_ = true; 84} 85 86void PortAllocatorSessionMuxer::OnPortReady(PortAllocatorSession* session, 87 PortInterface* port) { 88 ASSERT(session == session_.get()); 89 ports_.push_back(port); 90 port->SignalDestroyed.connect( 91 this, &PortAllocatorSessionMuxer::OnPortDestroyed); 92} 93 94void PortAllocatorSessionMuxer::OnPortDestroyed(PortInterface* port) { 95 std::vector<PortInterface*>::iterator it = 96 std::find(ports_.begin(), ports_.end(), port); 97 if (it != ports_.end()) 98 ports_.erase(it); 99} 100 101void PortAllocatorSessionMuxer::OnSessionProxyDestroyed( 102 PortAllocatorSession* proxy) { 103 104 std::vector<PortAllocatorSessionProxy*>::iterator it = 105 std::find(session_proxies_.begin(), session_proxies_.end(), proxy); 106 if (it != session_proxies_.end()) { 107 session_proxies_.erase(it); 108 } 109 110 if (session_proxies_.empty()) { 111 // Destroy PortAllocatorSession and its associated muxer object if all 112 // proxies belonging to this session are already destroyed. 113 delete this; 114 } 115} 116 117void PortAllocatorSessionMuxer::OnMessage(rtc::Message *pmsg) { 118 ProxyObjData* proxy = static_cast<ProxyObjData*>(pmsg->pdata); 119 switch (pmsg->message_id) { 120 case MSG_SEND_ALLOCATION_DONE: 121 SendAllocationDone_w(proxy->data()); 122 delete proxy; 123 break; 124 case MSG_SEND_ALLOCATED_PORTS: 125 SendAllocatedPorts_w(proxy->data()); 126 delete proxy; 127 break; 128 default: 129 ASSERT(false); 130 break; 131 } 132} 133 134void PortAllocatorSessionMuxer::SendAllocationDone_w( 135 PortAllocatorSessionProxy* proxy) { 136 std::vector<PortAllocatorSessionProxy*>::iterator iter = 137 std::find(session_proxies_.begin(), session_proxies_.end(), proxy); 138 if (iter != session_proxies_.end()) { 139 proxy->OnCandidatesAllocationDone(session_.get()); 140 } 141} 142 143void PortAllocatorSessionMuxer::SendAllocatedPorts_w( 144 PortAllocatorSessionProxy* proxy) { 145 std::vector<PortAllocatorSessionProxy*>::iterator iter = 146 std::find(session_proxies_.begin(), session_proxies_.end(), proxy); 147 if (iter != session_proxies_.end()) { 148 for (size_t i = 0; i < ports_.size(); ++i) { 149 PortInterface* port = ports_[i]; 150 proxy->OnPortReady(session_.get(), port); 151 // If port already has candidates, send this to the clients of proxy 152 // session. This can happen if proxy is created later than the actual 153 // implementation. 154 if (!port->Candidates().empty()) { 155 proxy->OnCandidatesReady(session_.get(), port->Candidates()); 156 } 157 } 158 } 159} 160 161PortAllocatorSessionProxy::~PortAllocatorSessionProxy() { 162 std::map<PortInterface*, PortProxy*>::iterator it; 163 for (it = proxy_ports_.begin(); it != proxy_ports_.end(); it++) 164 delete it->second; 165 166 SignalDestroyed(this); 167} 168 169void PortAllocatorSessionProxy::set_impl( 170 PortAllocatorSession* session) { 171 impl_ = session; 172 173 impl_->SignalCandidatesReady.connect( 174 this, &PortAllocatorSessionProxy::OnCandidatesReady); 175 impl_->SignalPortReady.connect( 176 this, &PortAllocatorSessionProxy::OnPortReady); 177 impl_->SignalCandidatesAllocationDone.connect( 178 this, &PortAllocatorSessionProxy::OnCandidatesAllocationDone); 179} 180 181void PortAllocatorSessionProxy::StartGettingPorts() { 182 ASSERT(impl_ != NULL); 183 // Since all proxies share a common PortAllocatorSession, this check will 184 // prohibit sending multiple STUN ping messages to the stun server, which 185 // is a problem on Chrome. GetInitialPorts() and StartGetAllPorts() called 186 // from the worker thread and are called together from TransportChannel, 187 // checking for IsGettingAllPorts() for GetInitialPorts() will not be a 188 // problem. 189 if (!impl_->IsGettingPorts()) { 190 impl_->StartGettingPorts(); 191 } 192} 193 194void PortAllocatorSessionProxy::StopGettingPorts() { 195 ASSERT(impl_ != NULL); 196 if (impl_->IsGettingPorts()) { 197 impl_->StopGettingPorts(); 198 } 199} 200 201bool PortAllocatorSessionProxy::IsGettingPorts() { 202 ASSERT(impl_ != NULL); 203 return impl_->IsGettingPorts(); 204} 205 206void PortAllocatorSessionProxy::OnPortReady(PortAllocatorSession* session, 207 PortInterface* port) { 208 ASSERT(session == impl_); 209 210 PortProxy* proxy_port = new PortProxy(); 211 proxy_port->set_impl(port); 212 proxy_ports_[port] = proxy_port; 213 SignalPortReady(this, proxy_port); 214} 215 216void PortAllocatorSessionProxy::OnCandidatesReady( 217 PortAllocatorSession* session, 218 const std::vector<Candidate>& candidates) { 219 ASSERT(session == impl_); 220 221 // Since all proxy sessions share a common PortAllocatorSession, 222 // all Candidates will have name associated with the common PAS. 223 // Change Candidate name with the PortAllocatorSessionProxy name. 224 std::vector<Candidate> our_candidates; 225 for (size_t i = 0; i < candidates.size(); ++i) { 226 Candidate new_local_candidate = candidates[i]; 227 new_local_candidate.set_component(component_); 228 our_candidates.push_back(new_local_candidate); 229 } 230 SignalCandidatesReady(this, our_candidates); 231} 232 233void PortAllocatorSessionProxy::OnCandidatesAllocationDone( 234 PortAllocatorSession* session) { 235 ASSERT(session == impl_); 236 SignalCandidatesAllocationDone(this); 237} 238 239} // namespace cricket 240