UDPSocketChild.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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 file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "UDPSocketChild.h"
  6. #include "UDPSocket.h"
  7. #include "mozilla/Unused.h"
  8. #include "mozilla/ipc/InputStreamUtils.h"
  9. #include "mozilla/net/NeckoChild.h"
  10. #include "mozilla/dom/PermissionMessageUtils.h"
  11. #include "mozilla/ipc/BackgroundChild.h"
  12. #include "mozilla/ipc/PBackgroundChild.h"
  13. #include "mozilla/ipc/BackgroundUtils.h"
  14. #include "mozilla/ipc/PBackgroundSharedTypes.h"
  15. #include "nsIIPCBackgroundChildCreateCallback.h"
  16. using mozilla::net::gNeckoChild;
  17. namespace mozilla {
  18. namespace dom {
  19. NS_IMPL_ISUPPORTS(UDPSocketChildBase, nsIUDPSocketChild)
  20. UDPSocketChildBase::UDPSocketChildBase()
  21. : mIPCOpen(false)
  22. {
  23. }
  24. UDPSocketChildBase::~UDPSocketChildBase()
  25. {
  26. }
  27. void
  28. UDPSocketChildBase::ReleaseIPDLReference()
  29. {
  30. MOZ_ASSERT(mIPCOpen);
  31. mIPCOpen = false;
  32. mSocket = nullptr;
  33. this->Release();
  34. }
  35. void
  36. UDPSocketChildBase::AddIPDLReference()
  37. {
  38. MOZ_ASSERT(!mIPCOpen);
  39. mIPCOpen = true;
  40. this->AddRef();
  41. }
  42. NS_IMETHODIMP_(MozExternalRefCountType) UDPSocketChild::Release(void)
  43. {
  44. nsrefcnt refcnt = UDPSocketChildBase::Release();
  45. if (refcnt == 1 && mIPCOpen) {
  46. PUDPSocketChild::SendRequestDelete();
  47. return 1;
  48. }
  49. return refcnt;
  50. }
  51. UDPSocketChild::UDPSocketChild()
  52. :mBackgroundManager(nullptr)
  53. ,mLocalPort(0)
  54. {
  55. }
  56. UDPSocketChild::~UDPSocketChild()
  57. {
  58. }
  59. class UDPSocketBackgroundChildCallback final :
  60. public nsIIPCBackgroundChildCreateCallback
  61. {
  62. bool* mDone;
  63. public:
  64. explicit UDPSocketBackgroundChildCallback(bool* aDone)
  65. : mDone(aDone)
  66. {
  67. MOZ_ASSERT(!NS_IsMainThread());
  68. MOZ_ASSERT(mDone);
  69. MOZ_ASSERT(!*mDone);
  70. }
  71. NS_DECL_ISUPPORTS
  72. private:
  73. ~UDPSocketBackgroundChildCallback()
  74. { }
  75. virtual void
  76. ActorCreated(PBackgroundChild* aActor) override
  77. {
  78. *mDone = true;
  79. }
  80. virtual void
  81. ActorFailed() override
  82. {
  83. *mDone = true;
  84. }
  85. };
  86. NS_IMPL_ISUPPORTS(UDPSocketBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
  87. nsresult
  88. UDPSocketChild::CreatePBackgroundSpinUntilDone()
  89. {
  90. using mozilla::ipc::BackgroundChild;
  91. // Spinning the event loop in MainThread would be dangerous
  92. MOZ_ASSERT(!NS_IsMainThread());
  93. MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
  94. bool done = false;
  95. nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
  96. new UDPSocketBackgroundChildCallback(&done);
  97. if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
  98. return NS_ERROR_FAILURE;
  99. }
  100. nsIThread* thread = NS_GetCurrentThread();
  101. while (!done) {
  102. if (NS_WARN_IF(!NS_ProcessNextEvent(thread, true /* aMayWait */))) {
  103. return NS_ERROR_FAILURE;
  104. }
  105. }
  106. if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
  107. return NS_ERROR_FAILURE;
  108. }
  109. return NS_OK;
  110. }
  111. // nsIUDPSocketChild Methods
  112. NS_IMETHODIMP
  113. UDPSocketChild::SetBackgroundSpinsEvents()
  114. {
  115. using mozilla::ipc::BackgroundChild;
  116. PBackgroundChild* existingBackgroundChild =
  117. BackgroundChild::GetForCurrentThread();
  118. // If it's not spun up yet, block until it is, and retry
  119. if (!existingBackgroundChild) {
  120. nsresult rv = CreatePBackgroundSpinUntilDone();
  121. if (NS_WARN_IF(NS_FAILED(rv))) {
  122. return rv;
  123. }
  124. existingBackgroundChild =
  125. BackgroundChild::GetForCurrentThread();
  126. MOZ_ASSERT(existingBackgroundChild);
  127. }
  128. // By now PBackground is guaranteed to be/have-been up
  129. mBackgroundManager = existingBackgroundChild;
  130. return NS_OK;
  131. }
  132. NS_IMETHODIMP
  133. UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
  134. nsIPrincipal* aPrincipal,
  135. const nsACString& aHost,
  136. uint16_t aPort,
  137. bool aAddressReuse,
  138. bool aLoopback,
  139. uint32_t recvBufferSize,
  140. uint32_t sendBufferSize)
  141. {
  142. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
  143. NS_ENSURE_ARG(aSocket);
  144. if (NS_IsMainThread()) {
  145. if (!gNeckoChild->SendPUDPSocketConstructor(
  146. this, IPC::Principal(aPrincipal), mFilterName)) {
  147. return NS_ERROR_FAILURE;
  148. }
  149. } else {
  150. if (!mBackgroundManager) {
  151. return NS_ERROR_NOT_AVAILABLE;
  152. }
  153. // If we want to support a passed-in principal here we'd need to
  154. // convert it to a PrincipalInfo
  155. MOZ_ASSERT(!aPrincipal);
  156. if (!mBackgroundManager->SendPUDPSocketConstructor(
  157. this, void_t(), mFilterName)) {
  158. return NS_ERROR_FAILURE;
  159. }
  160. }
  161. mSocket = aSocket;
  162. AddIPDLReference();
  163. SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback,
  164. recvBufferSize, sendBufferSize);
  165. return NS_OK;
  166. }
  167. NS_IMETHODIMP
  168. UDPSocketChild::Connect(nsIUDPSocketInternal* aSocket, const nsACString & aHost, uint16_t aPort)
  169. {
  170. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
  171. mSocket = aSocket;
  172. SendConnect(UDPAddressInfo(nsCString(aHost), aPort));
  173. return NS_OK;
  174. }
  175. NS_IMETHODIMP
  176. UDPSocketChild::Close()
  177. {
  178. SendClose();
  179. return NS_OK;
  180. }
  181. NS_IMETHODIMP
  182. UDPSocketChild::Send(const nsACString& aHost,
  183. uint16_t aPort,
  184. const uint8_t* aData,
  185. uint32_t aByteLength)
  186. {
  187. NS_ENSURE_ARG(aData);
  188. UDPSOCKET_LOG(("%s: %s:%u - %u bytes", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort, aByteLength));
  189. return SendDataInternal(UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)),
  190. aData, aByteLength);
  191. }
  192. NS_IMETHODIMP
  193. UDPSocketChild::SendWithAddr(nsINetAddr* aAddr,
  194. const uint8_t* aData,
  195. uint32_t aByteLength)
  196. {
  197. NS_ENSURE_ARG(aAddr);
  198. NS_ENSURE_ARG(aData);
  199. NetAddr addr;
  200. aAddr->GetNetAddr(&addr);
  201. UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength));
  202. return SendDataInternal(UDPSocketAddr(addr), aData, aByteLength);
  203. }
  204. NS_IMETHODIMP
  205. UDPSocketChild::SendWithAddress(const NetAddr* aAddr,
  206. const uint8_t* aData,
  207. uint32_t aByteLength)
  208. {
  209. NS_ENSURE_ARG(aAddr);
  210. NS_ENSURE_ARG(aData);
  211. UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength));
  212. return SendDataInternal(UDPSocketAddr(*aAddr), aData, aByteLength);
  213. }
  214. nsresult
  215. UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr,
  216. const uint8_t* aData,
  217. const uint32_t aByteLength)
  218. {
  219. NS_ENSURE_ARG(aData);
  220. FallibleTArray<uint8_t> fallibleArray;
  221. if (!fallibleArray.InsertElementsAt(0, aData, aByteLength, fallible)) {
  222. return NS_ERROR_OUT_OF_MEMORY;
  223. }
  224. InfallibleTArray<uint8_t> array;
  225. array.SwapElements(fallibleArray);
  226. SendOutgoingData(array, aAddr);
  227. return NS_OK;
  228. }
  229. NS_IMETHODIMP
  230. UDPSocketChild::SendBinaryStream(const nsACString& aHost,
  231. uint16_t aPort,
  232. nsIInputStream* aStream)
  233. {
  234. NS_ENSURE_ARG(aStream);
  235. OptionalInputStreamParams stream;
  236. nsTArray<mozilla::ipc::FileDescriptor> fds;
  237. SerializeInputStream(aStream, stream, fds);
  238. MOZ_ASSERT(fds.IsEmpty());
  239. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
  240. SendOutgoingData(UDPData(stream), UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)));
  241. return NS_OK;
  242. }
  243. NS_IMETHODIMP
  244. UDPSocketChild::JoinMulticast(const nsACString& aMulticastAddress,
  245. const nsACString& aInterface)
  246. {
  247. SendJoinMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
  248. return NS_OK;
  249. }
  250. NS_IMETHODIMP
  251. UDPSocketChild::LeaveMulticast(const nsACString& aMulticastAddress,
  252. const nsACString& aInterface)
  253. {
  254. SendLeaveMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
  255. return NS_OK;
  256. }
  257. NS_IMETHODIMP
  258. UDPSocketChild::GetLocalPort(uint16_t* aLocalPort)
  259. {
  260. NS_ENSURE_ARG_POINTER(aLocalPort);
  261. *aLocalPort = mLocalPort;
  262. return NS_OK;
  263. }
  264. NS_IMETHODIMP
  265. UDPSocketChild::GetLocalAddress(nsACString& aLocalAddress)
  266. {
  267. aLocalAddress = mLocalAddress;
  268. return NS_OK;
  269. }
  270. NS_IMETHODIMP
  271. UDPSocketChild::SetFilterName(const nsACString& aFilterName)
  272. {
  273. if (!mFilterName.IsEmpty()) {
  274. // filter name can only be set once.
  275. return NS_ERROR_FAILURE;
  276. }
  277. mFilterName = aFilterName;
  278. return NS_OK;
  279. }
  280. NS_IMETHODIMP
  281. UDPSocketChild::GetFilterName(nsACString& aFilterName)
  282. {
  283. aFilterName = mFilterName;
  284. return NS_OK;
  285. }
  286. // PUDPSocketChild Methods
  287. bool
  288. UDPSocketChild::RecvCallbackOpened(const UDPAddressInfo& aAddressInfo)
  289. {
  290. mLocalAddress = aAddressInfo.addr();
  291. mLocalPort = aAddressInfo.port();
  292. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
  293. nsresult rv = mSocket->CallListenerOpened();
  294. mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
  295. return true;
  296. }
  297. // PUDPSocketChild Methods
  298. bool
  299. UDPSocketChild::RecvCallbackConnected(const UDPAddressInfo& aAddressInfo)
  300. {
  301. mLocalAddress = aAddressInfo.addr();
  302. mLocalPort = aAddressInfo.port();
  303. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
  304. nsresult rv = mSocket->CallListenerConnected();
  305. mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
  306. return true;
  307. }
  308. bool
  309. UDPSocketChild::RecvCallbackClosed()
  310. {
  311. nsresult rv = mSocket->CallListenerClosed();
  312. mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
  313. return true;
  314. }
  315. bool
  316. UDPSocketChild::RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
  317. InfallibleTArray<uint8_t>&& aData)
  318. {
  319. UDPSOCKET_LOG(("%s: %s:%u length %u", __FUNCTION__,
  320. aAddressInfo.addr().get(), aAddressInfo.port(), aData.Length()));
  321. nsresult rv = mSocket->CallListenerReceivedData(aAddressInfo.addr(), aAddressInfo.port(),
  322. aData.Elements(), aData.Length());
  323. mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
  324. return true;
  325. }
  326. bool
  327. UDPSocketChild::RecvCallbackError(const nsCString& aMessage,
  328. const nsCString& aFilename,
  329. const uint32_t& aLineNumber)
  330. {
  331. UDPSOCKET_LOG(("%s: %s:%s:%u", __FUNCTION__, aMessage.get(), aFilename.get(), aLineNumber));
  332. nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber);
  333. mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
  334. return true;
  335. }
  336. } // namespace dom
  337. } // namespace mozilla