1 /* vim:set ts=2 sw=2 et cindent: */
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/. */
7 #include "mozilla/Attributes.h"
8 #include "mozilla/Components.h"
9 #include "mozilla/EndianUtils.h"
10 #include "mozilla/dom/TypedArray.h"
11 #include "mozilla/HoldDropJSObjects.h"
12 #include "mozilla/Telemetry.h"
14 #include "nsQueryObject.h"
15 #include "nsSocketTransport2.h"
16 #include "nsUDPSocket.h"
17 #include "nsProxyRelease.h"
20 #include "nsNetUtil.h"
21 #include "nsIOService.h"
24 #include "nsNetAddr.h"
25 #include "nsNetSegmentUtils.h"
26 #include "nsServiceManagerUtils.h"
27 #include "nsStreamUtils.h"
29 #include "nsThreadUtils.h"
30 #include "nsIDNSRecord.h"
31 #include "nsIDNSService.h"
32 #include "nsICancelable.h"
34 #include "nsWrapperCacheInlines.h"
35 #include "HttpConnectionUDP.h"
36 #include "mozilla/ProfilerBandwidthCounter.h"
37 #include "mozilla/StaticPrefs_network.h"
40 # include "FuzzyLayer.h"
41 # include "mozilla/StaticPrefs_fuzzing.h"
47 static const uint32_t UDP_PACKET_CHUNK_SIZE
= 1400;
49 //-----------------------------------------------------------------------------
51 using nsUDPSocketFunc
= void (nsUDPSocket::*)();
53 static nsresult
PostEvent(nsUDPSocket
* s
, nsUDPSocketFunc func
) {
54 if (!gSocketTransportService
) return NS_ERROR_FAILURE
;
56 return gSocketTransportService
->Dispatch(
57 NewRunnableMethod("net::PostEvent", s
, func
), NS_DISPATCH_NORMAL
);
60 static nsresult
ResolveHost(const nsACString
& host
,
61 const OriginAttributes
& aOriginAttributes
,
62 nsIDNSListener
* listener
) {
65 nsCOMPtr
<nsIDNSService
> dns
;
66 dns
= mozilla::components::DNS::Service(&rv
);
71 nsCOMPtr
<nsICancelable
> tmpOutstanding
;
72 return dns
->AsyncResolveNative(host
, nsIDNSService::RESOLVE_TYPE_DEFAULT
,
73 nsIDNSService::RESOLVE_DEFAULT_FLAGS
, nullptr,
74 listener
, nullptr, aOriginAttributes
,
75 getter_AddRefs(tmpOutstanding
));
78 static nsresult
CheckIOStatus(const NetAddr
* aAddr
) {
79 MOZ_ASSERT(gIOService
);
81 if (gIOService
->IsNetTearingDown()) {
82 return NS_ERROR_FAILURE
;
85 if (gIOService
->IsOffline() &&
86 (StaticPrefs::network_disable_localhost_when_offline() ||
87 !aAddr
->IsLoopbackAddr())) {
88 return NS_ERROR_OFFLINE
;
94 //-----------------------------------------------------------------------------
96 class SetSocketOptionRunnable
: public Runnable
{
98 SetSocketOptionRunnable(nsUDPSocket
* aSocket
, const PRSocketOptionData
& aOpt
)
99 : Runnable("net::SetSocketOptionRunnable"),
103 NS_IMETHOD
Run() override
{ return mSocket
->SetSocketOption(mOpt
); }
106 RefPtr
<nsUDPSocket
> mSocket
;
107 PRSocketOptionData mOpt
;
110 //-----------------------------------------------------------------------------
111 // nsUDPOutputStream impl
112 //-----------------------------------------------------------------------------
113 NS_IMPL_ISUPPORTS(nsUDPOutputStream
, nsIOutputStream
)
115 nsUDPOutputStream::nsUDPOutputStream(nsUDPSocket
* aSocket
, PRFileDesc
* aFD
,
116 PRNetAddr
& aPrClientAddr
)
119 mPrClientAddr(aPrClientAddr
),
122 NS_IMETHODIMP
nsUDPOutputStream::Close() {
123 if (mIsClosed
) return NS_BASE_STREAM_CLOSED
;
129 NS_IMETHODIMP
nsUDPOutputStream::Flush() { return NS_OK
; }
131 NS_IMETHODIMP
nsUDPOutputStream::StreamStatus() {
132 return mIsClosed
? NS_BASE_STREAM_CLOSED
: NS_OK
;
135 NS_IMETHODIMP
nsUDPOutputStream::Write(const char* aBuf
, uint32_t aCount
,
137 if (mIsClosed
) return NS_BASE_STREAM_CLOSED
;
141 PR_SendTo(mFD
, aBuf
, aCount
, 0, &mPrClientAddr
, PR_INTERVAL_NO_WAIT
);
143 PRErrorCode code
= PR_GetError();
144 return ErrorAccordingToNSPR(code
);
149 mSocket
->AddOutputBytes(count
);
154 NS_IMETHODIMP
nsUDPOutputStream::WriteFrom(nsIInputStream
* aFromStream
,
155 uint32_t aCount
, uint32_t* _retval
) {
156 return NS_ERROR_NOT_IMPLEMENTED
;
159 NS_IMETHODIMP
nsUDPOutputStream::WriteSegments(nsReadSegmentFun aReader
,
160 void* aClosure
, uint32_t aCount
,
162 return NS_ERROR_NOT_IMPLEMENTED
;
165 NS_IMETHODIMP
nsUDPOutputStream::IsNonBlocking(bool* _retval
) {
170 //-----------------------------------------------------------------------------
172 //-----------------------------------------------------------------------------
173 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsUDPMessage
)
174 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsUDPMessage
)
176 NS_IMPL_CYCLE_COLLECTION_CLASS(nsUDPMessage
)
178 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsUDPMessage
)
179 NS_INTERFACE_MAP_ENTRY(nsISupports
)
180 NS_INTERFACE_MAP_ENTRY(nsIUDPMessage
)
183 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsUDPMessage
)
184 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsobj
)
185 NS_IMPL_CYCLE_COLLECTION_TRACE_END
187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsUDPMessage
)
188 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
190 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsUDPMessage
)
191 tmp
->mJsobj
= nullptr;
192 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
194 nsUDPMessage::nsUDPMessage(NetAddr
* aAddr
, nsIOutputStream
* aOutputStream
,
195 FallibleTArray
<uint8_t>&& aData
)
196 : mOutputStream(aOutputStream
), mData(std::move(aData
)) {
197 memcpy(&mAddr
, aAddr
, sizeof(NetAddr
));
200 nsUDPMessage::~nsUDPMessage() { DropJSObjects(this); }
203 nsUDPMessage::GetFromAddr(nsINetAddr
** aFromAddr
) {
204 NS_ENSURE_ARG_POINTER(aFromAddr
);
206 nsCOMPtr
<nsINetAddr
> result
= new nsNetAddr(&mAddr
);
207 result
.forget(aFromAddr
);
213 nsUDPMessage::GetData(nsACString
& aData
) {
214 aData
.Assign(reinterpret_cast<const char*>(mData
.Elements()), mData
.Length());
219 nsUDPMessage::GetOutputStream(nsIOutputStream
** aOutputStream
) {
220 NS_ENSURE_ARG_POINTER(aOutputStream
);
221 *aOutputStream
= do_AddRef(mOutputStream
).take();
226 nsUDPMessage::GetRawData(JSContext
* cx
, JS::MutableHandle
<JS::Value
> aRawData
) {
229 mJsobj
= dom::Uint8Array::Create(cx
, nullptr, mData
, error
);
230 if (error
.Failed()) {
231 return error
.StealNSResult();
235 aRawData
.setObject(*mJsobj
);
239 FallibleTArray
<uint8_t>& nsUDPMessage::GetDataAsTArray() { return mData
; }
241 //-----------------------------------------------------------------------------
243 //-----------------------------------------------------------------------------
245 nsUDPSocket::nsUDPSocket() {
246 // we want to be able to access the STS directly, and it may not have been
247 // constructed yet. the STS constructor sets gSocketTransportService.
248 if (!gSocketTransportService
) {
249 // This call can fail if we're offline, for example.
250 mozilla::components::SocketTransport::Service();
253 mSts
= gSocketTransportService
;
256 nsUDPSocket::~nsUDPSocket() { CloseSocket(); }
258 void nsUDPSocket::AddOutputBytes(int32_t aBytes
) {
259 mByteWriteCount
+= aBytes
;
260 profiler_count_bandwidth_written_bytes(aBytes
);
263 void nsUDPSocket::OnMsgClose() {
264 UDPSOCKET_LOG(("nsUDPSocket::OnMsgClose [this=%p]\n", this));
266 if (NS_FAILED(mCondition
)) return;
268 // tear down socket. this signals the STS to detach our socket handler.
269 mCondition
= NS_BINDING_ABORTED
;
271 // if we are attached, then socket transport service will call our
272 // OnSocketDetached method automatically. Otherwise, we have to call it
273 // (and thus close the socket) manually.
274 if (!mAttached
) OnSocketDetached(mFD
);
277 void nsUDPSocket::OnMsgAttach() {
278 UDPSOCKET_LOG(("nsUDPSocket::OnMsgAttach [this=%p]\n", this));
280 if (NS_FAILED(mCondition
)) return;
282 mCondition
= TryAttach();
284 // if we hit an error while trying to attach then bail...
285 if (NS_FAILED(mCondition
)) {
286 UDPSOCKET_LOG(("nsUDPSocket::OnMsgAttach: TryAttach FAILED err=0x%" PRIx32
288 static_cast<uint32_t>(mCondition
), this));
289 NS_ASSERTION(!mAttached
, "should not be attached already");
290 OnSocketDetached(mFD
);
294 nsresult
nsUDPSocket::TryAttach() {
297 if (!gSocketTransportService
) return NS_ERROR_FAILURE
;
299 rv
= CheckIOStatus(&mAddr
);
305 // find out if it is going to be ok to attach another socket to the STS.
306 // if not then we have to wait for the STS to tell us that it is ok.
307 // the notification is asynchronous, which means that when we could be
308 // in a race to call AttachSocket once notified. for this reason, when
309 // we get notified, we just re-enter this function. as a result, we are
310 // sure to ask again before calling AttachSocket. in this way we deal
311 // with the race condition. though it isn't the most elegant solution,
312 // it is far simpler than trying to build a system that would guarantee
313 // FIFO ordering (which wouldn't even be that valuable IMO). see bug
314 // 194402 for more info.
316 if (!gSocketTransportService
->CanAttachSocket()) {
317 nsCOMPtr
<nsIRunnable
> event
= NewRunnableMethod(
318 "net::nsUDPSocket::OnMsgAttach", this, &nsUDPSocket::OnMsgAttach
);
320 nsresult rv
= gSocketTransportService
->NotifyWhenCanAttachSocket(event
);
321 if (NS_FAILED(rv
)) return rv
;
325 // ok, we can now attach our socket to the STS for polling
327 rv
= gSocketTransportService
->AttachSocket(mFD
, this);
328 if (NS_FAILED(rv
)) return rv
;
333 // now, configure our poll flags for listening...
335 mPollFlags
= (PR_POLL_READ
| PR_POLL_EXCEPT
);
340 //-----------------------------------------------------------------------------
342 //-----------------------------------------------------------------------------
343 class UDPMessageProxy final
: public nsIUDPMessage
{
345 UDPMessageProxy(NetAddr
* aAddr
, nsIOutputStream
* aOutputStream
,
346 FallibleTArray
<uint8_t>&& aData
)
347 : mOutputStream(aOutputStream
), mData(std::move(aData
)) {
348 memcpy(&mAddr
, aAddr
, sizeof(mAddr
));
351 NS_DECL_THREADSAFE_ISUPPORTS
352 NS_DECL_NSIUDPMESSAGE
355 ~UDPMessageProxy() = default;
358 nsCOMPtr
<nsIOutputStream
> mOutputStream
;
359 FallibleTArray
<uint8_t> mData
;
362 NS_IMPL_ISUPPORTS(UDPMessageProxy
, nsIUDPMessage
)
365 UDPMessageProxy::GetFromAddr(nsINetAddr
** aFromAddr
) {
366 NS_ENSURE_ARG_POINTER(aFromAddr
);
368 nsCOMPtr
<nsINetAddr
> result
= new nsNetAddr(&mAddr
);
369 result
.forget(aFromAddr
);
375 UDPMessageProxy::GetData(nsACString
& aData
) {
376 aData
.Assign(reinterpret_cast<const char*>(mData
.Elements()), mData
.Length());
380 FallibleTArray
<uint8_t>& UDPMessageProxy::GetDataAsTArray() { return mData
; }
383 UDPMessageProxy::GetRawData(JSContext
* cx
,
384 JS::MutableHandle
<JS::Value
> aRawData
) {
385 return NS_ERROR_NOT_IMPLEMENTED
;
389 UDPMessageProxy::GetOutputStream(nsIOutputStream
** aOutputStream
) {
390 NS_ENSURE_ARG_POINTER(aOutputStream
);
391 *aOutputStream
= do_AddRef(mOutputStream
).take();
395 } // anonymous namespace
397 //-----------------------------------------------------------------------------
398 // nsUDPSocket::nsASocketHandler
399 //-----------------------------------------------------------------------------
401 void nsUDPSocket::OnSocketReady(PRFileDesc
* fd
, int16_t outFlags
) {
403 ("nsUDPSocket::OnSocketReady: flags=%d [this=%p]\n", outFlags
, this));
404 NS_ASSERTION(NS_SUCCEEDED(mCondition
), "oops");
405 NS_ASSERTION(mFD
== fd
, "wrong file descriptor");
406 NS_ASSERTION(outFlags
!= -1, "unexpected timeout condition reached");
408 if (outFlags
& (PR_POLL_HUP
| PR_POLL_NVAL
)) {
409 NS_WARNING("error polling on listening socket");
410 mCondition
= NS_ERROR_UNEXPECTED
;
415 mSyncListener
->OnPacketReceived(this);
419 PRNetAddr prClientAddr
;
421 // Bug 1252755 - use 9216 bytes to allign with nICEr and transportlayer to
422 // support the maximum size of jumbo frames
424 count
= PR_RecvFrom(mFD
, buff
, sizeof(buff
), 0, &prClientAddr
,
425 PR_INTERVAL_NO_WAIT
);
428 ("nsUDPSocket::OnSocketReady: PR_RecvFrom failed [this=%p]\n", this));
431 mByteReadCount
+= count
;
432 profiler_count_bandwidth_read_bytes(count
);
434 FallibleTArray
<uint8_t> data
;
435 if (!data
.AppendElements(buff
, count
, fallible
)) {
437 "nsUDPSocket::OnSocketReady: AppendElements FAILED [this=%p]\n", this));
438 mCondition
= NS_ERROR_UNEXPECTED
;
442 nsCOMPtr
<nsIAsyncInputStream
> pipeIn
;
443 nsCOMPtr
<nsIAsyncOutputStream
> pipeOut
;
445 uint32_t segsize
= UDP_PACKET_CHUNK_SIZE
;
446 uint32_t segcount
= 0;
447 net_ResolveSegmentParams(segsize
, segcount
);
448 NS_NewPipe2(getter_AddRefs(pipeIn
), getter_AddRefs(pipeOut
), true, true,
451 RefPtr
<nsUDPOutputStream
> os
= new nsUDPOutputStream(this, mFD
, prClientAddr
);
452 nsresult rv
= NS_AsyncCopy(pipeIn
, os
, mSts
, NS_ASYNCCOPY_VIA_READSEGMENTS
,
453 UDP_PACKET_CHUNK_SIZE
);
459 NetAddr
netAddr(&prClientAddr
);
460 nsCOMPtr
<nsIUDPMessage
> message
=
461 new UDPMessageProxy(&netAddr
, pipeOut
, std::move(data
));
462 mListener
->OnPacketReceived(this, message
);
465 void nsUDPSocket::OnSocketDetached(PRFileDesc
* fd
) {
466 UDPSOCKET_LOG(("nsUDPSocket::OnSocketDetached [this=%p]\n", this));
467 // force a failure condition if none set; maybe the STS is shutting down :-/
468 if (NS_SUCCEEDED(mCondition
)) mCondition
= NS_ERROR_ABORT
;
471 NS_ASSERTION(mFD
== fd
, "wrong file descriptor");
476 mSyncListener
->OnStopListening(this, mCondition
);
477 mSyncListener
= nullptr;
478 } else if (mListener
) {
479 // need to atomically clear mListener. see our Close() method.
480 RefPtr
<nsIUDPSocketListener
> listener
= nullptr;
482 MutexAutoLock
lock(mLock
);
483 listener
= ToRefPtr(std::move(mListener
));
487 listener
->OnStopListening(this, mCondition
);
488 NS_ProxyRelease("nsUDPSocket::mListener", mListenerTarget
,
494 void nsUDPSocket::IsLocal(bool* aIsLocal
) {
495 // If bound to loopback, this UDP socket only accepts local connections.
496 *aIsLocal
= mAddr
.IsLoopbackAddr();
499 nsresult
nsUDPSocket::GetRemoteAddr(NetAddr
* addr
) {
500 if (!mSyncListener
) {
501 return NS_ERROR_FAILURE
;
503 RefPtr
<HttpConnectionUDP
> connUDP
= do_QueryObject(mSyncListener
);
505 return NS_ERROR_FAILURE
;
507 return connUDP
->GetPeerAddr(addr
);
510 //-----------------------------------------------------------------------------
511 // nsSocket::nsISupports
512 //-----------------------------------------------------------------------------
514 NS_IMPL_ISUPPORTS(nsUDPSocket
, nsIUDPSocket
)
516 //-----------------------------------------------------------------------------
517 // nsSocket::nsISocket
518 //-----------------------------------------------------------------------------
521 nsUDPSocket::Init(int32_t aPort
, bool aLoopbackOnly
, nsIPrincipal
* aPrincipal
,
522 bool aAddressReuse
, uint8_t aOptionalArgc
) {
525 if (aPort
< 0) aPort
= 0;
527 addr
.raw
.family
= AF_INET
;
528 addr
.inet
.port
= htons(aPort
);
531 addr
.inet
.ip
= htonl(INADDR_LOOPBACK
);
533 addr
.inet
.ip
= htonl(INADDR_ANY
);
536 return InitWithAddress(&addr
, aPrincipal
, aAddressReuse
, aOptionalArgc
);
540 nsUDPSocket::Init2(const nsACString
& aAddr
, int32_t aPort
,
541 nsIPrincipal
* aPrincipal
, bool aAddressReuse
,
542 uint8_t aOptionalArgc
) {
543 if (NS_WARN_IF(aAddr
.IsEmpty())) {
544 return NS_ERROR_INVALID_ARG
;
552 if (NS_FAILED(addr
.InitFromString(aAddr
, uint16_t(aPort
)))) {
553 return NS_ERROR_FAILURE
;
556 if (addr
.raw
.family
!= PR_AF_INET
&& addr
.raw
.family
!= PR_AF_INET6
) {
557 MOZ_ASSERT_UNREACHABLE("Dont accept address other than IPv4 and IPv6");
558 return NS_ERROR_ILLEGAL_VALUE
;
561 return InitWithAddress(&addr
, aPrincipal
, aAddressReuse
, aOptionalArgc
);
565 nsUDPSocket::InitWithAddress(const NetAddr
* aAddr
, nsIPrincipal
* aPrincipal
,
566 bool aAddressReuse
, uint8_t aOptionalArgc
) {
567 NS_ENSURE_TRUE(mFD
== nullptr, NS_ERROR_ALREADY_INITIALIZED
);
571 rv
= CheckIOStatus(aAddr
);
576 bool addressReuse
= (aOptionalArgc
== 1) ? aAddressReuse
: true;
579 mOriginAttributes
= aPrincipal
->OriginAttributesRef();
582 // configure listening socket...
585 mFD
= PR_OpenUDPSocket(aAddr
->raw
.family
);
587 NS_WARNING("unable to create UDP socket");
588 return NS_ERROR_FAILURE
;
592 if (StaticPrefs::fuzzing_necko_enabled()) {
593 rv
= AttachFuzzyIOLayer(mFD
);
595 UDPSOCKET_LOG(("Failed to attach fuzzing IOLayer [rv=%" PRIx32
"].\n",
596 static_cast<uint32_t>(rv
)));
599 UDPSOCKET_LOG(("Successfully attached fuzzing IOLayer.\n"));
604 if (NS_FAILED(aAddr
->GetPort(&port
))) {
605 NS_WARNING("invalid bind address");
609 PRSocketOptionData opt
;
611 // Linux kernel will sometimes hand out a used port if we bind
612 // to port 0 with SO_REUSEADDR
614 opt
.option
= PR_SockOpt_Reuseaddr
;
615 opt
.value
.reuse_addr
= addressReuse
;
616 PR_SetSocketOption(mFD
, &opt
);
619 opt
.option
= PR_SockOpt_Nonblocking
;
620 opt
.value
.non_blocking
= true;
621 PR_SetSocketOption(mFD
, &opt
);
624 // Temporary work around for IPv6 until bug 1330490 is fixed
625 memset(&addr
, 0, sizeof(addr
));
626 NetAddrToPRNetAddr(aAddr
, &addr
);
628 if (PR_Bind(mFD
, &addr
) != PR_SUCCESS
) {
629 NS_WARNING("failed to bind socket");
633 // get the resulting socket address, which may be different than what
634 // we passed to bind.
635 if (PR_GetSockName(mFD
, &addr
) != PR_SUCCESS
) {
636 NS_WARNING("cannot get socket name");
640 PRNetAddrToNetAddr(&addr
, &mAddr
);
642 // wait until AsyncListen is called before polling the socket for
643 // client connections.
648 return NS_ERROR_FAILURE
;
652 nsUDPSocket::Connect(const NetAddr
* aAddr
) {
653 UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
655 NS_ENSURE_ARG(aAddr
);
657 if (NS_WARN_IF(!mFD
)) {
658 return NS_ERROR_NOT_INITIALIZED
;
663 rv
= CheckIOStatus(aAddr
);
668 bool onSTSThread
= false;
669 mSts
->IsOnCurrentThread(&onSTSThread
);
670 NS_ASSERTION(onSTSThread
, "NOT ON STS THREAD");
672 return NS_ERROR_FAILURE
;
676 memset(&prAddr
, 0, sizeof(prAddr
));
677 NetAddrToPRNetAddr(aAddr
, &prAddr
);
679 if (PR_Connect(mFD
, &prAddr
, PR_INTERVAL_NO_WAIT
) != PR_SUCCESS
) {
680 NS_WARNING("Cannot PR_Connect");
681 return NS_ERROR_FAILURE
;
683 PR_SetFDInheritable(mFD
, false);
685 // get the resulting socket address, which may have been updated.
687 if (PR_GetSockName(mFD
, &addr
) != PR_SUCCESS
) {
688 NS_WARNING("cannot get socket name");
689 return NS_ERROR_FAILURE
;
692 PRNetAddrToNetAddr(&addr
, &mAddr
);
698 nsUDPSocket::Close() {
700 MutexAutoLock
lock(mLock
);
701 // we want to proxy the close operation to the socket thread if a listener
702 // has been set. otherwise, we should just close the socket here...
703 if (!mListener
&& !mSyncListener
) {
704 // Here we want to go directly with closing the socket since some tests
705 // expects this happen synchronously.
711 return PostEvent(this, &nsUDPSocket::OnMsgClose
);
715 nsUDPSocket::GetPort(int32_t* aResult
) {
716 // no need to enter the lock here
718 nsresult rv
= mAddr
.GetPort(&result
);
719 *aResult
= static_cast<int32_t>(result
);
724 nsUDPSocket::GetLocalAddr(nsINetAddr
** aResult
) {
725 NS_ENSURE_ARG_POINTER(aResult
);
727 nsCOMPtr
<nsINetAddr
> result
= new nsNetAddr(&mAddr
);
728 result
.forget(aResult
);
733 void nsUDPSocket::CloseSocket() {
735 if (gIOService
->IsNetTearingDown() &&
736 ((PR_IntervalNow() - gIOService
->NetTearingDownStarted()) >
737 gSocketTransportService
->MaxTimeForPrClosePref())) {
738 // If shutdown last to long, let the socket leak and do not close it.
739 UDPSOCKET_LOG(("Intentional leak"));
741 PRIntervalTime closeStarted
= 0;
742 if (gSocketTransportService
->IsTelemetryEnabledAndNotSleepPhase()) {
743 closeStarted
= PR_IntervalNow();
748 if (gSocketTransportService
->IsTelemetryEnabledAndNotSleepPhase()) {
749 PRIntervalTime now
= PR_IntervalNow();
750 if (gIOService
->IsNetTearingDown()) {
751 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN
,
752 PR_IntervalToMilliseconds(now
- closeStarted
));
754 } else if (PR_IntervalToSeconds(
755 now
- gIOService
->LastConnectivityChange()) < 60) {
756 Telemetry::Accumulate(
757 Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE
,
758 PR_IntervalToMilliseconds(now
- closeStarted
));
760 } else if (PR_IntervalToSeconds(
761 now
- gIOService
->LastNetworkLinkChange()) < 60) {
762 Telemetry::Accumulate(
763 Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE
,
764 PR_IntervalToMilliseconds(now
- closeStarted
));
766 } else if (PR_IntervalToSeconds(
767 now
- gIOService
->LastOfflineStateChange()) < 60) {
768 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE
,
769 PR_IntervalToMilliseconds(now
- closeStarted
));
772 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL
,
773 PR_IntervalToMilliseconds(now
- closeStarted
));
782 nsUDPSocket::GetAddress(NetAddr
* aResult
) {
783 // no need to enter the lock here
784 memcpy(aResult
, &mAddr
, sizeof(mAddr
));
789 //-----------------------------------------------------------------------------
790 // SocketListenerProxy
791 //-----------------------------------------------------------------------------
792 class SocketListenerProxy final
: public nsIUDPSocketListener
{
793 ~SocketListenerProxy() = default;
796 explicit SocketListenerProxy(nsIUDPSocketListener
* aListener
)
797 : mListener(new nsMainThreadPtrHolder
<nsIUDPSocketListener
>(
798 "SocketListenerProxy::mListener", aListener
)),
799 mTarget(GetCurrentSerialEventTarget()) {}
801 NS_DECL_THREADSAFE_ISUPPORTS
802 NS_DECL_NSIUDPSOCKETLISTENER
804 class OnPacketReceivedRunnable
: public Runnable
{
806 OnPacketReceivedRunnable(
807 const nsMainThreadPtrHandle
<nsIUDPSocketListener
>& aListener
,
808 nsIUDPSocket
* aSocket
, nsIUDPMessage
* aMessage
)
809 : Runnable("net::SocketListenerProxy::OnPacketReceivedRunnable"),
810 mListener(aListener
),
812 mMessage(aMessage
) {}
817 nsMainThreadPtrHandle
<nsIUDPSocketListener
> mListener
;
818 nsCOMPtr
<nsIUDPSocket
> mSocket
;
819 nsCOMPtr
<nsIUDPMessage
> mMessage
;
822 class OnStopListeningRunnable
: public Runnable
{
824 OnStopListeningRunnable(
825 const nsMainThreadPtrHandle
<nsIUDPSocketListener
>& aListener
,
826 nsIUDPSocket
* aSocket
, nsresult aStatus
)
827 : Runnable("net::SocketListenerProxy::OnStopListeningRunnable"),
828 mListener(aListener
),
835 nsMainThreadPtrHandle
<nsIUDPSocketListener
> mListener
;
836 nsCOMPtr
<nsIUDPSocket
> mSocket
;
841 nsMainThreadPtrHandle
<nsIUDPSocketListener
> mListener
;
842 nsCOMPtr
<nsIEventTarget
> mTarget
;
845 NS_IMPL_ISUPPORTS(SocketListenerProxy
, nsIUDPSocketListener
)
848 SocketListenerProxy::OnPacketReceived(nsIUDPSocket
* aSocket
,
849 nsIUDPMessage
* aMessage
) {
850 RefPtr
<OnPacketReceivedRunnable
> r
=
851 new OnPacketReceivedRunnable(mListener
, aSocket
, aMessage
);
852 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
856 SocketListenerProxy::OnStopListening(nsIUDPSocket
* aSocket
, nsresult aStatus
) {
857 RefPtr
<OnStopListeningRunnable
> r
=
858 new OnStopListeningRunnable(mListener
, aSocket
, aStatus
);
859 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
863 SocketListenerProxy::OnPacketReceivedRunnable::Run() {
865 nsCOMPtr
<nsINetAddr
> nsAddr
;
866 mMessage
->GetFromAddr(getter_AddRefs(nsAddr
));
867 nsAddr
->GetNetAddr(&netAddr
);
869 nsCOMPtr
<nsIOutputStream
> outputStream
;
870 mMessage
->GetOutputStream(getter_AddRefs(outputStream
));
872 FallibleTArray
<uint8_t>& data
= mMessage
->GetDataAsTArray();
874 nsCOMPtr
<nsIUDPMessage
> message
=
875 new nsUDPMessage(&netAddr
, outputStream
, std::move(data
));
876 mListener
->OnPacketReceived(mSocket
, message
);
881 SocketListenerProxy::OnStopListeningRunnable::Run() {
882 mListener
->OnStopListening(mSocket
, mStatus
);
886 class SocketListenerProxyBackground final
: public nsIUDPSocketListener
{
887 ~SocketListenerProxyBackground() = default;
890 explicit SocketListenerProxyBackground(nsIUDPSocketListener
* aListener
)
891 : mListener(aListener
), mTarget(GetCurrentSerialEventTarget()) {}
893 NS_DECL_THREADSAFE_ISUPPORTS
894 NS_DECL_NSIUDPSOCKETLISTENER
896 class OnPacketReceivedRunnable
: public Runnable
{
898 OnPacketReceivedRunnable(const nsCOMPtr
<nsIUDPSocketListener
>& aListener
,
899 nsIUDPSocket
* aSocket
, nsIUDPMessage
* aMessage
)
901 "net::SocketListenerProxyBackground::OnPacketReceivedRunnable"),
902 mListener(aListener
),
904 mMessage(aMessage
) {}
909 nsCOMPtr
<nsIUDPSocketListener
> mListener
;
910 nsCOMPtr
<nsIUDPSocket
> mSocket
;
911 nsCOMPtr
<nsIUDPMessage
> mMessage
;
914 class OnStopListeningRunnable
: public Runnable
{
916 OnStopListeningRunnable(const nsCOMPtr
<nsIUDPSocketListener
>& aListener
,
917 nsIUDPSocket
* aSocket
, nsresult aStatus
)
919 "net::SocketListenerProxyBackground::OnStopListeningRunnable"),
920 mListener(aListener
),
927 nsCOMPtr
<nsIUDPSocketListener
> mListener
;
928 nsCOMPtr
<nsIUDPSocket
> mSocket
;
933 nsCOMPtr
<nsIUDPSocketListener
> mListener
;
934 nsCOMPtr
<nsIEventTarget
> mTarget
;
937 NS_IMPL_ISUPPORTS(SocketListenerProxyBackground
, nsIUDPSocketListener
)
940 SocketListenerProxyBackground::OnPacketReceived(nsIUDPSocket
* aSocket
,
941 nsIUDPMessage
* aMessage
) {
942 RefPtr
<OnPacketReceivedRunnable
> r
=
943 new OnPacketReceivedRunnable(mListener
, aSocket
, aMessage
);
944 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
948 SocketListenerProxyBackground::OnStopListening(nsIUDPSocket
* aSocket
,
950 RefPtr
<OnStopListeningRunnable
> r
=
951 new OnStopListeningRunnable(mListener
, aSocket
, aStatus
);
952 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
956 SocketListenerProxyBackground::OnPacketReceivedRunnable::Run() {
958 nsCOMPtr
<nsINetAddr
> nsAddr
;
959 mMessage
->GetFromAddr(getter_AddRefs(nsAddr
));
960 nsAddr
->GetNetAddr(&netAddr
);
962 nsCOMPtr
<nsIOutputStream
> outputStream
;
963 mMessage
->GetOutputStream(getter_AddRefs(outputStream
));
965 FallibleTArray
<uint8_t>& data
= mMessage
->GetDataAsTArray();
967 UDPSOCKET_LOG(("%s [this=%p], len %zu", __FUNCTION__
, this, data
.Length()));
968 nsCOMPtr
<nsIUDPMessage
> message
=
969 new UDPMessageProxy(&netAddr
, outputStream
, std::move(data
));
970 mListener
->OnPacketReceived(mSocket
, message
);
975 SocketListenerProxyBackground::OnStopListeningRunnable::Run() {
976 mListener
->OnStopListening(mSocket
, mStatus
);
980 class PendingSend
: public nsIDNSListener
{
982 NS_DECL_THREADSAFE_ISUPPORTS
983 NS_DECL_NSIDNSLISTENER
985 PendingSend(nsUDPSocket
* aSocket
, uint16_t aPort
,
986 FallibleTArray
<uint8_t>&& aData
)
987 : mSocket(aSocket
), mPort(aPort
), mData(std::move(aData
)) {}
990 virtual ~PendingSend() = default;
992 RefPtr
<nsUDPSocket
> mSocket
;
994 FallibleTArray
<uint8_t> mData
;
997 NS_IMPL_ISUPPORTS(PendingSend
, nsIDNSListener
)
1000 PendingSend::OnLookupComplete(nsICancelable
* request
, nsIDNSRecord
* aRecord
,
1002 if (NS_FAILED(status
)) {
1003 NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
1007 nsCOMPtr
<nsIDNSAddrRecord
> rec
= do_QueryInterface(aRecord
);
1010 if (NS_SUCCEEDED(rec
->GetNextAddr(mPort
, &addr
))) {
1012 nsresult rv
= mSocket
->SendWithAddress(&addr
, mData
.Elements(),
1013 mData
.Length(), &count
);
1014 NS_ENSURE_SUCCESS(rv
, rv
);
1020 class PendingSendStream
: public nsIDNSListener
{
1022 NS_DECL_THREADSAFE_ISUPPORTS
1023 NS_DECL_NSIDNSLISTENER
1025 PendingSendStream(nsUDPSocket
* aSocket
, uint16_t aPort
,
1026 nsIInputStream
* aStream
)
1027 : mSocket(aSocket
), mPort(aPort
), mStream(aStream
) {}
1030 virtual ~PendingSendStream() = default;
1032 RefPtr
<nsUDPSocket
> mSocket
;
1034 nsCOMPtr
<nsIInputStream
> mStream
;
1037 NS_IMPL_ISUPPORTS(PendingSendStream
, nsIDNSListener
)
1040 PendingSendStream::OnLookupComplete(nsICancelable
* request
,
1041 nsIDNSRecord
* aRecord
, nsresult status
) {
1042 if (NS_FAILED(status
)) {
1043 NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
1047 nsCOMPtr
<nsIDNSAddrRecord
> rec
= do_QueryInterface(aRecord
);
1050 if (NS_SUCCEEDED(rec
->GetNextAddr(mPort
, &addr
))) {
1051 nsresult rv
= mSocket
->SendBinaryStreamWithAddress(&addr
, mStream
);
1052 NS_ENSURE_SUCCESS(rv
, rv
);
1058 class SendRequestRunnable
: public Runnable
{
1060 SendRequestRunnable(nsUDPSocket
* aSocket
, const NetAddr
& aAddr
,
1061 FallibleTArray
<uint8_t>&& aData
)
1062 : Runnable("net::SendRequestRunnable"),
1065 mData(std::move(aData
)) {}
1070 RefPtr
<nsUDPSocket
> mSocket
;
1071 const NetAddr mAddr
;
1072 FallibleTArray
<uint8_t> mData
;
1076 SendRequestRunnable::Run() {
1078 mSocket
->SendWithAddress(&mAddr
, mData
.Elements(), mData
.Length(), &count
);
1085 nsUDPSocket::AsyncListen(nsIUDPSocketListener
* aListener
) {
1086 // ensuring mFD implies ensuring mLock
1087 NS_ENSURE_TRUE(mFD
, NS_ERROR_NOT_INITIALIZED
);
1088 NS_ENSURE_TRUE(mListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1089 NS_ENSURE_TRUE(mSyncListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1091 MutexAutoLock
lock(mLock
);
1092 mListenerTarget
= GetCurrentSerialEventTarget();
1093 if (NS_IsMainThread()) {
1095 mListener
= new SocketListenerProxy(aListener
);
1097 // PBackground usage from dom/media/webrtc/transport
1098 mListener
= new SocketListenerProxyBackground(aListener
);
1101 return PostEvent(this, &nsUDPSocket::OnMsgAttach
);
1105 nsUDPSocket::SyncListen(nsIUDPSocketSyncListener
* aListener
) {
1106 // ensuring mFD implies ensuring mLock
1107 NS_ENSURE_TRUE(mFD
, NS_ERROR_NOT_INITIALIZED
);
1108 NS_ENSURE_TRUE(mListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1109 NS_ENSURE_TRUE(mSyncListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1111 mSyncListener
= aListener
;
1113 return PostEvent(this, &nsUDPSocket::OnMsgAttach
);
1117 nsUDPSocket::Send(const nsACString
& aHost
, uint16_t aPort
,
1118 const nsTArray
<uint8_t>& aData
, uint32_t* _retval
) {
1119 NS_ENSURE_ARG_POINTER(_retval
);
1123 FallibleTArray
<uint8_t> fallibleArray
;
1124 if (!fallibleArray
.InsertElementsAt(0, aData
, fallible
)) {
1125 return NS_ERROR_OUT_OF_MEMORY
;
1128 nsCOMPtr
<nsIDNSListener
> listener
=
1129 new PendingSend(this, aPort
, std::move(fallibleArray
));
1131 nsresult rv
= ResolveHost(aHost
, mOriginAttributes
, listener
);
1132 NS_ENSURE_SUCCESS(rv
, rv
);
1134 *_retval
= aData
.Length();
1139 nsUDPSocket::SendWithAddr(nsINetAddr
* aAddr
, const nsTArray
<uint8_t>& aData
,
1140 uint32_t* _retval
) {
1141 NS_ENSURE_ARG(aAddr
);
1142 NS_ENSURE_ARG_POINTER(_retval
);
1145 aAddr
->GetNetAddr(&netAddr
);
1146 return SendWithAddress(&netAddr
, aData
.Elements(), aData
.Length(), _retval
);
1150 nsUDPSocket::SendWithAddress(const NetAddr
* aAddr
, const uint8_t* aData
,
1151 uint32_t aLength
, uint32_t* _retval
) {
1152 NS_ENSURE_ARG(aAddr
);
1153 NS_ENSURE_ARG_POINTER(_retval
);
1155 if (StaticPrefs::network_http_http3_block_loopback_ipv6_addr() &&
1156 aAddr
->raw
.family
== AF_INET6
&& aAddr
->IsLoopbackAddr()) {
1157 return NS_ERROR_CONNECTION_REFUSED
;
1163 NetAddrToPRNetAddr(aAddr
, &prAddr
);
1165 bool onSTSThread
= false;
1166 mSts
->IsOnCurrentThread(&onSTSThread
);
1169 MutexAutoLock
lock(mLock
);
1171 // socket is not initialized or has been closed
1172 return NS_ERROR_FAILURE
;
1175 PR_SendTo(mFD
, aData
, aLength
, 0, &prAddr
, PR_INTERVAL_NO_WAIT
);
1177 PRErrorCode code
= PR_GetError();
1178 return ErrorAccordingToNSPR(code
);
1180 this->AddOutputBytes(count
);
1183 FallibleTArray
<uint8_t> fallibleArray
;
1184 if (!fallibleArray
.AppendElements(aData
, aLength
, fallible
)) {
1185 return NS_ERROR_OUT_OF_MEMORY
;
1188 nsresult rv
= mSts
->Dispatch(
1189 new SendRequestRunnable(this, *aAddr
, std::move(fallibleArray
)),
1190 NS_DISPATCH_NORMAL
);
1191 NS_ENSURE_SUCCESS(rv
, rv
);
1198 nsUDPSocket::SendBinaryStream(const nsACString
& aHost
, uint16_t aPort
,
1199 nsIInputStream
* aStream
) {
1200 NS_ENSURE_ARG(aStream
);
1202 nsCOMPtr
<nsIDNSListener
> listener
=
1203 new PendingSendStream(this, aPort
, aStream
);
1205 return ResolveHost(aHost
, mOriginAttributes
, listener
);
1209 nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr
* aAddr
,
1210 nsIInputStream
* aStream
) {
1211 NS_ENSURE_ARG(aAddr
);
1212 NS_ENSURE_ARG(aStream
);
1215 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prAddr
);
1216 NetAddrToPRNetAddr(aAddr
, &prAddr
);
1218 RefPtr
<nsUDPOutputStream
> os
= new nsUDPOutputStream(this, mFD
, prAddr
);
1219 return NS_AsyncCopy(aStream
, os
, mSts
, NS_ASYNCCOPY_VIA_READSEGMENTS
,
1220 UDP_PACKET_CHUNK_SIZE
);
1224 nsUDPSocket::RecvWithAddr(NetAddr
* addr
, nsTArray
<uint8_t>& aData
) {
1225 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1229 count
= PR_RecvFrom(mFD
, buff
, sizeof(buff
), 0, &prAddr
, PR_INTERVAL_NO_WAIT
);
1232 ("nsUDPSocket::RecvWithAddr: PR_RecvFrom failed [this=%p]\n", this));
1235 mByteReadCount
+= count
;
1236 profiler_count_bandwidth_read_bytes(count
);
1237 PRNetAddrToNetAddr(&prAddr
, addr
);
1239 if (!aData
.AppendElements(buff
, count
, fallible
)) {
1241 "nsUDPSocket::OnSocketReady: AppendElements FAILED [this=%p]\n", this));
1242 mCondition
= NS_ERROR_UNEXPECTED
;
1247 nsresult
nsUDPSocket::SetSocketOption(const PRSocketOptionData
& aOpt
) {
1248 bool onSTSThread
= false;
1249 mSts
->IsOnCurrentThread(&onSTSThread
);
1252 // Dispatch to STS thread and re-enter this method there
1253 nsCOMPtr
<nsIRunnable
> runnable
= new SetSocketOptionRunnable(this, aOpt
);
1254 nsresult rv
= mSts
->Dispatch(runnable
, NS_DISPATCH_NORMAL
);
1255 if (NS_WARN_IF(NS_FAILED(rv
))) {
1261 if (NS_WARN_IF(!mFD
)) {
1262 return NS_ERROR_NOT_INITIALIZED
;
1265 if (PR_SetSocketOption(mFD
, &aOpt
) != PR_SUCCESS
) {
1267 ("nsUDPSocket::SetSocketOption [this=%p] failed for type %d, "
1269 this, aOpt
.option
, PR_GetError()));
1270 return NS_ERROR_FAILURE
;
1277 nsUDPSocket::JoinMulticast(const nsACString
& aAddr
, const nsACString
& aIface
) {
1278 if (NS_WARN_IF(aAddr
.IsEmpty())) {
1279 return NS_ERROR_INVALID_ARG
;
1281 if (NS_WARN_IF(!mFD
)) {
1282 return NS_ERROR_NOT_INITIALIZED
;
1286 if (PR_StringToNetAddr(aAddr
.BeginReading(), &prAddr
) != PR_SUCCESS
) {
1287 return NS_ERROR_FAILURE
;
1291 if (aIface
.IsEmpty()) {
1292 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1294 if (PR_StringToNetAddr(aIface
.BeginReading(), &prIface
) != PR_SUCCESS
) {
1295 return NS_ERROR_FAILURE
;
1299 return JoinMulticastInternal(prAddr
, prIface
);
1303 nsUDPSocket::JoinMulticastAddr(const NetAddr aAddr
, const NetAddr
* aIface
) {
1304 if (NS_WARN_IF(!mFD
)) {
1305 return NS_ERROR_NOT_INITIALIZED
;
1309 NetAddrToPRNetAddr(&aAddr
, &prAddr
);
1313 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1315 NetAddrToPRNetAddr(aIface
, &prIface
);
1318 return JoinMulticastInternal(prAddr
, prIface
);
1321 nsresult
nsUDPSocket::JoinMulticastInternal(const PRNetAddr
& aAddr
,
1322 const PRNetAddr
& aIface
) {
1323 PRSocketOptionData opt
;
1325 opt
.option
= PR_SockOpt_AddMember
;
1326 opt
.value
.add_member
.mcaddr
= aAddr
;
1327 opt
.value
.add_member
.ifaddr
= aIface
;
1329 nsresult rv
= SetSocketOption(opt
);
1330 if (NS_WARN_IF(NS_FAILED(rv
))) {
1331 return NS_ERROR_FAILURE
;
1338 nsUDPSocket::LeaveMulticast(const nsACString
& aAddr
, const nsACString
& aIface
) {
1339 if (NS_WARN_IF(aAddr
.IsEmpty())) {
1340 return NS_ERROR_INVALID_ARG
;
1342 if (NS_WARN_IF(!mFD
)) {
1343 return NS_ERROR_NOT_INITIALIZED
;
1347 if (PR_StringToNetAddr(aAddr
.BeginReading(), &prAddr
) != PR_SUCCESS
) {
1348 return NS_ERROR_FAILURE
;
1352 if (aIface
.IsEmpty()) {
1353 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1355 if (PR_StringToNetAddr(aIface
.BeginReading(), &prIface
) != PR_SUCCESS
) {
1356 return NS_ERROR_FAILURE
;
1360 return LeaveMulticastInternal(prAddr
, prIface
);
1364 nsUDPSocket::LeaveMulticastAddr(const NetAddr aAddr
, const NetAddr
* aIface
) {
1365 if (NS_WARN_IF(!mFD
)) {
1366 return NS_ERROR_NOT_INITIALIZED
;
1370 NetAddrToPRNetAddr(&aAddr
, &prAddr
);
1374 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1376 NetAddrToPRNetAddr(aIface
, &prIface
);
1379 return LeaveMulticastInternal(prAddr
, prIface
);
1382 nsresult
nsUDPSocket::LeaveMulticastInternal(const PRNetAddr
& aAddr
,
1383 const PRNetAddr
& aIface
) {
1384 PRSocketOptionData opt
;
1386 opt
.option
= PR_SockOpt_DropMember
;
1387 opt
.value
.drop_member
.mcaddr
= aAddr
;
1388 opt
.value
.drop_member
.ifaddr
= aIface
;
1390 nsresult rv
= SetSocketOption(opt
);
1391 if (NS_WARN_IF(NS_FAILED(rv
))) {
1392 return NS_ERROR_FAILURE
;
1399 nsUDPSocket::GetMulticastLoopback(bool* aLoopback
) {
1400 return NS_ERROR_NOT_IMPLEMENTED
;
1404 nsUDPSocket::SetMulticastLoopback(bool aLoopback
) {
1405 if (NS_WARN_IF(!mFD
)) {
1406 return NS_ERROR_NOT_INITIALIZED
;
1409 PRSocketOptionData opt
;
1411 opt
.option
= PR_SockOpt_McastLoopback
;
1412 opt
.value
.mcast_loopback
= aLoopback
;
1414 nsresult rv
= SetSocketOption(opt
);
1415 if (NS_WARN_IF(NS_FAILED(rv
))) {
1416 return NS_ERROR_FAILURE
;
1423 nsUDPSocket::GetRecvBufferSize(int* size
) {
1424 // Bug 1252759 - missing support for GetSocketOption
1425 return NS_ERROR_NOT_IMPLEMENTED
;
1429 nsUDPSocket::SetRecvBufferSize(int size
) {
1430 if (NS_WARN_IF(!mFD
)) {
1431 return NS_ERROR_NOT_INITIALIZED
;
1434 PRSocketOptionData opt
;
1436 opt
.option
= PR_SockOpt_RecvBufferSize
;
1437 opt
.value
.recv_buffer_size
= size
;
1439 nsresult rv
= SetSocketOption(opt
);
1440 if (NS_WARN_IF(NS_FAILED(rv
))) {
1441 return NS_ERROR_FAILURE
;
1448 nsUDPSocket::GetDontFragment(bool* dontFragment
) {
1449 // Bug 1252759 - missing support for GetSocketOption
1450 return NS_ERROR_NOT_IMPLEMENTED
;
1454 nsUDPSocket::SetDontFragment(bool dontFragment
) {
1455 if (NS_WARN_IF(!mFD
)) {
1456 return NS_ERROR_NOT_INITIALIZED
;
1459 PRSocketOptionData opt
;
1460 opt
.option
= PR_SockOpt_DontFrag
;
1461 opt
.value
.dont_fragment
= dontFragment
;
1463 nsresult rv
= SetSocketOption(opt
);
1464 if (NS_WARN_IF(NS_FAILED(rv
))) {
1465 return NS_ERROR_FAILURE
;
1471 nsUDPSocket::GetSendBufferSize(int* size
) {
1472 // Bug 1252759 - missing support for GetSocketOption
1473 return NS_ERROR_NOT_IMPLEMENTED
;
1477 nsUDPSocket::SetSendBufferSize(int size
) {
1478 if (NS_WARN_IF(!mFD
)) {
1479 return NS_ERROR_NOT_INITIALIZED
;
1482 PRSocketOptionData opt
;
1484 opt
.option
= PR_SockOpt_SendBufferSize
;
1485 opt
.value
.send_buffer_size
= size
;
1487 nsresult rv
= SetSocketOption(opt
);
1488 if (NS_WARN_IF(NS_FAILED(rv
))) {
1489 return NS_ERROR_FAILURE
;
1496 nsUDPSocket::GetMulticastInterface(nsACString
& aIface
) {
1497 return NS_ERROR_NOT_IMPLEMENTED
;
1501 nsUDPSocket::GetMulticastInterfaceAddr(NetAddr
* aIface
) {
1502 return NS_ERROR_NOT_IMPLEMENTED
;
1506 nsUDPSocket::SetMulticastInterface(const nsACString
& aIface
) {
1507 if (NS_WARN_IF(!mFD
)) {
1508 return NS_ERROR_NOT_INITIALIZED
;
1512 if (aIface
.IsEmpty()) {
1513 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1515 if (PR_StringToNetAddr(aIface
.BeginReading(), &prIface
) != PR_SUCCESS
) {
1516 return NS_ERROR_FAILURE
;
1520 return SetMulticastInterfaceInternal(prIface
);
1524 nsUDPSocket::SetMulticastInterfaceAddr(NetAddr aIface
) {
1525 if (NS_WARN_IF(!mFD
)) {
1526 return NS_ERROR_NOT_INITIALIZED
;
1530 NetAddrToPRNetAddr(&aIface
, &prIface
);
1532 return SetMulticastInterfaceInternal(prIface
);
1535 nsresult
nsUDPSocket::SetMulticastInterfaceInternal(const PRNetAddr
& aIface
) {
1536 PRSocketOptionData opt
;
1538 opt
.option
= PR_SockOpt_McastInterface
;
1539 opt
.value
.mcast_if
= aIface
;
1541 nsresult rv
= SetSocketOption(opt
);
1542 if (NS_WARN_IF(NS_FAILED(rv
))) {
1543 return NS_ERROR_FAILURE
;
1550 } // namespace mozilla