1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/nriceresolver.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,222 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 + 1.11 +// Original authors: jib@mozilla.com, ekr@rtfm.com 1.12 + 1.13 +// Some of this code is cut-and-pasted from nICEr. Copyright is: 1.14 + 1.15 +/* 1.16 +Copyright (c) 2007, Adobe Systems, Incorporated 1.17 +All rights reserved. 1.18 + 1.19 +Redistribution and use in source and binary forms, with or without 1.20 +modification, are permitted provided that the following conditions are 1.21 +met: 1.22 + 1.23 +* Redistributions of source code must retain the above copyright 1.24 + notice, this list of conditions and the following disclaimer. 1.25 + 1.26 +* Redistributions in binary form must reproduce the above copyright 1.27 + notice, this list of conditions and the following disclaimer in the 1.28 + documentation and/or other materials provided with the distribution. 1.29 + 1.30 +* Neither the name of Adobe Systems, Network Resonance nor the names of its 1.31 + contributors may be used to endorse or promote products derived from 1.32 + this software without specific prior written permission. 1.33 + 1.34 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.35 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.36 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.37 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.38 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.39 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.40 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.41 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.42 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.43 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.44 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.45 +*/ 1.46 + 1.47 +#include "logging.h" 1.48 +#include "nspr.h" 1.49 +#include "prnetdb.h" 1.50 + 1.51 +#include "mozilla/Assertions.h" 1.52 + 1.53 +extern "C" { 1.54 +#include "nr_api.h" 1.55 +#include "async_timer.h" 1.56 +#include "nr_resolver.h" 1.57 +#include "transport_addr.h" 1.58 +} 1.59 + 1.60 +#include "mozilla/net/DNS.h" // TODO(jib@mozilla.com) down here because bug 848578 1.61 +#include "nsThreadUtils.h" 1.62 +#include "nsServiceManagerUtils.h" 1.63 +#include "nsIDNSService.h" 1.64 +#include "nsIDNSListener.h" 1.65 +#include "nsIDNSRecord.h" 1.66 +#include "nsNetCID.h" 1.67 +#include "nsCOMPtr.h" 1.68 +#include "nriceresolver.h" 1.69 +#include "nr_socket_prsock.h" 1.70 +#include "mtransport/runnable_utils.h" 1.71 + 1.72 +namespace mozilla { 1.73 + 1.74 +MOZ_MTLOG_MODULE("mtransport") 1.75 + 1.76 +NrIceResolver::NrIceResolver() : 1.77 + vtbl_(new nr_resolver_vtbl()) 1.78 +#ifdef DEBUG 1.79 + , allocated_resolvers_(0) 1.80 +#endif 1.81 +{ 1.82 + vtbl_->destroy = &NrIceResolver::destroy; 1.83 + vtbl_->resolve = &NrIceResolver::resolve; 1.84 + vtbl_->cancel = &NrIceResolver::cancel; 1.85 +} 1.86 + 1.87 +NrIceResolver::~NrIceResolver() { 1.88 + MOZ_ASSERT(!allocated_resolvers_); 1.89 + delete vtbl_; 1.90 +} 1.91 + 1.92 +nsresult NrIceResolver::Init() { 1.93 + nsresult rv; 1.94 + 1.95 + sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.96 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.97 + dns_ = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); 1.98 + if (NS_FAILED(rv)) { 1.99 + MOZ_MTLOG(ML_ERROR, "Could not acquire DNS service"); 1.100 + } 1.101 + return rv; 1.102 +} 1.103 + 1.104 +nr_resolver *NrIceResolver::AllocateResolver() { 1.105 + nr_resolver *resolver; 1.106 + 1.107 + int r = nr_resolver_create_int((void *)this, vtbl_, &resolver); 1.108 + MOZ_ASSERT(!r); 1.109 + if(r) { 1.110 + MOZ_MTLOG(ML_ERROR, "nr_resolver_create_int failed"); 1.111 + return nullptr; 1.112 + } 1.113 + // We must be available to allocators until they all call DestroyResolver, 1.114 + // because allocators may (and do) outlive the originator of NrIceResolver. 1.115 + AddRef(); 1.116 +#ifdef DEBUG 1.117 + ++allocated_resolvers_; 1.118 +#endif 1.119 + return resolver; 1.120 +} 1.121 + 1.122 +void NrIceResolver::DestroyResolver() { 1.123 +#ifdef DEBUG 1.124 + --allocated_resolvers_; 1.125 +#endif 1.126 + // Undoes Addref in AllocateResolver so the NrIceResolver can be freed. 1.127 + Release(); 1.128 +} 1.129 + 1.130 +int NrIceResolver::destroy(void **objp) { 1.131 + if (!objp || !*objp) 1.132 + return 0; 1.133 + NrIceResolver *resolver = static_cast<NrIceResolver *>(*objp); 1.134 + *objp = 0; 1.135 + resolver->DestroyResolver(); 1.136 + return 0; 1.137 +} 1.138 + 1.139 +int NrIceResolver::resolve(void *obj, 1.140 + nr_resolver_resource *resource, 1.141 + int (*cb)(void *cb_arg, nr_transport_addr *addr), 1.142 + void *cb_arg, 1.143 + void **handle) { 1.144 + MOZ_ASSERT(obj); 1.145 + return static_cast<NrIceResolver *>(obj)->resolve(resource, cb, cb_arg, handle); 1.146 +} 1.147 + 1.148 +int NrIceResolver::resolve(nr_resolver_resource *resource, 1.149 + int (*cb)(void *cb_arg, nr_transport_addr *addr), 1.150 + void *cb_arg, 1.151 + void **handle) { 1.152 + int _status; 1.153 + MOZ_ASSERT(allocated_resolvers_ > 0); 1.154 + ASSERT_ON_THREAD(sts_thread_); 1.155 + nsRefPtr<PendingResolution> pr; 1.156 + 1.157 + if (resource->transport_protocol != IPPROTO_UDP && 1.158 + resource->transport_protocol != IPPROTO_TCP) { 1.159 + MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported."); 1.160 + ABORT(R_NOT_FOUND); 1.161 + } 1.162 + pr = new PendingResolution(sts_thread_, 1.163 + resource->port? resource->port : 3478, 1.164 + resource->transport_protocol ? 1.165 + resource->transport_protocol : 1.166 + IPPROTO_UDP, 1.167 + cb, cb_arg); 1.168 + if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name), 1.169 + nsIDNSService::RESOLVE_DISABLE_IPV6, pr, 1.170 + sts_thread_, getter_AddRefs(pr->request_)))) { 1.171 + MOZ_MTLOG(ML_ERROR, "AsyncResolve failed."); 1.172 + ABORT(R_NOT_FOUND); 1.173 + } 1.174 + // Because the C API offers no "finished" method to release the handle we 1.175 + // return, we cannot return the request we got from AsyncResolve directly. 1.176 + // 1.177 + // Instead, we return an addref'ed reference to PendingResolution itself, 1.178 + // which in turn holds the request and coordinates between cancel and 1.179 + // OnLookupComplete to release it only once. 1.180 + pr.forget(handle); 1.181 + 1.182 + _status=0; 1.183 +abort: 1.184 + return _status; 1.185 +} 1.186 + 1.187 +nsresult NrIceResolver::PendingResolution::OnLookupComplete( 1.188 + nsICancelable *request, nsIDNSRecord *record, nsresult status) { 1.189 + ASSERT_ON_THREAD(thread_); 1.190 + // First check if we've been canceled. This is single-threaded on the STS 1.191 + // thread, but cancel() cannot guarantee this event isn't on the queue. 1.192 + if (!canceled_) { 1.193 + nr_transport_addr *cb_addr = nullptr; 1.194 + nr_transport_addr ta; 1.195 + // TODO(jib@mozilla.com): Revisit when we do TURN. 1.196 + if (NS_SUCCEEDED(status)) { 1.197 + net::NetAddr na; 1.198 + if (NS_SUCCEEDED(record->GetNextAddr(port_, &na))) { 1.199 + MOZ_ALWAYS_TRUE (nr_netaddr_to_transport_addr(&na, &ta, 1.200 + transport_) == 0); 1.201 + cb_addr = &ta; 1.202 + } 1.203 + } 1.204 + cb_(cb_arg_, cb_addr); 1.205 + Release(); 1.206 + } 1.207 + return NS_OK; 1.208 +} 1.209 + 1.210 +int NrIceResolver::cancel(void *obj, void *handle) { 1.211 + MOZ_ALWAYS_TRUE(obj); 1.212 + MOZ_ASSERT(handle); 1.213 + ASSERT_ON_THREAD(static_cast<NrIceResolver *>(obj)->sts_thread_); 1.214 + return static_cast<PendingResolution *>(handle)->cancel(); 1.215 +} 1.216 + 1.217 +int NrIceResolver::PendingResolution::cancel() { 1.218 + request_->Cancel (NS_ERROR_ABORT); 1.219 + canceled_ = true; // in case OnLookupComplete is already on event queue. 1.220 + Release(); 1.221 + return 0; 1.222 +} 1.223 + 1.224 +NS_IMPL_ISUPPORTS(NrIceResolver::PendingResolution, nsIDNSListener); 1.225 +} // End of namespace mozilla