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"
14 #include "nsNetAddr.h"
15 #include "nsIThread.h"
16 #include "nsThreadUtils.h"
18 using namespace mozilla::ipc
;
23 //-----------------------------------------------------------------------------
25 // A simple class to provide nsIDNSRecord on the child
26 //-----------------------------------------------------------------------------
28 class ChildDNSRecord
: public nsIDNSRecord
31 NS_DECL_THREADSAFE_ISUPPORTS
34 ChildDNSRecord(const DNSRecord
& reply
, uint16_t flags
);
37 virtual ~ChildDNSRecord();
39 nsCString mCanonicalName
;
40 nsTArray
<NetAddr
> mAddresses
;
41 uint32_t mCurrent
; // addr iterator
42 uint32_t mLength
; // number of addrs
46 NS_IMPL_ISUPPORTS(ChildDNSRecord
, nsIDNSRecord
)
48 ChildDNSRecord::ChildDNSRecord(const DNSRecord
& reply
, uint16_t 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();
57 mLength
= addrs
.Length();
58 for (; i
< mLength
; i
++) {
59 mAddresses
.AppendElement(addrs
[i
]);
63 ChildDNSRecord::~ChildDNSRecord()
67 //-----------------------------------------------------------------------------
68 // ChildDNSRecord::nsIDNSRecord
69 //-----------------------------------------------------------------------------
72 ChildDNSRecord::GetCanonicalName(nsACString
&result
)
74 if (!(mFlags
& nsHostResolver::RES_CANON_NAME
)) {
75 return NS_ERROR_NOT_AVAILABLE
;
78 result
= mCanonicalName
;
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
);
97 // shamelessly copied from nsDNSRecord
99 ChildDNSRecord::GetScriptableNextAddr(uint16_t port
, nsINetAddr
**result
)
102 nsresult rv
= GetNextAddr(port
, &addr
);
103 if (NS_FAILED(rv
)) return rv
;
105 NS_ADDREF(*result
= new nsNetAddr(&addr
));
110 // also copied from nsDNSRecord
112 ChildDNSRecord::GetNextAddrAsString(nsACString
&result
)
115 nsresult rv
= GetNextAddr(0, &addr
);
120 char buf
[kIPv6CStrBufSize
];
121 if (NetAddrToString(&addr
, buf
, sizeof(buf
))) {
125 NS_ERROR("NetAddrToString failed unexpectedly");
126 return NS_ERROR_FAILURE
; // conversion failed for some reason
130 ChildDNSRecord::HasMore(bool *result
)
132 *result
= mCurrent
< mLength
;
137 ChildDNSRecord::Rewind()
144 ChildDNSRecord::ReportUnusable(uint16_t aPort
)
146 // "We thank you for your feedback" == >/dev/null
147 // TODO: we could send info back to parent.
151 //-----------------------------------------------------------------------------
152 // CancelDNSRequestEvent
153 //-----------------------------------------------------------------------------
155 class CancelDNSRequestEvent
: public nsRunnable
158 CancelDNSRequestEvent(DNSRequestChild
* aDnsReq
, nsresult aReason
)
159 : mDnsRequest(aDnsReq
)
160 , mReasonForCancel(aReason
)
165 if (mDnsRequest
->mIPCOpen
) {
166 // Send request to Parent process.
167 mDnsRequest
->SendCancelDNSRequest(mDnsRequest
->mHost
, mDnsRequest
->mFlags
,
168 mDnsRequest
->mNetworkInterface
,
174 nsRefPtr
<DNSRequestChild
> mDnsRequest
;
175 nsresult mReasonForCancel
;
178 //-----------------------------------------------------------------------------
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
)
189 , mResultStatus(NS_OK
)
192 , mNetworkInterface(aNetworkInterface
)
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
));
207 // Send request to Parent process.
208 gNeckoChild
->SendPDNSRequestConstructor(this, mHost
, mFlags
,
212 // IPDL holds a reference until IPDL channel gets destroyed
217 DNSRequestChild::CallOnLookupComplete()
219 MOZ_ASSERT(mListener
);
220 mListener
->OnLookupComplete(this, mResultRecord
, mResultStatus
);
224 DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse
& reply
)
227 MOZ_ASSERT(mListener
);
229 switch (reply
.type()) {
230 case DNSRequestResponse::TDNSRecord
: {
231 mResultRecord
= new ChildDNSRecord(reply
.get_DNSRecord(), mFlags
);
234 case DNSRequestResponse::Tnsresult
: {
235 mResultStatus
= reply
.get_nsresult();
239 NS_NOTREACHED("unknown type");
243 MOZ_ASSERT(NS_IsMainThread());
245 bool targetIsMain
= false;
249 mTarget
->IsOnCurrentThread(&targetIsMain
);
253 CallOnLookupComplete();
255 nsCOMPtr
<nsIRunnable
> event
=
256 NS_NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete
);
257 mTarget
->Dispatch(event
, NS_DISPATCH_NORMAL
);
260 unused
<< Send__delete__(this);
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);
277 DNSRequestChild::ActorDestroy(ActorDestroyReason why
)
282 //-----------------------------------------------------------------------------
283 // DNSRequestChild::nsISupports
284 //-----------------------------------------------------------------------------
286 NS_IMPL_ISUPPORTS(DNSRequestChild
,
289 //-----------------------------------------------------------------------------
290 // DNSRequestChild::nsICancelable
291 //-----------------------------------------------------------------------------
294 DNSRequestChild::Cancel(nsresult reason
)
297 // We can only do IPDL on the main thread
298 NS_DispatchToMainThread(
299 new CancelDNSRequestEvent(this, reason
));
304 //------------------------------------------------------------------------------