UDPSocket.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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 "UDPSocket.h"
  6. #include "mozilla/AsyncEventDispatcher.h"
  7. #include "mozilla/dom/File.h"
  8. #include "mozilla/dom/ErrorEvent.h"
  9. #include "mozilla/dom/UDPMessageEvent.h"
  10. #include "mozilla/dom/UDPSocketBinding.h"
  11. #include "mozilla/dom/UnionTypes.h"
  12. #include "mozilla/net/DNS.h"
  13. #include "nsComponentManagerUtils.h"
  14. #include "nsContentUtils.h"
  15. #include "nsINetAddr.h"
  16. #include "nsStringStream.h"
  17. using namespace mozilla::net;
  18. namespace mozilla {
  19. namespace dom {
  20. NS_IMPL_ISUPPORTS(UDPSocket::ListenerProxy,
  21. nsIUDPSocketListener,
  22. nsIUDPSocketInternal)
  23. NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
  24. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
  25. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpened)
  26. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClosed)
  27. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  28. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
  29. NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpened)
  30. NS_IMPL_CYCLE_COLLECTION_UNLINK(mClosed)
  31. tmp->CloseWithReason(NS_OK);
  32. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  33. NS_IMPL_ADDREF_INHERITED(UDPSocket, DOMEventTargetHelper)
  34. NS_IMPL_RELEASE_INHERITED(UDPSocket, DOMEventTargetHelper)
  35. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UDPSocket)
  36. NS_INTERFACE_MAP_ENTRY(nsIUDPSocketListener)
  37. NS_INTERFACE_MAP_ENTRY(nsIUDPSocketInternal)
  38. NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
  39. /* static */ already_AddRefed<UDPSocket>
  40. UDPSocket::Constructor(const GlobalObject& aGlobal,
  41. const UDPOptions& aOptions,
  42. ErrorResult& aRv)
  43. {
  44. nsCOMPtr<nsPIDOMWindowInner> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
  45. if (!ownerWindow) {
  46. aRv.Throw(NS_ERROR_FAILURE);
  47. return nullptr;
  48. }
  49. bool addressReuse = aOptions.mAddressReuse;
  50. bool loopback = aOptions.mLoopback;
  51. nsCString remoteAddress;
  52. if (aOptions.mRemoteAddress.WasPassed()) {
  53. remoteAddress = NS_ConvertUTF16toUTF8(aOptions.mRemoteAddress.Value());
  54. } else {
  55. remoteAddress.SetIsVoid(true);
  56. }
  57. Nullable<uint16_t> remotePort;
  58. if (aOptions.mRemotePort.WasPassed()) {
  59. remotePort.SetValue(aOptions.mRemotePort.Value());
  60. if (remotePort.Value() == 0) {
  61. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  62. return nullptr;
  63. }
  64. }
  65. nsString localAddress;
  66. if (aOptions.mLocalAddress.WasPassed()) {
  67. localAddress = aOptions.mLocalAddress.Value();
  68. // check if localAddress is a valid IPv4/6 address
  69. NS_ConvertUTF16toUTF8 address(localAddress);
  70. PRNetAddr prAddr;
  71. PRStatus status = PR_StringToNetAddr(address.BeginReading(), &prAddr);
  72. if (status != PR_SUCCESS) {
  73. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  74. return nullptr;
  75. }
  76. } else {
  77. SetDOMStringToNull(localAddress);
  78. }
  79. Nullable<uint16_t> localPort;
  80. if (aOptions.mLocalPort.WasPassed()) {
  81. localPort.SetValue(aOptions.mLocalPort.Value());
  82. if (localPort.Value() == 0) {
  83. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  84. return nullptr;
  85. }
  86. }
  87. RefPtr<UDPSocket> socket = new UDPSocket(ownerWindow, remoteAddress, remotePort);
  88. aRv = socket->Init(localAddress, localPort, addressReuse, loopback);
  89. if (NS_WARN_IF(aRv.Failed())) {
  90. return nullptr;
  91. }
  92. return socket.forget();
  93. }
  94. UDPSocket::UDPSocket(nsPIDOMWindowInner* aOwner,
  95. const nsCString& aRemoteAddress,
  96. const Nullable<uint16_t>& aRemotePort)
  97. : DOMEventTargetHelper(aOwner)
  98. , mRemoteAddress(aRemoteAddress)
  99. , mRemotePort(aRemotePort)
  100. , mAddressReuse(false)
  101. , mLoopback(false)
  102. , mReadyState(SocketReadyState::Opening)
  103. {
  104. MOZ_ASSERT(aOwner);
  105. MOZ_ASSERT(aOwner->IsInnerWindow());
  106. nsIDocument* aDoc = aOwner->GetExtantDoc();
  107. if (aDoc) {
  108. aDoc->DisallowBFCaching();
  109. }
  110. }
  111. UDPSocket::~UDPSocket()
  112. {
  113. CloseWithReason(NS_OK);
  114. }
  115. JSObject*
  116. UDPSocket::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  117. {
  118. return UDPSocketBinding::Wrap(aCx, this, aGivenProto);
  119. }
  120. void
  121. UDPSocket::DisconnectFromOwner()
  122. {
  123. DOMEventTargetHelper::DisconnectFromOwner();
  124. CloseWithReason(NS_OK);
  125. }
  126. already_AddRefed<Promise>
  127. UDPSocket::Close()
  128. {
  129. MOZ_ASSERT(mClosed);
  130. RefPtr<Promise> promise = mClosed;
  131. if (mReadyState == SocketReadyState::Closed) {
  132. return promise.forget();
  133. }
  134. CloseWithReason(NS_OK);
  135. return promise.forget();
  136. }
  137. void
  138. UDPSocket::CloseWithReason(nsresult aReason)
  139. {
  140. if (mReadyState == SocketReadyState::Closed) {
  141. return;
  142. }
  143. if (mOpened) {
  144. if (mReadyState == SocketReadyState::Opening) {
  145. // reject openedPromise with AbortError if socket is closed without error
  146. nsresult openFailedReason = NS_FAILED(aReason) ? aReason : NS_ERROR_DOM_ABORT_ERR;
  147. mOpened->MaybeReject(openFailedReason);
  148. }
  149. }
  150. mReadyState = SocketReadyState::Closed;
  151. if (mListenerProxy) {
  152. mListenerProxy->Disconnect();
  153. mListenerProxy = nullptr;
  154. }
  155. if (mSocket) {
  156. mSocket->Close();
  157. mSocket = nullptr;
  158. }
  159. if (mSocketChild) {
  160. mSocketChild->Close();
  161. mSocketChild = nullptr;
  162. }
  163. if (mClosed) {
  164. if (NS_SUCCEEDED(aReason)) {
  165. mClosed->MaybeResolveWithUndefined();
  166. } else {
  167. mClosed->MaybeReject(aReason);
  168. }
  169. }
  170. mPendingMcastCommands.Clear();
  171. }
  172. void
  173. UDPSocket::JoinMulticastGroup(const nsAString& aMulticastGroupAddress,
  174. ErrorResult& aRv)
  175. {
  176. if (mReadyState == SocketReadyState::Closed) {
  177. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  178. return;
  179. }
  180. if (mReadyState == SocketReadyState::Opening) {
  181. MulticastCommand joinCommand(MulticastCommand::Join, aMulticastGroupAddress);
  182. mPendingMcastCommands.AppendElement(joinCommand);
  183. return;
  184. }
  185. MOZ_ASSERT(mSocket || mSocketChild);
  186. NS_ConvertUTF16toUTF8 address(aMulticastGroupAddress);
  187. if (mSocket) {
  188. MOZ_ASSERT(!mSocketChild);
  189. aRv = mSocket->JoinMulticast(address, EmptyCString());
  190. NS_WARNING_ASSERTION(!aRv.Failed(), "JoinMulticast failed");
  191. return;
  192. }
  193. MOZ_ASSERT(mSocketChild);
  194. aRv = mSocketChild->JoinMulticast(address, EmptyCString());
  195. NS_WARNING_ASSERTION(!aRv.Failed(), "JoinMulticast failed");
  196. }
  197. void
  198. UDPSocket::LeaveMulticastGroup(const nsAString& aMulticastGroupAddress,
  199. ErrorResult& aRv)
  200. {
  201. if (mReadyState == SocketReadyState::Closed) {
  202. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  203. return;
  204. }
  205. if (mReadyState == SocketReadyState::Opening) {
  206. MulticastCommand leaveCommand(MulticastCommand::Leave, aMulticastGroupAddress);
  207. mPendingMcastCommands.AppendElement(leaveCommand);
  208. return;
  209. }
  210. MOZ_ASSERT(mSocket || mSocketChild);
  211. nsCString address = NS_ConvertUTF16toUTF8(aMulticastGroupAddress);
  212. if (mSocket) {
  213. MOZ_ASSERT(!mSocketChild);
  214. aRv = mSocket->LeaveMulticast(address, EmptyCString());
  215. NS_WARNING_ASSERTION(!aRv.Failed(), "mSocket->LeaveMulticast failed");
  216. return;
  217. }
  218. MOZ_ASSERT(mSocketChild);
  219. aRv = mSocketChild->LeaveMulticast(address, EmptyCString());
  220. NS_WARNING_ASSERTION(!aRv.Failed(), "mSocketChild->LeaveMulticast failed");
  221. }
  222. nsresult
  223. UDPSocket::DoPendingMcastCommand()
  224. {
  225. MOZ_ASSERT(mReadyState == SocketReadyState::Open, "Multicast command can only be executed after socket opened");
  226. for (uint32_t i = 0; i < mPendingMcastCommands.Length(); ++i) {
  227. MulticastCommand& command = mPendingMcastCommands[i];
  228. ErrorResult rv;
  229. switch (command.mCommand) {
  230. case MulticastCommand::Join: {
  231. JoinMulticastGroup(command.mAddress, rv);
  232. break;
  233. }
  234. case MulticastCommand::Leave: {
  235. LeaveMulticastGroup(command.mAddress, rv);
  236. break;
  237. }
  238. }
  239. if (NS_WARN_IF(rv.Failed())) {
  240. return rv.StealNSResult();
  241. }
  242. }
  243. mPendingMcastCommands.Clear();
  244. return NS_OK;
  245. }
  246. bool
  247. UDPSocket::Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
  248. const Optional<nsAString>& aRemoteAddress,
  249. const Optional<Nullable<uint16_t>>& aRemotePort,
  250. ErrorResult& aRv)
  251. {
  252. if (mReadyState != SocketReadyState::Open) {
  253. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  254. return false;
  255. }
  256. MOZ_ASSERT(mSocket || mSocketChild);
  257. // If the remote address and port were not specified in the constructor or as arguments,
  258. // throw InvalidAccessError.
  259. nsCString remoteAddress;
  260. if (aRemoteAddress.WasPassed()) {
  261. remoteAddress = NS_ConvertUTF16toUTF8(aRemoteAddress.Value());
  262. UDPSOCKET_LOG(("%s: Send to %s", __FUNCTION__, remoteAddress.get()));
  263. } else if (!mRemoteAddress.IsVoid()) {
  264. remoteAddress = mRemoteAddress;
  265. UDPSOCKET_LOG(("%s: Send to %s", __FUNCTION__, remoteAddress.get()));
  266. } else {
  267. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  268. return false;
  269. }
  270. uint16_t remotePort;
  271. if (aRemotePort.WasPassed() && !aRemotePort.Value().IsNull()) {
  272. remotePort = aRemotePort.Value().Value();
  273. } else if (!mRemotePort.IsNull()) {
  274. remotePort = mRemotePort.Value();
  275. } else {
  276. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  277. return false;
  278. }
  279. nsCOMPtr<nsIInputStream> stream;
  280. if (aData.IsBlob()) {
  281. Blob& blob = aData.GetAsBlob();
  282. blob.GetInternalStream(getter_AddRefs(stream), aRv);
  283. if (NS_WARN_IF(aRv.Failed())) {
  284. return false;
  285. }
  286. } else {
  287. nsresult rv;
  288. nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
  289. if (NS_WARN_IF(NS_FAILED(rv))) {
  290. aRv.Throw(rv);
  291. return false;
  292. }
  293. if (aData.IsString()) {
  294. NS_ConvertUTF16toUTF8 data(aData.GetAsString());
  295. aRv = strStream->SetData(data.BeginReading(), data.Length());
  296. } else if (aData.IsArrayBuffer()) {
  297. const ArrayBuffer& data = aData.GetAsArrayBuffer();
  298. data.ComputeLengthAndData();
  299. aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
  300. } else {
  301. const ArrayBufferView& data = aData.GetAsArrayBufferView();
  302. data.ComputeLengthAndData();
  303. aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
  304. }
  305. if (NS_WARN_IF(aRv.Failed())) {
  306. return false;
  307. }
  308. stream = strStream;
  309. }
  310. if (mSocket) {
  311. aRv = mSocket->SendBinaryStream(remoteAddress, remotePort, stream);
  312. } else if (mSocketChild) {
  313. aRv = mSocketChild->SendBinaryStream(remoteAddress, remotePort, stream);
  314. }
  315. if (NS_WARN_IF(aRv.Failed())) {
  316. return false;
  317. }
  318. return true;
  319. }
  320. nsresult
  321. UDPSocket::InitLocal(const nsAString& aLocalAddress,
  322. const uint16_t& aLocalPort)
  323. {
  324. nsresult rv;
  325. nsCOMPtr<nsIUDPSocket> sock =
  326. do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
  327. if (NS_FAILED(rv)) {
  328. return rv;
  329. }
  330. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner(), &rv);
  331. if (NS_FAILED(rv)) {
  332. return rv;
  333. }
  334. nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
  335. if (!principal) {
  336. return NS_ERROR_FAILURE;
  337. }
  338. if (aLocalAddress.IsEmpty()) {
  339. rv = sock->Init(aLocalPort, /* loopback = */ false, principal,
  340. mAddressReuse, /* optionalArgc = */ 1);
  341. } else {
  342. PRNetAddr prAddr;
  343. PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr);
  344. PR_StringToNetAddr(NS_ConvertUTF16toUTF8(aLocalAddress).BeginReading(), &prAddr);
  345. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, NS_ConvertUTF16toUTF8(aLocalAddress).get(), aLocalPort));
  346. mozilla::net::NetAddr addr;
  347. PRNetAddrToNetAddr(&prAddr, &addr);
  348. rv = sock->InitWithAddress(&addr, principal, mAddressReuse,
  349. /* optionalArgc = */ 1);
  350. }
  351. if (NS_FAILED(rv)) {
  352. return rv;
  353. }
  354. rv = sock->SetMulticastLoopback(mLoopback);
  355. if (NS_FAILED(rv)) {
  356. return rv;
  357. }
  358. mSocket = sock;
  359. // Get real local address and local port
  360. nsCOMPtr<nsINetAddr> localAddr;
  361. rv = mSocket->GetLocalAddr(getter_AddRefs(localAddr));
  362. if (NS_FAILED(rv)) {
  363. return rv;
  364. }
  365. nsCString localAddress;
  366. rv = localAddr->GetAddress(localAddress);
  367. if (NS_FAILED(rv)) {
  368. return rv;
  369. }
  370. mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
  371. uint16_t localPort;
  372. rv = localAddr->GetPort(&localPort);
  373. if (NS_FAILED(rv)) {
  374. return rv;
  375. }
  376. mLocalPort.SetValue(localPort);
  377. mListenerProxy = new ListenerProxy(this);
  378. rv = mSocket->AsyncListen(mListenerProxy);
  379. if (NS_FAILED(rv)) {
  380. return rv;
  381. }
  382. mReadyState = SocketReadyState::Open;
  383. rv = DoPendingMcastCommand();
  384. if (NS_FAILED(rv)) {
  385. return rv;
  386. }
  387. mOpened->MaybeResolveWithUndefined();
  388. return NS_OK;
  389. }
  390. nsresult
  391. UDPSocket::InitRemote(const nsAString& aLocalAddress,
  392. const uint16_t& aLocalPort)
  393. {
  394. nsresult rv;
  395. nsCOMPtr<nsIUDPSocketChild> sock =
  396. do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
  397. if (NS_FAILED(rv)) {
  398. return rv;
  399. }
  400. mListenerProxy = new ListenerProxy(this);
  401. nsCOMPtr<nsIGlobalObject> obj = do_QueryInterface(GetOwner(), &rv);
  402. if (NS_FAILED(rv)) {
  403. return rv;
  404. }
  405. nsCOMPtr<nsIPrincipal> principal = obj->PrincipalOrNull();
  406. if (!principal) {
  407. return NS_ERROR_FAILURE;
  408. }
  409. rv = sock->Bind(mListenerProxy,
  410. principal,
  411. NS_ConvertUTF16toUTF8(aLocalAddress),
  412. aLocalPort,
  413. mAddressReuse,
  414. mLoopback,
  415. 0,
  416. 0);
  417. if (NS_FAILED(rv)) {
  418. return rv;
  419. }
  420. mSocketChild = sock;
  421. return NS_OK;
  422. }
  423. nsresult
  424. UDPSocket::Init(const nsString& aLocalAddress,
  425. const Nullable<uint16_t>& aLocalPort,
  426. const bool& aAddressReuse,
  427. const bool& aLoopback)
  428. {
  429. MOZ_ASSERT(!mSocket && !mSocketChild);
  430. mLocalAddress = aLocalAddress;
  431. mLocalPort = aLocalPort;
  432. mAddressReuse = aAddressReuse;
  433. mLoopback = aLoopback;
  434. ErrorResult rv;
  435. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
  436. mOpened = Promise::Create(global, rv);
  437. if (NS_WARN_IF(rv.Failed())) {
  438. return rv.StealNSResult();
  439. }
  440. mClosed = Promise::Create(global, rv);
  441. if (NS_WARN_IF(rv.Failed())) {
  442. return rv.StealNSResult();
  443. }
  444. class OpenSocketRunnable final : public Runnable
  445. {
  446. public:
  447. explicit OpenSocketRunnable(UDPSocket* aSocket) : mSocket(aSocket)
  448. { }
  449. NS_IMETHOD Run() override
  450. {
  451. MOZ_ASSERT(mSocket);
  452. if (mSocket->mReadyState != SocketReadyState::Opening) {
  453. return NS_OK;
  454. }
  455. uint16_t localPort = 0;
  456. if (!mSocket->mLocalPort.IsNull()) {
  457. localPort = mSocket->mLocalPort.Value();
  458. }
  459. nsresult rv;
  460. if (!XRE_IsParentProcess()) {
  461. rv = mSocket->InitRemote(mSocket->mLocalAddress, localPort);
  462. } else {
  463. rv = mSocket->InitLocal(mSocket->mLocalAddress, localPort);
  464. }
  465. if (NS_WARN_IF(NS_FAILED(rv))) {
  466. mSocket->CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
  467. }
  468. return NS_OK;
  469. }
  470. private:
  471. RefPtr<UDPSocket> mSocket;
  472. };
  473. nsCOMPtr<nsIRunnable> runnable = new OpenSocketRunnable(this);
  474. return NS_DispatchToMainThread(runnable);
  475. }
  476. void
  477. UDPSocket::HandleReceivedData(const nsACString& aRemoteAddress,
  478. const uint16_t& aRemotePort,
  479. const uint8_t* aData,
  480. const uint32_t& aDataLength)
  481. {
  482. if (mReadyState != SocketReadyState::Open) {
  483. return;
  484. }
  485. if (NS_FAILED(CheckInnerWindowCorrectness())) {
  486. return;
  487. }
  488. if (NS_FAILED(DispatchReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength))) {
  489. CloseWithReason(NS_ERROR_TYPE_ERR);
  490. }
  491. }
  492. nsresult
  493. UDPSocket::DispatchReceivedData(const nsACString& aRemoteAddress,
  494. const uint16_t& aRemotePort,
  495. const uint8_t* aData,
  496. const uint32_t& aDataLength)
  497. {
  498. AutoJSAPI jsapi;
  499. if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
  500. return NS_ERROR_FAILURE;
  501. }
  502. JSContext* cx = jsapi.cx();
  503. // Copy packet data to ArrayBuffer
  504. JS::Rooted<JSObject*> arrayBuf(cx, ArrayBuffer::Create(cx, aDataLength, aData));
  505. if (NS_WARN_IF(!arrayBuf)) {
  506. return NS_ERROR_FAILURE;
  507. }
  508. JS::Rooted<JS::Value> jsData(cx, JS::ObjectValue(*arrayBuf));
  509. // Create DOM event
  510. RootedDictionary<UDPMessageEventInit> init(cx);
  511. init.mRemoteAddress = NS_ConvertUTF8toUTF16(aRemoteAddress);
  512. init.mRemotePort = aRemotePort;
  513. init.mData = jsData;
  514. RefPtr<UDPMessageEvent> udpEvent =
  515. UDPMessageEvent::Constructor(this, NS_LITERAL_STRING("message"), init);
  516. if (NS_WARN_IF(!udpEvent)) {
  517. return NS_ERROR_FAILURE;
  518. }
  519. udpEvent->SetTrusted(true);
  520. RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(this, udpEvent);
  521. return asyncDispatcher->PostDOMEvent();
  522. }
  523. // nsIUDPSocketListener
  524. NS_IMETHODIMP
  525. UDPSocket::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
  526. {
  527. // nsIUDPSocketListener callbacks should be invoked on main thread.
  528. MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
  529. // Create appropriate JS object for message
  530. FallibleTArray<uint8_t>& buffer = aMessage->GetDataAsTArray();
  531. nsCOMPtr<nsINetAddr> addr;
  532. if (NS_WARN_IF(NS_FAILED(aMessage->GetFromAddr(getter_AddRefs(addr))))) {
  533. return NS_OK;
  534. }
  535. nsCString remoteAddress;
  536. if (NS_WARN_IF(NS_FAILED(addr->GetAddress(remoteAddress)))) {
  537. return NS_OK;
  538. }
  539. uint16_t remotePort;
  540. if (NS_WARN_IF(NS_FAILED(addr->GetPort(&remotePort)))) {
  541. return NS_OK;
  542. }
  543. HandleReceivedData(remoteAddress, remotePort, buffer.Elements(), buffer.Length());
  544. return NS_OK;
  545. }
  546. NS_IMETHODIMP
  547. UDPSocket::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
  548. {
  549. // nsIUDPSocketListener callbacks should be invoked on main thread.
  550. MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
  551. CloseWithReason(aStatus);
  552. return NS_OK;
  553. }
  554. // nsIUDPSocketInternal
  555. NS_IMETHODIMP
  556. UDPSocket::CallListenerError(const nsACString& aMessage,
  557. const nsACString& aFilename,
  558. uint32_t aLineNumber)
  559. {
  560. CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
  561. return NS_OK;
  562. }
  563. NS_IMETHODIMP
  564. UDPSocket::CallListenerReceivedData(const nsACString& aRemoteAddress,
  565. uint16_t aRemotePort,
  566. const uint8_t* aData,
  567. uint32_t aDataLength)
  568. {
  569. HandleReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength);
  570. return NS_OK;
  571. }
  572. NS_IMETHODIMP
  573. UDPSocket::CallListenerOpened()
  574. {
  575. if (mReadyState != SocketReadyState::Opening) {
  576. return NS_OK;
  577. }
  578. MOZ_ASSERT(mSocketChild);
  579. // Get real local address and local port
  580. nsCString localAddress;
  581. mSocketChild->GetLocalAddress(localAddress);
  582. mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
  583. uint16_t localPort;
  584. mSocketChild->GetLocalPort(&localPort);
  585. mLocalPort.SetValue(localPort);
  586. mReadyState = SocketReadyState::Open;
  587. nsresult rv = DoPendingMcastCommand();
  588. if (NS_WARN_IF(NS_FAILED(rv))) {
  589. CloseWithReason(rv);
  590. return NS_OK;
  591. }
  592. mOpened->MaybeResolveWithUndefined();
  593. return NS_OK;
  594. }
  595. NS_IMETHODIMP
  596. UDPSocket::CallListenerConnected()
  597. {
  598. // This shouldn't be called here.
  599. MOZ_CRASH();
  600. return NS_OK;
  601. }
  602. NS_IMETHODIMP
  603. UDPSocket::CallListenerClosed()
  604. {
  605. CloseWithReason(NS_OK);
  606. return NS_OK;
  607. }
  608. } // namespace dom
  609. } // namespace mozilla