michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: // Original authors: jib@mozilla.com, ekr@rtfm.com michael@0: michael@0: // Some of this code is cut-and-pasted from nICEr. Copyright is: michael@0: michael@0: /* michael@0: Copyright (c) 2007, Adobe Systems, Incorporated michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: michael@0: * Neither the name of Adobe Systems, Network Resonance nor the names of its michael@0: contributors may be used to endorse or promote products derived from michael@0: this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: #include "logging.h" michael@0: #include "nspr.h" michael@0: #include "prnetdb.h" michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: extern "C" { michael@0: #include "nr_api.h" michael@0: #include "async_timer.h" michael@0: #include "nr_resolver.h" michael@0: #include "transport_addr.h" michael@0: } michael@0: michael@0: #include "mozilla/net/DNS.h" // TODO(jib@mozilla.com) down here because bug 848578 michael@0: #include "nsThreadUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsIDNSService.h" michael@0: #include "nsIDNSListener.h" michael@0: #include "nsIDNSRecord.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nriceresolver.h" michael@0: #include "nr_socket_prsock.h" michael@0: #include "mtransport/runnable_utils.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: MOZ_MTLOG_MODULE("mtransport") michael@0: michael@0: NrIceResolver::NrIceResolver() : michael@0: vtbl_(new nr_resolver_vtbl()) michael@0: #ifdef DEBUG michael@0: , allocated_resolvers_(0) michael@0: #endif michael@0: { michael@0: vtbl_->destroy = &NrIceResolver::destroy; michael@0: vtbl_->resolve = &NrIceResolver::resolve; michael@0: vtbl_->cancel = &NrIceResolver::cancel; michael@0: } michael@0: michael@0: NrIceResolver::~NrIceResolver() { michael@0: MOZ_ASSERT(!allocated_resolvers_); michael@0: delete vtbl_; michael@0: } michael@0: michael@0: nsresult NrIceResolver::Init() { michael@0: nsresult rv; michael@0: michael@0: sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); michael@0: MOZ_ASSERT(NS_SUCCEEDED(rv)); michael@0: dns_ = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: MOZ_MTLOG(ML_ERROR, "Could not acquire DNS service"); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nr_resolver *NrIceResolver::AllocateResolver() { michael@0: nr_resolver *resolver; michael@0: michael@0: int r = nr_resolver_create_int((void *)this, vtbl_, &resolver); michael@0: MOZ_ASSERT(!r); michael@0: if(r) { michael@0: MOZ_MTLOG(ML_ERROR, "nr_resolver_create_int failed"); michael@0: return nullptr; michael@0: } michael@0: // We must be available to allocators until they all call DestroyResolver, michael@0: // because allocators may (and do) outlive the originator of NrIceResolver. michael@0: AddRef(); michael@0: #ifdef DEBUG michael@0: ++allocated_resolvers_; michael@0: #endif michael@0: return resolver; michael@0: } michael@0: michael@0: void NrIceResolver::DestroyResolver() { michael@0: #ifdef DEBUG michael@0: --allocated_resolvers_; michael@0: #endif michael@0: // Undoes Addref in AllocateResolver so the NrIceResolver can be freed. michael@0: Release(); michael@0: } michael@0: michael@0: int NrIceResolver::destroy(void **objp) { michael@0: if (!objp || !*objp) michael@0: return 0; michael@0: NrIceResolver *resolver = static_cast(*objp); michael@0: *objp = 0; michael@0: resolver->DestroyResolver(); michael@0: return 0; michael@0: } michael@0: michael@0: int NrIceResolver::resolve(void *obj, michael@0: nr_resolver_resource *resource, michael@0: int (*cb)(void *cb_arg, nr_transport_addr *addr), michael@0: void *cb_arg, michael@0: void **handle) { michael@0: MOZ_ASSERT(obj); michael@0: return static_cast(obj)->resolve(resource, cb, cb_arg, handle); michael@0: } michael@0: michael@0: int NrIceResolver::resolve(nr_resolver_resource *resource, michael@0: int (*cb)(void *cb_arg, nr_transport_addr *addr), michael@0: void *cb_arg, michael@0: void **handle) { michael@0: int _status; michael@0: MOZ_ASSERT(allocated_resolvers_ > 0); michael@0: ASSERT_ON_THREAD(sts_thread_); michael@0: nsRefPtr pr; michael@0: michael@0: if (resource->transport_protocol != IPPROTO_UDP && michael@0: resource->transport_protocol != IPPROTO_TCP) { michael@0: MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported."); michael@0: ABORT(R_NOT_FOUND); michael@0: } michael@0: pr = new PendingResolution(sts_thread_, michael@0: resource->port? resource->port : 3478, michael@0: resource->transport_protocol ? michael@0: resource->transport_protocol : michael@0: IPPROTO_UDP, michael@0: cb, cb_arg); michael@0: if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name), michael@0: nsIDNSService::RESOLVE_DISABLE_IPV6, pr, michael@0: sts_thread_, getter_AddRefs(pr->request_)))) { michael@0: MOZ_MTLOG(ML_ERROR, "AsyncResolve failed."); michael@0: ABORT(R_NOT_FOUND); michael@0: } michael@0: // Because the C API offers no "finished" method to release the handle we michael@0: // return, we cannot return the request we got from AsyncResolve directly. michael@0: // michael@0: // Instead, we return an addref'ed reference to PendingResolution itself, michael@0: // which in turn holds the request and coordinates between cancel and michael@0: // OnLookupComplete to release it only once. michael@0: pr.forget(handle); michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: nsresult NrIceResolver::PendingResolution::OnLookupComplete( michael@0: nsICancelable *request, nsIDNSRecord *record, nsresult status) { michael@0: ASSERT_ON_THREAD(thread_); michael@0: // First check if we've been canceled. This is single-threaded on the STS michael@0: // thread, but cancel() cannot guarantee this event isn't on the queue. michael@0: if (!canceled_) { michael@0: nr_transport_addr *cb_addr = nullptr; michael@0: nr_transport_addr ta; michael@0: // TODO(jib@mozilla.com): Revisit when we do TURN. michael@0: if (NS_SUCCEEDED(status)) { michael@0: net::NetAddr na; michael@0: if (NS_SUCCEEDED(record->GetNextAddr(port_, &na))) { michael@0: MOZ_ALWAYS_TRUE (nr_netaddr_to_transport_addr(&na, &ta, michael@0: transport_) == 0); michael@0: cb_addr = &ta; michael@0: } michael@0: } michael@0: cb_(cb_arg_, cb_addr); michael@0: Release(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: int NrIceResolver::cancel(void *obj, void *handle) { michael@0: MOZ_ALWAYS_TRUE(obj); michael@0: MOZ_ASSERT(handle); michael@0: ASSERT_ON_THREAD(static_cast(obj)->sts_thread_); michael@0: return static_cast(handle)->cancel(); michael@0: } michael@0: michael@0: int NrIceResolver::PendingResolution::cancel() { michael@0: request_->Cancel (NS_ERROR_ABORT); michael@0: canceled_ = true; // in case OnLookupComplete is already on event queue. michael@0: Release(); michael@0: return 0; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(NrIceResolver::PendingResolution, nsIDNSListener); michael@0: } // End of namespace mozilla