michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et 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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/net/DNSRequestChild.h" michael@0: #include "mozilla/net/NeckoChild.h" michael@0: #include "nsIDNSRecord.h" michael@0: #include "nsHostResolver.h" michael@0: #include "nsTArray.h" michael@0: #include "nsNetAddr.h" michael@0: #include "nsIThread.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: using namespace mozilla::ipc; michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // ChildDNSRecord: michael@0: // A simple class to provide nsIDNSRecord on the child michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class ChildDNSRecord : public nsIDNSRecord michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIDNSRECORD michael@0: michael@0: ChildDNSRecord(const DNSRecord& reply, uint16_t flags); michael@0: virtual ~ChildDNSRecord(); michael@0: michael@0: private: michael@0: nsCString mCanonicalName; michael@0: nsTArray mAddresses; michael@0: uint32_t mCurrent; // addr iterator michael@0: uint32_t mLength; // number of addrs michael@0: uint16_t mFlags; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord) michael@0: michael@0: ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply, uint16_t flags) michael@0: : mCurrent(0) michael@0: , mFlags(flags) michael@0: { michael@0: mCanonicalName = reply.canonicalName(); michael@0: michael@0: // A shame IPDL gives us no way to grab ownership of array: so copy it. michael@0: const nsTArray& addrs = reply.addrs(); michael@0: uint32_t i = 0; michael@0: mLength = addrs.Length(); michael@0: for (; i < mLength; i++) { michael@0: mAddresses.AppendElement(addrs[i]); michael@0: } michael@0: } michael@0: michael@0: ChildDNSRecord::~ChildDNSRecord() michael@0: { michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // ChildDNSRecord::nsIDNSRecord michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::GetCanonicalName(nsACString &result) michael@0: { michael@0: if (!(mFlags & nsHostResolver::RES_CANON_NAME)) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: result = mCanonicalName; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) michael@0: { michael@0: if (mCurrent >= mLength) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr)); michael@0: michael@0: // both Ipv4/6 use same bits for port, so safe to just use ipv4's field michael@0: addr->inet.port = port; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // shamelessly copied from nsDNSRecord michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result) michael@0: { michael@0: NetAddr addr; michael@0: nsresult rv = GetNextAddr(port, &addr); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: NS_ADDREF(*result = new nsNetAddr(&addr)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // also copied from nsDNSRecord michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::GetNextAddrAsString(nsACString &result) michael@0: { michael@0: NetAddr addr; michael@0: nsresult rv = GetNextAddr(0, &addr); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: char buf[kIPv6CStrBufSize]; michael@0: if (NetAddrToString(&addr, buf, sizeof(buf))) { michael@0: result.Assign(buf); michael@0: return NS_OK; michael@0: } michael@0: NS_ERROR("NetAddrToString failed unexpectedly"); michael@0: return NS_ERROR_FAILURE; // conversion failed for some reason michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::HasMore(bool *result) michael@0: { michael@0: *result = mCurrent < mLength; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::Rewind() michael@0: { michael@0: mCurrent = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ChildDNSRecord::ReportUnusable(uint16_t aPort) michael@0: { michael@0: // "We thank you for your feedback" == >/dev/null michael@0: // TODO: we could send info back to parent. michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // DNSRequestChild michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: DNSRequestChild::DNSRequestChild(const nsCString& aHost, michael@0: const uint32_t& aFlags, michael@0: nsIDNSListener *aListener, michael@0: nsIEventTarget *target) michael@0: : mListener(aListener) michael@0: , mTarget(target) michael@0: , mResultStatus(NS_OK) michael@0: , mHost(aHost) michael@0: , mFlags(aFlags) michael@0: { michael@0: } michael@0: michael@0: void michael@0: DNSRequestChild::StartRequest() michael@0: { michael@0: // we can only do IPDL on the main thread michael@0: if (!NS_IsMainThread()) { michael@0: NS_DispatchToMainThread( michael@0: NS_NewRunnableMethod(this, &DNSRequestChild::StartRequest)); michael@0: return; michael@0: } michael@0: michael@0: // Send request to Parent process. michael@0: gNeckoChild->SendPDNSRequestConstructor(this, mHost, mFlags); michael@0: michael@0: // IPDL holds a reference until IPDL channel gets destroyed michael@0: AddIPDLReference(); michael@0: } michael@0: michael@0: void michael@0: DNSRequestChild::CallOnLookupComplete() michael@0: { michael@0: MOZ_ASSERT(mListener); michael@0: michael@0: mListener->OnLookupComplete(this, mResultRecord, mResultStatus); michael@0: } michael@0: michael@0: bool michael@0: DNSRequestChild::Recv__delete__(const DNSRequestResponse& reply) michael@0: { michael@0: MOZ_ASSERT(mListener); michael@0: michael@0: switch (reply.type()) { michael@0: case DNSRequestResponse::TDNSRecord: { michael@0: mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags); michael@0: break; michael@0: } michael@0: case DNSRequestResponse::Tnsresult: { michael@0: mResultStatus = reply.get_nsresult(); michael@0: break; michael@0: } michael@0: default: michael@0: NS_NOTREACHED("unknown type"); michael@0: return false; michael@0: } michael@0: michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: bool targetIsMain = false; michael@0: if (!mTarget) { michael@0: targetIsMain = true; michael@0: } else { michael@0: mTarget->IsOnCurrentThread(&targetIsMain); michael@0: } michael@0: michael@0: if (targetIsMain) { michael@0: CallOnLookupComplete(); michael@0: } else { michael@0: nsCOMPtr event = michael@0: NS_NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete); michael@0: mTarget->Dispatch(event, NS_DISPATCH_NORMAL); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // DNSRequestChild::nsISupports michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMPL_ISUPPORTS(DNSRequestChild, michael@0: nsICancelable) michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // DNSRequestChild::nsICancelable michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: DNSRequestChild::Cancel(nsresult reason) michael@0: { michael@0: // for now Cancel is a no-op michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------------------------------ michael@0: }} // mozilla::net