DNSRequestChild.cpp 7.6 KB

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