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