Bumping manifests a=b2g-bump
[gecko.git] / netwerk / dns / DNSRequestChild.cpp
blobeab6cb5e4e35ee8479611e2d6685306ddb7e0f16
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/net/ChildDNSService.h"
8 #include "mozilla/net/DNSRequestChild.h"
9 #include "mozilla/net/NeckoChild.h"
10 #include "mozilla/unused.h"
11 #include "nsIDNSRecord.h"
12 #include "nsHostResolver.h"
13 #include "nsTArray.h"
14 #include "nsNetAddr.h"
15 #include "nsIThread.h"
16 #include "nsThreadUtils.h"
18 using namespace mozilla::ipc;
20 namespace mozilla {
21 namespace net {
23 //-----------------------------------------------------------------------------
24 // ChildDNSRecord:
25 // A simple class to provide nsIDNSRecord on the child
26 //-----------------------------------------------------------------------------
28 class ChildDNSRecord : public nsIDNSRecord
30 public:
31 NS_DECL_THREADSAFE_ISUPPORTS
32 NS_DECL_NSIDNSRECORD
34 ChildDNSRecord(const DNSRecord& reply, uint16_t flags);
36 private:
37 virtual ~ChildDNSRecord();
39 nsCString mCanonicalName;
40 nsTArray<NetAddr> mAddresses;
41 uint32_t mCurrent; // addr iterator
42 uint32_t mLength; // number of addrs
43 uint16_t mFlags;
46 NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord)
48 ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply, uint16_t flags)
49 : mCurrent(0)
50 , mFlags(flags)
52 mCanonicalName = reply.canonicalName();
54 // A shame IPDL gives us no way to grab ownership of array: so copy it.
55 const nsTArray<NetAddr>& addrs = reply.addrs();
56 uint32_t i = 0;
57 mLength = addrs.Length();
58 for (; i < mLength; i++) {
59 mAddresses.AppendElement(addrs[i]);
63 ChildDNSRecord::~ChildDNSRecord()
67 //-----------------------------------------------------------------------------
68 // ChildDNSRecord::nsIDNSRecord
69 //-----------------------------------------------------------------------------
71 NS_IMETHODIMP
72 ChildDNSRecord::GetCanonicalName(nsACString &result)
74 if (!(mFlags & nsHostResolver::RES_CANON_NAME)) {
75 return NS_ERROR_NOT_AVAILABLE;
78 result = mCanonicalName;
79 return NS_OK;
82 NS_IMETHODIMP
83 ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
85 if (mCurrent >= mLength) {
86 return NS_ERROR_NOT_AVAILABLE;
89 memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr));
91 // both Ipv4/6 use same bits for port, so safe to just use ipv4's field
92 addr->inet.port = htons(port);
94 return NS_OK;
97 // shamelessly copied from nsDNSRecord
98 NS_IMETHODIMP
99 ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result)
101 NetAddr addr;
102 nsresult rv = GetNextAddr(port, &addr);
103 if (NS_FAILED(rv)) return rv;
105 NS_ADDREF(*result = new nsNetAddr(&addr));
107 return NS_OK;
110 // also copied from nsDNSRecord
111 NS_IMETHODIMP
112 ChildDNSRecord::GetNextAddrAsString(nsACString &result)
114 NetAddr addr;
115 nsresult rv = GetNextAddr(0, &addr);
116 if (NS_FAILED(rv)) {
117 return rv;
120 char buf[kIPv6CStrBufSize];
121 if (NetAddrToString(&addr, buf, sizeof(buf))) {
122 result.Assign(buf);
123 return NS_OK;
125 NS_ERROR("NetAddrToString failed unexpectedly");
126 return NS_ERROR_FAILURE; // conversion failed for some reason
129 NS_IMETHODIMP
130 ChildDNSRecord::HasMore(bool *result)
132 *result = mCurrent < mLength;
133 return NS_OK;
136 NS_IMETHODIMP
137 ChildDNSRecord::Rewind()
139 mCurrent = 0;
140 return NS_OK;
143 NS_IMETHODIMP
144 ChildDNSRecord::ReportUnusable(uint16_t aPort)
146 // "We thank you for your feedback" == >/dev/null
147 // TODO: we could send info back to parent.
148 return NS_OK;
151 //-----------------------------------------------------------------------------
152 // CancelDNSRequestEvent
153 //-----------------------------------------------------------------------------
155 class CancelDNSRequestEvent : public nsRunnable
157 public:
158 CancelDNSRequestEvent(DNSRequestChild* aDnsReq, nsresult aReason)
159 : mDnsRequest(aDnsReq)
160 , mReasonForCancel(aReason)
163 NS_IMETHOD Run()
165 if (mDnsRequest->mIPCOpen) {
166 // Send request to Parent process.
167 mDnsRequest->SendCancelDNSRequest(mDnsRequest->mHost, mDnsRequest->mFlags,
168 mDnsRequest->mNetworkInterface,
169 mReasonForCancel);
171 return NS_OK;
173 private:
174 nsRefPtr<DNSRequestChild> mDnsRequest;
175 nsresult mReasonForCancel;
178 //-----------------------------------------------------------------------------
179 // DNSRequestChild
180 //-----------------------------------------------------------------------------
182 DNSRequestChild::DNSRequestChild(const nsCString& aHost,
183 const uint32_t& aFlags,
184 const nsCString& aNetworkInterface,
185 nsIDNSListener *aListener,
186 nsIEventTarget *target)
187 : mListener(aListener)
188 , mTarget(target)
189 , mResultStatus(NS_OK)
190 , mHost(aHost)
191 , mFlags(aFlags)
192 , mNetworkInterface(aNetworkInterface)
193 , mIPCOpen(false)
197 void
198 DNSRequestChild::StartRequest()
200 // we can only do IPDL on the main thread
201 if (!NS_IsMainThread()) {
202 NS_DispatchToMainThread(
203 NS_NewRunnableMethod(this, &DNSRequestChild::StartRequest));
204 return;
207 // Send request to Parent process.
208 gNeckoChild->SendPDNSRequestConstructor(this, mHost, mFlags,
209 mNetworkInterface);
210 mIPCOpen = true;
212 // IPDL holds a reference until IPDL channel gets destroyed
213 AddIPDLReference();
216 void
217 DNSRequestChild::CallOnLookupComplete()
219 MOZ_ASSERT(mListener);
220 mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
223 bool
224 DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply)
226 mIPCOpen = false;
227 MOZ_ASSERT(mListener);
229 switch (reply.type()) {
230 case DNSRequestResponse::TDNSRecord: {
231 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags);
232 break;
234 case DNSRequestResponse::Tnsresult: {
235 mResultStatus = reply.get_nsresult();
236 break;
238 default:
239 NS_NOTREACHED("unknown type");
240 return false;
243 MOZ_ASSERT(NS_IsMainThread());
245 bool targetIsMain = false;
246 if (!mTarget) {
247 targetIsMain = true;
248 } else {
249 mTarget->IsOnCurrentThread(&targetIsMain);
252 if (targetIsMain) {
253 CallOnLookupComplete();
254 } else {
255 nsCOMPtr<nsIRunnable> event =
256 NS_NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete);
257 mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
260 unused << Send__delete__(this);
262 return true;
265 void
266 DNSRequestChild::ReleaseIPDLReference()
268 // Request is done or destroyed. Remove it from the hash table.
269 nsRefPtr<ChildDNSService> dnsServiceChild =
270 dont_AddRef(ChildDNSService::GetSingleton());
271 dnsServiceChild->NotifyRequestDone(this);
273 Release();
276 void
277 DNSRequestChild::ActorDestroy(ActorDestroyReason why)
279 mIPCOpen = false;
282 //-----------------------------------------------------------------------------
283 // DNSRequestChild::nsISupports
284 //-----------------------------------------------------------------------------
286 NS_IMPL_ISUPPORTS(DNSRequestChild,
287 nsICancelable)
289 //-----------------------------------------------------------------------------
290 // DNSRequestChild::nsICancelable
291 //-----------------------------------------------------------------------------
293 NS_IMETHODIMP
294 DNSRequestChild::Cancel(nsresult reason)
296 if(mIPCOpen) {
297 // We can only do IPDL on the main thread
298 NS_DispatchToMainThread(
299 new CancelDNSRequestEvent(this, reason));
301 return NS_OK;
304 //------------------------------------------------------------------------------
305 }} // mozilla::net