|
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/. */ |
|
6 |
|
7 #include "mozilla/net/DNSRequestChild.h" |
|
8 #include "mozilla/net/NeckoChild.h" |
|
9 #include "nsIDNSRecord.h" |
|
10 #include "nsHostResolver.h" |
|
11 #include "nsTArray.h" |
|
12 #include "nsNetAddr.h" |
|
13 #include "nsIThread.h" |
|
14 #include "nsThreadUtils.h" |
|
15 |
|
16 using namespace mozilla::ipc; |
|
17 |
|
18 namespace mozilla { |
|
19 namespace net { |
|
20 |
|
21 //----------------------------------------------------------------------------- |
|
22 // ChildDNSRecord: |
|
23 // A simple class to provide nsIDNSRecord on the child |
|
24 //----------------------------------------------------------------------------- |
|
25 |
|
26 class ChildDNSRecord : public nsIDNSRecord |
|
27 { |
|
28 public: |
|
29 NS_DECL_THREADSAFE_ISUPPORTS |
|
30 NS_DECL_NSIDNSRECORD |
|
31 |
|
32 ChildDNSRecord(const DNSRecord& reply, uint16_t flags); |
|
33 virtual ~ChildDNSRecord(); |
|
34 |
|
35 private: |
|
36 nsCString mCanonicalName; |
|
37 nsTArray<NetAddr> mAddresses; |
|
38 uint32_t mCurrent; // addr iterator |
|
39 uint32_t mLength; // number of addrs |
|
40 uint16_t mFlags; |
|
41 }; |
|
42 |
|
43 NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord) |
|
44 |
|
45 ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply, uint16_t flags) |
|
46 : mCurrent(0) |
|
47 , mFlags(flags) |
|
48 { |
|
49 mCanonicalName = reply.canonicalName(); |
|
50 |
|
51 // A shame IPDL gives us no way to grab ownership of array: so copy it. |
|
52 const nsTArray<NetAddr>& addrs = reply.addrs(); |
|
53 uint32_t i = 0; |
|
54 mLength = addrs.Length(); |
|
55 for (; i < mLength; i++) { |
|
56 mAddresses.AppendElement(addrs[i]); |
|
57 } |
|
58 } |
|
59 |
|
60 ChildDNSRecord::~ChildDNSRecord() |
|
61 { |
|
62 } |
|
63 |
|
64 //----------------------------------------------------------------------------- |
|
65 // ChildDNSRecord::nsIDNSRecord |
|
66 //----------------------------------------------------------------------------- |
|
67 |
|
68 NS_IMETHODIMP |
|
69 ChildDNSRecord::GetCanonicalName(nsACString &result) |
|
70 { |
|
71 if (!(mFlags & nsHostResolver::RES_CANON_NAME)) { |
|
72 return NS_ERROR_NOT_AVAILABLE; |
|
73 } |
|
74 |
|
75 result = mCanonicalName; |
|
76 return NS_OK; |
|
77 } |
|
78 |
|
79 NS_IMETHODIMP |
|
80 ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) |
|
81 { |
|
82 if (mCurrent >= mLength) { |
|
83 return NS_ERROR_NOT_AVAILABLE; |
|
84 } |
|
85 |
|
86 memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr)); |
|
87 |
|
88 // both Ipv4/6 use same bits for port, so safe to just use ipv4's field |
|
89 addr->inet.port = port; |
|
90 |
|
91 return NS_OK; |
|
92 } |
|
93 |
|
94 // shamelessly copied from nsDNSRecord |
|
95 NS_IMETHODIMP |
|
96 ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result) |
|
97 { |
|
98 NetAddr addr; |
|
99 nsresult rv = GetNextAddr(port, &addr); |
|
100 if (NS_FAILED(rv)) return rv; |
|
101 |
|
102 NS_ADDREF(*result = new nsNetAddr(&addr)); |
|
103 |
|
104 return NS_OK; |
|
105 } |
|
106 |
|
107 // also copied from nsDNSRecord |
|
108 NS_IMETHODIMP |
|
109 ChildDNSRecord::GetNextAddrAsString(nsACString &result) |
|
110 { |
|
111 NetAddr addr; |
|
112 nsresult rv = GetNextAddr(0, &addr); |
|
113 if (NS_FAILED(rv)) { |
|
114 return rv; |
|
115 } |
|
116 |
|
117 char buf[kIPv6CStrBufSize]; |
|
118 if (NetAddrToString(&addr, buf, sizeof(buf))) { |
|
119 result.Assign(buf); |
|
120 return NS_OK; |
|
121 } |
|
122 NS_ERROR("NetAddrToString failed unexpectedly"); |
|
123 return NS_ERROR_FAILURE; // conversion failed for some reason |
|
124 } |
|
125 |
|
126 NS_IMETHODIMP |
|
127 ChildDNSRecord::HasMore(bool *result) |
|
128 { |
|
129 *result = mCurrent < mLength; |
|
130 return NS_OK; |
|
131 } |
|
132 |
|
133 NS_IMETHODIMP |
|
134 ChildDNSRecord::Rewind() |
|
135 { |
|
136 mCurrent = 0; |
|
137 return NS_OK; |
|
138 } |
|
139 |
|
140 NS_IMETHODIMP |
|
141 ChildDNSRecord::ReportUnusable(uint16_t aPort) |
|
142 { |
|
143 // "We thank you for your feedback" == >/dev/null |
|
144 // TODO: we could send info back to parent. |
|
145 return NS_OK; |
|
146 } |
|
147 |
|
148 //----------------------------------------------------------------------------- |
|
149 // DNSRequestChild |
|
150 //----------------------------------------------------------------------------- |
|
151 |
|
152 DNSRequestChild::DNSRequestChild(const nsCString& aHost, |
|
153 const uint32_t& aFlags, |
|
154 nsIDNSListener *aListener, |
|
155 nsIEventTarget *target) |
|
156 : mListener(aListener) |
|
157 , mTarget(target) |
|
158 , mResultStatus(NS_OK) |
|
159 , mHost(aHost) |
|
160 , mFlags(aFlags) |
|
161 { |
|
162 } |
|
163 |
|
164 void |
|
165 DNSRequestChild::StartRequest() |
|
166 { |
|
167 // we can only do IPDL on the main thread |
|
168 if (!NS_IsMainThread()) { |
|
169 NS_DispatchToMainThread( |
|
170 NS_NewRunnableMethod(this, &DNSRequestChild::StartRequest)); |
|
171 return; |
|
172 } |
|
173 |
|
174 // Send request to Parent process. |
|
175 gNeckoChild->SendPDNSRequestConstructor(this, mHost, mFlags); |
|
176 |
|
177 // IPDL holds a reference until IPDL channel gets destroyed |
|
178 AddIPDLReference(); |
|
179 } |
|
180 |
|
181 void |
|
182 DNSRequestChild::CallOnLookupComplete() |
|
183 { |
|
184 MOZ_ASSERT(mListener); |
|
185 |
|
186 mListener->OnLookupComplete(this, mResultRecord, mResultStatus); |
|
187 } |
|
188 |
|
189 bool |
|
190 DNSRequestChild::Recv__delete__(const DNSRequestResponse& reply) |
|
191 { |
|
192 MOZ_ASSERT(mListener); |
|
193 |
|
194 switch (reply.type()) { |
|
195 case DNSRequestResponse::TDNSRecord: { |
|
196 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags); |
|
197 break; |
|
198 } |
|
199 case DNSRequestResponse::Tnsresult: { |
|
200 mResultStatus = reply.get_nsresult(); |
|
201 break; |
|
202 } |
|
203 default: |
|
204 NS_NOTREACHED("unknown type"); |
|
205 return false; |
|
206 } |
|
207 |
|
208 MOZ_ASSERT(NS_IsMainThread()); |
|
209 |
|
210 bool targetIsMain = false; |
|
211 if (!mTarget) { |
|
212 targetIsMain = true; |
|
213 } else { |
|
214 mTarget->IsOnCurrentThread(&targetIsMain); |
|
215 } |
|
216 |
|
217 if (targetIsMain) { |
|
218 CallOnLookupComplete(); |
|
219 } else { |
|
220 nsCOMPtr<nsIRunnable> event = |
|
221 NS_NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete); |
|
222 mTarget->Dispatch(event, NS_DISPATCH_NORMAL); |
|
223 } |
|
224 |
|
225 return true; |
|
226 } |
|
227 |
|
228 //----------------------------------------------------------------------------- |
|
229 // DNSRequestChild::nsISupports |
|
230 //----------------------------------------------------------------------------- |
|
231 |
|
232 NS_IMPL_ISUPPORTS(DNSRequestChild, |
|
233 nsICancelable) |
|
234 |
|
235 //----------------------------------------------------------------------------- |
|
236 // DNSRequestChild::nsICancelable |
|
237 //----------------------------------------------------------------------------- |
|
238 |
|
239 NS_IMETHODIMP |
|
240 DNSRequestChild::Cancel(nsresult reason) |
|
241 { |
|
242 // for now Cancel is a no-op |
|
243 return NS_OK; |
|
244 } |
|
245 |
|
246 //------------------------------------------------------------------------------ |
|
247 }} // mozilla::net |