Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/dns/DNSRequestChild.cpp
Line
Count
Source (jump to first uncovered line)
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/dom/ContentChild.h"
8
#include "mozilla/net/ChildDNSService.h"
9
#include "mozilla/net/DNSRequestChild.h"
10
#include "mozilla/net/NeckoChild.h"
11
#include "mozilla/SystemGroup.h"
12
#include "mozilla/Unused.h"
13
#include "nsIDNSRecord.h"
14
#include "nsIDNSByTypeRecord.h"
15
#include "nsHostResolver.h"
16
#include "nsTArray.h"
17
#include "nsNetAddr.h"
18
#include "nsIThread.h"
19
#include "nsThreadUtils.h"
20
21
using namespace mozilla::ipc;
22
23
namespace mozilla {
24
namespace net {
25
26
//-----------------------------------------------------------------------------
27
// ChildDNSRecord:
28
// A simple class to provide nsIDNSRecord on the child
29
//-----------------------------------------------------------------------------
30
31
class ChildDNSRecord : public nsIDNSRecord
32
{
33
public:
34
  NS_DECL_THREADSAFE_ISUPPORTS
35
  NS_DECL_NSIDNSRECORD
36
37
  ChildDNSRecord(const DNSRecord& reply, uint16_t flags);
38
39
private:
40
0
  virtual ~ChildDNSRecord() = default;
41
42
  nsCString mCanonicalName;
43
  nsTArray<NetAddr> mAddresses;
44
  uint32_t mCurrent; // addr iterator
45
  uint32_t mLength;  // number of addrs
46
  uint16_t mFlags;
47
};
48
49
NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord)
50
51
ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply, uint16_t flags)
52
  : mCurrent(0)
53
  , mFlags(flags)
54
0
{
55
0
  mCanonicalName = reply.canonicalName();
56
0
57
0
  // A shame IPDL gives us no way to grab ownership of array: so copy it.
58
0
  const nsTArray<NetAddr>& addrs = reply.addrs();
59
0
  uint32_t i = 0;
60
0
  mLength = addrs.Length();
61
0
  for (; i < mLength; i++) {
62
0
    mAddresses.AppendElement(addrs[i]);
63
0
  }
64
0
}
65
66
//-----------------------------------------------------------------------------
67
// ChildDNSRecord::nsIDNSRecord
68
//-----------------------------------------------------------------------------
69
70
NS_IMETHODIMP
71
ChildDNSRecord::GetCanonicalName(nsACString &result)
72
0
{
73
0
  if (!(mFlags & nsHostResolver::RES_CANON_NAME)) {
74
0
    return NS_ERROR_NOT_AVAILABLE;
75
0
  }
76
0
77
0
  result = mCanonicalName;
78
0
  return NS_OK;
79
0
}
80
81
NS_IMETHODIMP
82
ChildDNSRecord::IsTRR(bool *retval)
83
0
{
84
0
  *retval = false;
85
0
  return NS_ERROR_NOT_AVAILABLE;
86
0
}
87
88
NS_IMETHODIMP
89
ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
90
0
{
91
0
  if (mCurrent >= mLength) {
92
0
    return NS_ERROR_NOT_AVAILABLE;
93
0
  }
94
0
95
0
  memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr));
96
0
97
0
  // both Ipv4/6 use same bits for port, so safe to just use ipv4's field
98
0
  addr->inet.port = htons(port);
99
0
100
0
  return NS_OK;
101
0
}
102
103
NS_IMETHODIMP
104
ChildDNSRecord::GetAddresses(nsTArray<NetAddr> & aAddressArray)
105
0
{
106
0
  aAddressArray = mAddresses;
107
0
  return NS_OK;
108
0
}
109
110
// shamelessly copied from nsDNSRecord
111
NS_IMETHODIMP
112
ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result)
113
0
{
114
0
  NetAddr addr;
115
0
  nsresult rv = GetNextAddr(port, &addr);
116
0
  if (NS_FAILED(rv)) return rv;
117
0
118
0
  NS_ADDREF(*result = new nsNetAddr(&addr));
119
0
120
0
  return NS_OK;
121
0
}
122
123
// also copied from nsDNSRecord
124
NS_IMETHODIMP
125
ChildDNSRecord::GetNextAddrAsString(nsACString &result)
126
0
{
127
0
  NetAddr addr;
128
0
  nsresult rv = GetNextAddr(0, &addr);
129
0
  if (NS_FAILED(rv)) {
130
0
    return rv;
131
0
  }
132
0
133
0
  char buf[kIPv6CStrBufSize];
134
0
  if (NetAddrToString(&addr, buf, sizeof(buf))) {
135
0
    result.Assign(buf);
136
0
    return NS_OK;
137
0
  }
138
0
  NS_ERROR("NetAddrToString failed unexpectedly");
139
0
  return NS_ERROR_FAILURE; // conversion failed for some reason
140
0
}
141
142
NS_IMETHODIMP
143
ChildDNSRecord::HasMore(bool *result)
144
0
{
145
0
  *result = mCurrent < mLength;
146
0
  return NS_OK;
147
0
}
148
149
NS_IMETHODIMP
150
ChildDNSRecord::Rewind()
151
0
{
152
0
  mCurrent = 0;
153
0
  return NS_OK;
154
0
}
155
156
NS_IMETHODIMP
157
ChildDNSRecord::ReportUnusable(uint16_t aPort)
158
0
{
159
0
  // "We thank you for your feedback" == >/dev/null
160
0
  // TODO: we could send info back to parent.
161
0
  return NS_OK;
162
0
}
163
164
class ChildDNSByTypeRecord : public nsIDNSByTypeRecord
165
{
166
public:
167
  NS_DECL_THREADSAFE_ISUPPORTS
168
  NS_DECL_NSIDNSBYTYPERECORD
169
170
  explicit ChildDNSByTypeRecord(const nsTArray<nsCString> &reply);
171
172
private:
173
0
  virtual ~ChildDNSByTypeRecord() = default;
174
175
  nsTArray<nsCString> mRecords;
176
};
177
178
NS_IMPL_ISUPPORTS(ChildDNSByTypeRecord, nsIDNSByTypeRecord)
179
180
ChildDNSByTypeRecord::ChildDNSByTypeRecord(const nsTArray<nsCString> &reply)
181
0
{
182
0
  mRecords = reply;
183
0
}
184
185
NS_IMETHODIMP
186
ChildDNSByTypeRecord::GetRecords(nsTArray<nsCString> &aRecords)
187
0
{
188
0
  aRecords = mRecords;
189
0
  return NS_OK;
190
0
}
191
192
NS_IMETHODIMP
193
ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString &aRecords)
194
0
{
195
0
  // deep copy
196
0
  for (uint32_t i = 0; i < mRecords.Length(); i++) {
197
0
      aRecords.Append(mRecords[i]);
198
0
  }
199
0
  return NS_OK;
200
0
}
201
202
203
//-----------------------------------------------------------------------------
204
// CancelDNSRequestEvent
205
//-----------------------------------------------------------------------------
206
207
class CancelDNSRequestEvent : public Runnable
208
{
209
public:
210
  CancelDNSRequestEvent(DNSRequestChild* aDnsReq, nsresult aReason)
211
    : Runnable("net::CancelDNSRequestEvent")
212
    , mDnsRequest(aDnsReq)
213
    , mReasonForCancel(aReason)
214
0
  {}
215
216
  NS_IMETHOD Run() override
217
0
  {
218
0
    if (mDnsRequest->mIPCOpen) {
219
0
      // Send request to Parent process.
220
0
      mDnsRequest->SendCancelDNSRequest(mDnsRequest->mHost,
221
0
                                        mDnsRequest->mType,
222
0
                                        mDnsRequest->mOriginAttributes,
223
0
                                        mDnsRequest->mFlags,
224
0
                                        mReasonForCancel);
225
0
    }
226
0
    return NS_OK;
227
0
  }
228
private:
229
  RefPtr<DNSRequestChild> mDnsRequest;
230
  nsresult mReasonForCancel;
231
};
232
233
//-----------------------------------------------------------------------------
234
// DNSRequestChild
235
//-----------------------------------------------------------------------------
236
237
DNSRequestChild::DNSRequestChild(const nsACString &aHost,
238
                                 const uint16_t &aType,
239
                                 const OriginAttributes& aOriginAttributes,
240
                                 const uint32_t &aFlags,
241
                                 nsIDNSListener *aListener,
242
                                 nsIEventTarget *target)
243
  : mListener(aListener)
244
  , mTarget(target)
245
  , mResultStatus(NS_OK)
246
  , mHost(aHost)
247
  , mType(aType)
248
  , mOriginAttributes(aOriginAttributes)
249
  , mFlags(aFlags)
250
  , mIPCOpen(false)
251
0
{
252
0
}
253
254
void
255
DNSRequestChild::StartRequest()
256
0
{
257
0
  // we can only do IPDL on the main thread
258
0
  if (!NS_IsMainThread()) {
259
0
    SystemGroup::Dispatch(
260
0
      TaskCategory::Other,
261
0
      NewRunnableMethod("net::DNSRequestChild::StartRequest",
262
0
                        this,
263
0
                        &DNSRequestChild::StartRequest));
264
0
    return;
265
0
  }
266
0
267
0
  nsCOMPtr<nsIEventTarget> systemGroupEventTarget
268
0
    = SystemGroup::EventTargetFor(TaskCategory::Other);
269
0
270
0
  gNeckoChild->SetEventTargetForActor(this, systemGroupEventTarget);
271
0
272
0
  mozilla::dom::ContentChild* cc =
273
0
    static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
274
0
  if (cc->IsShuttingDown()) {
275
0
    return;
276
0
  }
277
0
278
0
  // Send request to Parent process.
279
0
  gNeckoChild->SendPDNSRequestConstructor(this, mHost, mOriginAttributes,
280
0
                                          mFlags);
281
0
  mIPCOpen = true;
282
0
283
0
  // IPDL holds a reference until IPDL channel gets destroyed
284
0
  AddIPDLReference();
285
0
}
286
287
void
288
DNSRequestChild::CallOnLookupComplete()
289
0
{
290
0
  MOZ_ASSERT(mListener);
291
0
  mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
292
0
}
293
294
void
295
DNSRequestChild::CallOnLookupByTypeComplete()
296
0
{
297
0
  MOZ_ASSERT(mListener);
298
0
  MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
299
0
  mListener->OnLookupByTypeComplete(this, mResultByTypeRecords, mResultStatus);
300
0
}
301
302
mozilla::ipc::IPCResult
303
DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply)
304
0
{
305
0
  mIPCOpen = false;
306
0
  MOZ_ASSERT(mListener);
307
0
308
0
  switch (reply.type()) {
309
0
  case DNSRequestResponse::TDNSRecord: {
310
0
    mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags);
311
0
    break;
312
0
  }
313
0
  case DNSRequestResponse::Tnsresult: {
314
0
    mResultStatus = reply.get_nsresult();
315
0
    break;
316
0
  }
317
0
  case DNSRequestResponse::TArrayOfnsCString: {
318
0
    MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
319
0
    mResultByTypeRecords = new ChildDNSByTypeRecord(reply.get_ArrayOfnsCString());
320
0
    break;
321
0
  }
322
0
  default:
323
0
    MOZ_ASSERT_UNREACHABLE("unknown type");
324
0
    return IPC_FAIL_NO_REASON(this);
325
0
  }
326
0
327
0
  MOZ_ASSERT(NS_IsMainThread());
328
0
329
0
  bool targetIsMain = false;
330
0
  if (!mTarget) {
331
0
    targetIsMain = true;
332
0
  } else {
333
0
    mTarget->IsOnCurrentThread(&targetIsMain);
334
0
  }
335
0
336
0
  if (targetIsMain) {
337
0
    if (mType == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
338
0
      CallOnLookupComplete();
339
0
    } else {
340
0
      CallOnLookupByTypeComplete();
341
0
    }
342
0
  } else {
343
0
    if (mType == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
344
0
      nsCOMPtr<nsIRunnable> event =
345
0
        NewRunnableMethod("net::DNSRequestChild::CallOnLookupComplete",
346
0
                          this,
347
0
                          &DNSRequestChild::CallOnLookupComplete);
348
0
      mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
349
0
    } else {
350
0
      nsCOMPtr<nsIRunnable> event =
351
0
        NewRunnableMethod("net::DNSRequestChild::CallOnLookupByTypeComplete",
352
0
                          this,
353
0
                          &DNSRequestChild::CallOnLookupByTypeComplete);
354
0
      mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
355
0
    }
356
0
  }
357
0
358
0
  Unused << Send__delete__(this);
359
0
360
0
  return IPC_OK();
361
0
}
362
363
void
364
DNSRequestChild::ReleaseIPDLReference()
365
0
{
366
0
  // Request is done or destroyed. Remove it from the hash table.
367
0
  RefPtr<ChildDNSService> dnsServiceChild =
368
0
    dont_AddRef(ChildDNSService::GetSingleton());
369
0
  dnsServiceChild->NotifyRequestDone(this);
370
0
371
0
  Release();
372
0
}
373
374
void
375
DNSRequestChild::ActorDestroy(ActorDestroyReason why)
376
0
{
377
0
  mIPCOpen = false;
378
0
}
379
380
//-----------------------------------------------------------------------------
381
// DNSRequestChild::nsISupports
382
//-----------------------------------------------------------------------------
383
384
NS_IMPL_ISUPPORTS(DNSRequestChild,
385
                  nsICancelable)
386
387
//-----------------------------------------------------------------------------
388
// DNSRequestChild::nsICancelable
389
//-----------------------------------------------------------------------------
390
391
NS_IMETHODIMP
392
DNSRequestChild::Cancel(nsresult reason)
393
0
{
394
0
  if(mIPCOpen) {
395
0
    // We can only do IPDL on the main thread
396
0
    nsCOMPtr<nsIRunnable> runnable = new CancelDNSRequestEvent(this, reason);
397
0
    SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
398
0
  }
399
0
  return NS_OK;
400
0
}
401
402
//------------------------------------------------------------------------------
403
} // namespace net
404
} // namespace mozilla