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