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/. */
6 #include "mozilla/Attributes.h"
7 #include "mozilla/EndianUtils.h"
8 #include "mozilla/dom/TypedArray.h"
9 #include "mozilla/HoldDropJSObjects.h"
10 #include "mozilla/Telemetry.h"
12 #include "nsQueryObject.h"
13 #include "nsSocketTransport2.h"
14 #include "nsUDPSocket.h"
15 #include "nsProxyRelease.h"
18 #include "nsNetUtil.h"
19 #include "nsIOService.h"
22 #include "nsNetAddr.h"
23 #include "nsNetSegmentUtils.h"
24 #include "IOActivityMonitor.h"
25 #include "nsServiceManagerUtils.h"
26 #include "nsStreamUtils.h"
28 #include "nsThreadUtils.h"
29 #include "nsIDNSRecord.h"
30 #include "nsIDNSService.h"
31 #include "nsICancelable.h"
33 #include "nsWrapperCacheInlines.h"
34 #include "HttpConnectionUDP.h"
35 #include "mozilla/ProfilerBandwidthCounter.h"
36 #include "mozilla/StaticPrefs_network.h"
39 # include "FuzzyLayer.h"
40 # include "mozilla/StaticPrefs_fuzzing.h"
46 static const uint32_t UDP_PACKET_CHUNK_SIZE
= 1400;
48 //-----------------------------------------------------------------------------
50 using nsUDPSocketFunc
= void (nsUDPSocket::*)();
52 static nsresult
PostEvent(nsUDPSocket
* s
, nsUDPSocketFunc func
) {
53 if (!gSocketTransportService
) return NS_ERROR_FAILURE
;
55 return gSocketTransportService
->Dispatch(
56 NewRunnableMethod("net::PostEvent", s
, func
), NS_DISPATCH_NORMAL
);
59 static nsresult
ResolveHost(const nsACString
& host
,
60 const OriginAttributes
& aOriginAttributes
,
61 nsIDNSListener
* listener
) {
64 nsCOMPtr
<nsIDNSService
> dns
=
65 do_GetService("@mozilla.org/network/dns-service;1", &rv
);
70 nsCOMPtr
<nsICancelable
> tmpOutstanding
;
71 return dns
->AsyncResolveNative(host
, nsIDNSService::RESOLVE_TYPE_DEFAULT
,
72 nsIDNSService::RESOLVE_DEFAULT_FLAGS
, nullptr,
73 listener
, nullptr, aOriginAttributes
,
74 getter_AddRefs(tmpOutstanding
));
77 static nsresult
CheckIOStatus(const NetAddr
* aAddr
) {
78 MOZ_ASSERT(gIOService
);
80 if (gIOService
->IsNetTearingDown()) {
81 return NS_ERROR_FAILURE
;
84 if (gIOService
->IsOffline() &&
85 (StaticPrefs::network_disable_localhost_when_offline() ||
86 !aAddr
->IsLoopbackAddr())) {
87 return NS_ERROR_OFFLINE
;
93 //-----------------------------------------------------------------------------
95 class SetSocketOptionRunnable
: public Runnable
{
97 SetSocketOptionRunnable(nsUDPSocket
* aSocket
, const PRSocketOptionData
& aOpt
)
98 : Runnable("net::SetSocketOptionRunnable"),
102 NS_IMETHOD
Run() override
{ return mSocket
->SetSocketOption(mOpt
); }
105 RefPtr
<nsUDPSocket
> mSocket
;
106 PRSocketOptionData mOpt
;
109 //-----------------------------------------------------------------------------
110 // nsUDPOutputStream impl
111 //-----------------------------------------------------------------------------
112 NS_IMPL_ISUPPORTS(nsUDPOutputStream
, nsIOutputStream
)
114 nsUDPOutputStream::nsUDPOutputStream(nsUDPSocket
* aSocket
, PRFileDesc
* aFD
,
115 PRNetAddr
& aPrClientAddr
)
118 mPrClientAddr(aPrClientAddr
),
121 NS_IMETHODIMP
nsUDPOutputStream::Close() {
122 if (mIsClosed
) return NS_BASE_STREAM_CLOSED
;
128 NS_IMETHODIMP
nsUDPOutputStream::Flush() { return NS_OK
; }
130 NS_IMETHODIMP
nsUDPOutputStream::StreamStatus() {
131 return mIsClosed
? NS_BASE_STREAM_CLOSED
: NS_OK
;
134 NS_IMETHODIMP
nsUDPOutputStream::Write(const char* aBuf
, uint32_t aCount
,
136 if (mIsClosed
) return NS_BASE_STREAM_CLOSED
;
140 PR_SendTo(mFD
, aBuf
, aCount
, 0, &mPrClientAddr
, PR_INTERVAL_NO_WAIT
);
142 PRErrorCode code
= PR_GetError();
143 return ErrorAccordingToNSPR(code
);
148 mSocket
->AddOutputBytes(count
);
153 NS_IMETHODIMP
nsUDPOutputStream::WriteFrom(nsIInputStream
* aFromStream
,
154 uint32_t aCount
, uint32_t* _retval
) {
155 return NS_ERROR_NOT_IMPLEMENTED
;
158 NS_IMETHODIMP
nsUDPOutputStream::WriteSegments(nsReadSegmentFun aReader
,
159 void* aClosure
, uint32_t aCount
,
161 return NS_ERROR_NOT_IMPLEMENTED
;
164 NS_IMETHODIMP
nsUDPOutputStream::IsNonBlocking(bool* _retval
) {
169 //-----------------------------------------------------------------------------
171 //-----------------------------------------------------------------------------
172 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsUDPMessage
)
173 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsUDPMessage
)
175 NS_IMPL_CYCLE_COLLECTION_CLASS(nsUDPMessage
)
177 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsUDPMessage
)
178 NS_INTERFACE_MAP_ENTRY(nsISupports
)
179 NS_INTERFACE_MAP_ENTRY(nsIUDPMessage
)
182 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsUDPMessage
)
183 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsobj
)
184 NS_IMPL_CYCLE_COLLECTION_TRACE_END
186 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsUDPMessage
)
187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
189 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsUDPMessage
)
190 tmp
->mJsobj
= nullptr;
191 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
193 nsUDPMessage::nsUDPMessage(NetAddr
* aAddr
, nsIOutputStream
* aOutputStream
,
194 FallibleTArray
<uint8_t>&& aData
)
195 : mOutputStream(aOutputStream
), mData(std::move(aData
)) {
196 memcpy(&mAddr
, aAddr
, sizeof(NetAddr
));
199 nsUDPMessage::~nsUDPMessage() { DropJSObjects(this); }
202 nsUDPMessage::GetFromAddr(nsINetAddr
** aFromAddr
) {
203 NS_ENSURE_ARG_POINTER(aFromAddr
);
205 nsCOMPtr
<nsINetAddr
> result
= new nsNetAddr(&mAddr
);
206 result
.forget(aFromAddr
);
212 nsUDPMessage::GetData(nsACString
& aData
) {
213 aData
.Assign(reinterpret_cast<const char*>(mData
.Elements()), mData
.Length());
218 nsUDPMessage::GetOutputStream(nsIOutputStream
** aOutputStream
) {
219 NS_ENSURE_ARG_POINTER(aOutputStream
);
220 *aOutputStream
= do_AddRef(mOutputStream
).take();
225 nsUDPMessage::GetRawData(JSContext
* cx
, JS::MutableHandle
<JS::Value
> aRawData
) {
228 mJsobj
= dom::Uint8Array::Create(cx
, nullptr, mData
, error
);
229 if (error
.Failed()) {
230 return error
.StealNSResult();
234 aRawData
.setObject(*mJsobj
);
238 FallibleTArray
<uint8_t>& nsUDPMessage::GetDataAsTArray() { return mData
; }
240 //-----------------------------------------------------------------------------
242 //-----------------------------------------------------------------------------
244 nsUDPSocket::nsUDPSocket() {
245 // we want to be able to access the STS directly, and it may not have been
246 // constructed yet. the STS constructor sets gSocketTransportService.
247 if (!gSocketTransportService
) {
248 // This call can fail if we're offline, for example.
249 nsCOMPtr
<nsISocketTransportService
> sts
=
250 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
);
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 // create proxy via IOActivityMonitor
643 IOActivityMonitor::MonitorSocket(mFD
);
645 // wait until AsyncListen is called before polling the socket for
646 // client connections.
651 return NS_ERROR_FAILURE
;
655 nsUDPSocket::Connect(const NetAddr
* aAddr
) {
656 UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
658 NS_ENSURE_ARG(aAddr
);
660 if (NS_WARN_IF(!mFD
)) {
661 return NS_ERROR_NOT_INITIALIZED
;
666 rv
= CheckIOStatus(aAddr
);
671 bool onSTSThread
= false;
672 mSts
->IsOnCurrentThread(&onSTSThread
);
673 NS_ASSERTION(onSTSThread
, "NOT ON STS THREAD");
675 return NS_ERROR_FAILURE
;
679 memset(&prAddr
, 0, sizeof(prAddr
));
680 NetAddrToPRNetAddr(aAddr
, &prAddr
);
682 if (PR_Connect(mFD
, &prAddr
, PR_INTERVAL_NO_WAIT
) != PR_SUCCESS
) {
683 NS_WARNING("Cannot PR_Connect");
684 return NS_ERROR_FAILURE
;
686 PR_SetFDInheritable(mFD
, false);
688 // get the resulting socket address, which may have been updated.
690 if (PR_GetSockName(mFD
, &addr
) != PR_SUCCESS
) {
691 NS_WARNING("cannot get socket name");
692 return NS_ERROR_FAILURE
;
695 PRNetAddrToNetAddr(&addr
, &mAddr
);
701 nsUDPSocket::Close() {
703 MutexAutoLock
lock(mLock
);
704 // we want to proxy the close operation to the socket thread if a listener
705 // has been set. otherwise, we should just close the socket here...
706 if (!mListener
&& !mSyncListener
) {
707 // Here we want to go directly with closing the socket since some tests
708 // expects this happen synchronously.
714 return PostEvent(this, &nsUDPSocket::OnMsgClose
);
718 nsUDPSocket::GetPort(int32_t* aResult
) {
719 // no need to enter the lock here
721 nsresult rv
= mAddr
.GetPort(&result
);
722 *aResult
= static_cast<int32_t>(result
);
727 nsUDPSocket::GetLocalAddr(nsINetAddr
** aResult
) {
728 NS_ENSURE_ARG_POINTER(aResult
);
730 nsCOMPtr
<nsINetAddr
> result
= new nsNetAddr(&mAddr
);
731 result
.forget(aResult
);
736 void nsUDPSocket::CloseSocket() {
738 if (gIOService
->IsNetTearingDown() &&
739 ((PR_IntervalNow() - gIOService
->NetTearingDownStarted()) >
740 gSocketTransportService
->MaxTimeForPrClosePref())) {
741 // If shutdown last to long, let the socket leak and do not close it.
742 UDPSOCKET_LOG(("Intentional leak"));
744 PRIntervalTime closeStarted
= 0;
745 if (gSocketTransportService
->IsTelemetryEnabledAndNotSleepPhase()) {
746 closeStarted
= PR_IntervalNow();
751 if (gSocketTransportService
->IsTelemetryEnabledAndNotSleepPhase()) {
752 PRIntervalTime now
= PR_IntervalNow();
753 if (gIOService
->IsNetTearingDown()) {
754 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN
,
755 PR_IntervalToMilliseconds(now
- closeStarted
));
757 } else if (PR_IntervalToSeconds(
758 now
- gIOService
->LastConnectivityChange()) < 60) {
759 Telemetry::Accumulate(
760 Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE
,
761 PR_IntervalToMilliseconds(now
- closeStarted
));
763 } else if (PR_IntervalToSeconds(
764 now
- gIOService
->LastNetworkLinkChange()) < 60) {
765 Telemetry::Accumulate(
766 Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE
,
767 PR_IntervalToMilliseconds(now
- closeStarted
));
769 } else if (PR_IntervalToSeconds(
770 now
- gIOService
->LastOfflineStateChange()) < 60) {
771 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE
,
772 PR_IntervalToMilliseconds(now
- closeStarted
));
775 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL
,
776 PR_IntervalToMilliseconds(now
- closeStarted
));
785 nsUDPSocket::GetAddress(NetAddr
* aResult
) {
786 // no need to enter the lock here
787 memcpy(aResult
, &mAddr
, sizeof(mAddr
));
792 //-----------------------------------------------------------------------------
793 // SocketListenerProxy
794 //-----------------------------------------------------------------------------
795 class SocketListenerProxy final
: public nsIUDPSocketListener
{
796 ~SocketListenerProxy() = default;
799 explicit SocketListenerProxy(nsIUDPSocketListener
* aListener
)
800 : mListener(new nsMainThreadPtrHolder
<nsIUDPSocketListener
>(
801 "SocketListenerProxy::mListener", aListener
)),
802 mTarget(GetCurrentSerialEventTarget()) {}
804 NS_DECL_THREADSAFE_ISUPPORTS
805 NS_DECL_NSIUDPSOCKETLISTENER
807 class OnPacketReceivedRunnable
: public Runnable
{
809 OnPacketReceivedRunnable(
810 const nsMainThreadPtrHandle
<nsIUDPSocketListener
>& aListener
,
811 nsIUDPSocket
* aSocket
, nsIUDPMessage
* aMessage
)
812 : Runnable("net::SocketListenerProxy::OnPacketReceivedRunnable"),
813 mListener(aListener
),
815 mMessage(aMessage
) {}
820 nsMainThreadPtrHandle
<nsIUDPSocketListener
> mListener
;
821 nsCOMPtr
<nsIUDPSocket
> mSocket
;
822 nsCOMPtr
<nsIUDPMessage
> mMessage
;
825 class OnStopListeningRunnable
: public Runnable
{
827 OnStopListeningRunnable(
828 const nsMainThreadPtrHandle
<nsIUDPSocketListener
>& aListener
,
829 nsIUDPSocket
* aSocket
, nsresult aStatus
)
830 : Runnable("net::SocketListenerProxy::OnStopListeningRunnable"),
831 mListener(aListener
),
838 nsMainThreadPtrHandle
<nsIUDPSocketListener
> mListener
;
839 nsCOMPtr
<nsIUDPSocket
> mSocket
;
844 nsMainThreadPtrHandle
<nsIUDPSocketListener
> mListener
;
845 nsCOMPtr
<nsIEventTarget
> mTarget
;
848 NS_IMPL_ISUPPORTS(SocketListenerProxy
, nsIUDPSocketListener
)
851 SocketListenerProxy::OnPacketReceived(nsIUDPSocket
* aSocket
,
852 nsIUDPMessage
* aMessage
) {
853 RefPtr
<OnPacketReceivedRunnable
> r
=
854 new OnPacketReceivedRunnable(mListener
, aSocket
, aMessage
);
855 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
859 SocketListenerProxy::OnStopListening(nsIUDPSocket
* aSocket
, nsresult aStatus
) {
860 RefPtr
<OnStopListeningRunnable
> r
=
861 new OnStopListeningRunnable(mListener
, aSocket
, aStatus
);
862 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
866 SocketListenerProxy::OnPacketReceivedRunnable::Run() {
868 nsCOMPtr
<nsINetAddr
> nsAddr
;
869 mMessage
->GetFromAddr(getter_AddRefs(nsAddr
));
870 nsAddr
->GetNetAddr(&netAddr
);
872 nsCOMPtr
<nsIOutputStream
> outputStream
;
873 mMessage
->GetOutputStream(getter_AddRefs(outputStream
));
875 FallibleTArray
<uint8_t>& data
= mMessage
->GetDataAsTArray();
877 nsCOMPtr
<nsIUDPMessage
> message
=
878 new nsUDPMessage(&netAddr
, outputStream
, std::move(data
));
879 mListener
->OnPacketReceived(mSocket
, message
);
884 SocketListenerProxy::OnStopListeningRunnable::Run() {
885 mListener
->OnStopListening(mSocket
, mStatus
);
889 class SocketListenerProxyBackground final
: public nsIUDPSocketListener
{
890 ~SocketListenerProxyBackground() = default;
893 explicit SocketListenerProxyBackground(nsIUDPSocketListener
* aListener
)
894 : mListener(aListener
), mTarget(GetCurrentSerialEventTarget()) {}
896 NS_DECL_THREADSAFE_ISUPPORTS
897 NS_DECL_NSIUDPSOCKETLISTENER
899 class OnPacketReceivedRunnable
: public Runnable
{
901 OnPacketReceivedRunnable(const nsCOMPtr
<nsIUDPSocketListener
>& aListener
,
902 nsIUDPSocket
* aSocket
, nsIUDPMessage
* aMessage
)
904 "net::SocketListenerProxyBackground::OnPacketReceivedRunnable"),
905 mListener(aListener
),
907 mMessage(aMessage
) {}
912 nsCOMPtr
<nsIUDPSocketListener
> mListener
;
913 nsCOMPtr
<nsIUDPSocket
> mSocket
;
914 nsCOMPtr
<nsIUDPMessage
> mMessage
;
917 class OnStopListeningRunnable
: public Runnable
{
919 OnStopListeningRunnable(const nsCOMPtr
<nsIUDPSocketListener
>& aListener
,
920 nsIUDPSocket
* aSocket
, nsresult aStatus
)
922 "net::SocketListenerProxyBackground::OnStopListeningRunnable"),
923 mListener(aListener
),
930 nsCOMPtr
<nsIUDPSocketListener
> mListener
;
931 nsCOMPtr
<nsIUDPSocket
> mSocket
;
936 nsCOMPtr
<nsIUDPSocketListener
> mListener
;
937 nsCOMPtr
<nsIEventTarget
> mTarget
;
940 NS_IMPL_ISUPPORTS(SocketListenerProxyBackground
, nsIUDPSocketListener
)
943 SocketListenerProxyBackground::OnPacketReceived(nsIUDPSocket
* aSocket
,
944 nsIUDPMessage
* aMessage
) {
945 RefPtr
<OnPacketReceivedRunnable
> r
=
946 new OnPacketReceivedRunnable(mListener
, aSocket
, aMessage
);
947 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
951 SocketListenerProxyBackground::OnStopListening(nsIUDPSocket
* aSocket
,
953 RefPtr
<OnStopListeningRunnable
> r
=
954 new OnStopListeningRunnable(mListener
, aSocket
, aStatus
);
955 return mTarget
->Dispatch(r
, NS_DISPATCH_NORMAL
);
959 SocketListenerProxyBackground::OnPacketReceivedRunnable::Run() {
961 nsCOMPtr
<nsINetAddr
> nsAddr
;
962 mMessage
->GetFromAddr(getter_AddRefs(nsAddr
));
963 nsAddr
->GetNetAddr(&netAddr
);
965 nsCOMPtr
<nsIOutputStream
> outputStream
;
966 mMessage
->GetOutputStream(getter_AddRefs(outputStream
));
968 FallibleTArray
<uint8_t>& data
= mMessage
->GetDataAsTArray();
970 UDPSOCKET_LOG(("%s [this=%p], len %zu", __FUNCTION__
, this, data
.Length()));
971 nsCOMPtr
<nsIUDPMessage
> message
=
972 new UDPMessageProxy(&netAddr
, outputStream
, std::move(data
));
973 mListener
->OnPacketReceived(mSocket
, message
);
978 SocketListenerProxyBackground::OnStopListeningRunnable::Run() {
979 mListener
->OnStopListening(mSocket
, mStatus
);
983 class PendingSend
: public nsIDNSListener
{
985 NS_DECL_THREADSAFE_ISUPPORTS
986 NS_DECL_NSIDNSLISTENER
988 PendingSend(nsUDPSocket
* aSocket
, uint16_t aPort
,
989 FallibleTArray
<uint8_t>&& aData
)
990 : mSocket(aSocket
), mPort(aPort
), mData(std::move(aData
)) {}
993 virtual ~PendingSend() = default;
995 RefPtr
<nsUDPSocket
> mSocket
;
997 FallibleTArray
<uint8_t> mData
;
1000 NS_IMPL_ISUPPORTS(PendingSend
, nsIDNSListener
)
1003 PendingSend::OnLookupComplete(nsICancelable
* request
, nsIDNSRecord
* aRecord
,
1005 if (NS_FAILED(status
)) {
1006 NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
1010 nsCOMPtr
<nsIDNSAddrRecord
> rec
= do_QueryInterface(aRecord
);
1013 if (NS_SUCCEEDED(rec
->GetNextAddr(mPort
, &addr
))) {
1015 nsresult rv
= mSocket
->SendWithAddress(&addr
, mData
.Elements(),
1016 mData
.Length(), &count
);
1017 NS_ENSURE_SUCCESS(rv
, rv
);
1023 class PendingSendStream
: public nsIDNSListener
{
1025 NS_DECL_THREADSAFE_ISUPPORTS
1026 NS_DECL_NSIDNSLISTENER
1028 PendingSendStream(nsUDPSocket
* aSocket
, uint16_t aPort
,
1029 nsIInputStream
* aStream
)
1030 : mSocket(aSocket
), mPort(aPort
), mStream(aStream
) {}
1033 virtual ~PendingSendStream() = default;
1035 RefPtr
<nsUDPSocket
> mSocket
;
1037 nsCOMPtr
<nsIInputStream
> mStream
;
1040 NS_IMPL_ISUPPORTS(PendingSendStream
, nsIDNSListener
)
1043 PendingSendStream::OnLookupComplete(nsICancelable
* request
,
1044 nsIDNSRecord
* aRecord
, nsresult status
) {
1045 if (NS_FAILED(status
)) {
1046 NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
1050 nsCOMPtr
<nsIDNSAddrRecord
> rec
= do_QueryInterface(aRecord
);
1053 if (NS_SUCCEEDED(rec
->GetNextAddr(mPort
, &addr
))) {
1054 nsresult rv
= mSocket
->SendBinaryStreamWithAddress(&addr
, mStream
);
1055 NS_ENSURE_SUCCESS(rv
, rv
);
1061 class SendRequestRunnable
: public Runnable
{
1063 SendRequestRunnable(nsUDPSocket
* aSocket
, const NetAddr
& aAddr
,
1064 FallibleTArray
<uint8_t>&& aData
)
1065 : Runnable("net::SendRequestRunnable"),
1068 mData(std::move(aData
)) {}
1073 RefPtr
<nsUDPSocket
> mSocket
;
1074 const NetAddr mAddr
;
1075 FallibleTArray
<uint8_t> mData
;
1079 SendRequestRunnable::Run() {
1081 mSocket
->SendWithAddress(&mAddr
, mData
.Elements(), mData
.Length(), &count
);
1088 nsUDPSocket::AsyncListen(nsIUDPSocketListener
* aListener
) {
1089 // ensuring mFD implies ensuring mLock
1090 NS_ENSURE_TRUE(mFD
, NS_ERROR_NOT_INITIALIZED
);
1091 NS_ENSURE_TRUE(mListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1092 NS_ENSURE_TRUE(mSyncListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1094 MutexAutoLock
lock(mLock
);
1095 mListenerTarget
= GetCurrentSerialEventTarget();
1096 if (NS_IsMainThread()) {
1098 mListener
= new SocketListenerProxy(aListener
);
1100 // PBackground usage from dom/media/webrtc/transport
1101 mListener
= new SocketListenerProxyBackground(aListener
);
1104 return PostEvent(this, &nsUDPSocket::OnMsgAttach
);
1108 nsUDPSocket::SyncListen(nsIUDPSocketSyncListener
* aListener
) {
1109 // ensuring mFD implies ensuring mLock
1110 NS_ENSURE_TRUE(mFD
, NS_ERROR_NOT_INITIALIZED
);
1111 NS_ENSURE_TRUE(mListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1112 NS_ENSURE_TRUE(mSyncListener
== nullptr, NS_ERROR_IN_PROGRESS
);
1114 mSyncListener
= aListener
;
1116 return PostEvent(this, &nsUDPSocket::OnMsgAttach
);
1120 nsUDPSocket::Send(const nsACString
& aHost
, uint16_t aPort
,
1121 const nsTArray
<uint8_t>& aData
, uint32_t* _retval
) {
1122 NS_ENSURE_ARG_POINTER(_retval
);
1126 FallibleTArray
<uint8_t> fallibleArray
;
1127 if (!fallibleArray
.InsertElementsAt(0, aData
, fallible
)) {
1128 return NS_ERROR_OUT_OF_MEMORY
;
1131 nsCOMPtr
<nsIDNSListener
> listener
=
1132 new PendingSend(this, aPort
, std::move(fallibleArray
));
1134 nsresult rv
= ResolveHost(aHost
, mOriginAttributes
, listener
);
1135 NS_ENSURE_SUCCESS(rv
, rv
);
1137 *_retval
= aData
.Length();
1142 nsUDPSocket::SendWithAddr(nsINetAddr
* aAddr
, const nsTArray
<uint8_t>& aData
,
1143 uint32_t* _retval
) {
1144 NS_ENSURE_ARG(aAddr
);
1145 NS_ENSURE_ARG_POINTER(_retval
);
1148 aAddr
->GetNetAddr(&netAddr
);
1149 return SendWithAddress(&netAddr
, aData
.Elements(), aData
.Length(), _retval
);
1153 nsUDPSocket::SendWithAddress(const NetAddr
* aAddr
, const uint8_t* aData
,
1154 uint32_t aLength
, uint32_t* _retval
) {
1155 NS_ENSURE_ARG(aAddr
);
1156 NS_ENSURE_ARG_POINTER(_retval
);
1158 if (StaticPrefs::network_http_http3_block_loopback_ipv6_addr() &&
1159 aAddr
->raw
.family
== AF_INET6
&& aAddr
->IsLoopbackAddr()) {
1160 return NS_ERROR_CONNECTION_REFUSED
;
1166 NetAddrToPRNetAddr(aAddr
, &prAddr
);
1168 bool onSTSThread
= false;
1169 mSts
->IsOnCurrentThread(&onSTSThread
);
1172 MutexAutoLock
lock(mLock
);
1174 // socket is not initialized or has been closed
1175 return NS_ERROR_FAILURE
;
1178 PR_SendTo(mFD
, aData
, aLength
, 0, &prAddr
, PR_INTERVAL_NO_WAIT
);
1180 PRErrorCode code
= PR_GetError();
1181 return ErrorAccordingToNSPR(code
);
1183 this->AddOutputBytes(count
);
1186 FallibleTArray
<uint8_t> fallibleArray
;
1187 if (!fallibleArray
.AppendElements(aData
, aLength
, fallible
)) {
1188 return NS_ERROR_OUT_OF_MEMORY
;
1191 nsresult rv
= mSts
->Dispatch(
1192 new SendRequestRunnable(this, *aAddr
, std::move(fallibleArray
)),
1193 NS_DISPATCH_NORMAL
);
1194 NS_ENSURE_SUCCESS(rv
, rv
);
1201 nsUDPSocket::SendBinaryStream(const nsACString
& aHost
, uint16_t aPort
,
1202 nsIInputStream
* aStream
) {
1203 NS_ENSURE_ARG(aStream
);
1205 nsCOMPtr
<nsIDNSListener
> listener
=
1206 new PendingSendStream(this, aPort
, aStream
);
1208 return ResolveHost(aHost
, mOriginAttributes
, listener
);
1212 nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr
* aAddr
,
1213 nsIInputStream
* aStream
) {
1214 NS_ENSURE_ARG(aAddr
);
1215 NS_ENSURE_ARG(aStream
);
1218 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prAddr
);
1219 NetAddrToPRNetAddr(aAddr
, &prAddr
);
1221 RefPtr
<nsUDPOutputStream
> os
= new nsUDPOutputStream(this, mFD
, prAddr
);
1222 return NS_AsyncCopy(aStream
, os
, mSts
, NS_ASYNCCOPY_VIA_READSEGMENTS
,
1223 UDP_PACKET_CHUNK_SIZE
);
1227 nsUDPSocket::RecvWithAddr(NetAddr
* addr
, nsTArray
<uint8_t>& aData
) {
1228 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1232 count
= PR_RecvFrom(mFD
, buff
, sizeof(buff
), 0, &prAddr
, PR_INTERVAL_NO_WAIT
);
1235 ("nsUDPSocket::RecvWithAddr: PR_RecvFrom failed [this=%p]\n", this));
1238 mByteReadCount
+= count
;
1239 profiler_count_bandwidth_read_bytes(count
);
1240 PRNetAddrToNetAddr(&prAddr
, addr
);
1242 if (!aData
.AppendElements(buff
, count
, fallible
)) {
1244 "nsUDPSocket::OnSocketReady: AppendElements FAILED [this=%p]\n", this));
1245 mCondition
= NS_ERROR_UNEXPECTED
;
1250 nsresult
nsUDPSocket::SetSocketOption(const PRSocketOptionData
& aOpt
) {
1251 bool onSTSThread
= false;
1252 mSts
->IsOnCurrentThread(&onSTSThread
);
1255 // Dispatch to STS thread and re-enter this method there
1256 nsCOMPtr
<nsIRunnable
> runnable
= new SetSocketOptionRunnable(this, aOpt
);
1257 nsresult rv
= mSts
->Dispatch(runnable
, NS_DISPATCH_NORMAL
);
1258 if (NS_WARN_IF(NS_FAILED(rv
))) {
1264 if (NS_WARN_IF(!mFD
)) {
1265 return NS_ERROR_NOT_INITIALIZED
;
1268 if (PR_SetSocketOption(mFD
, &aOpt
) != PR_SUCCESS
) {
1270 ("nsUDPSocket::SetSocketOption [this=%p] failed for type %d, "
1272 this, aOpt
.option
, PR_GetError()));
1273 return NS_ERROR_FAILURE
;
1280 nsUDPSocket::JoinMulticast(const nsACString
& aAddr
, const nsACString
& aIface
) {
1281 if (NS_WARN_IF(aAddr
.IsEmpty())) {
1282 return NS_ERROR_INVALID_ARG
;
1284 if (NS_WARN_IF(!mFD
)) {
1285 return NS_ERROR_NOT_INITIALIZED
;
1289 if (PR_StringToNetAddr(aAddr
.BeginReading(), &prAddr
) != PR_SUCCESS
) {
1290 return NS_ERROR_FAILURE
;
1294 if (aIface
.IsEmpty()) {
1295 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1297 if (PR_StringToNetAddr(aIface
.BeginReading(), &prIface
) != PR_SUCCESS
) {
1298 return NS_ERROR_FAILURE
;
1302 return JoinMulticastInternal(prAddr
, prIface
);
1306 nsUDPSocket::JoinMulticastAddr(const NetAddr aAddr
, const NetAddr
* aIface
) {
1307 if (NS_WARN_IF(!mFD
)) {
1308 return NS_ERROR_NOT_INITIALIZED
;
1312 NetAddrToPRNetAddr(&aAddr
, &prAddr
);
1316 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1318 NetAddrToPRNetAddr(aIface
, &prIface
);
1321 return JoinMulticastInternal(prAddr
, prIface
);
1324 nsresult
nsUDPSocket::JoinMulticastInternal(const PRNetAddr
& aAddr
,
1325 const PRNetAddr
& aIface
) {
1326 PRSocketOptionData opt
;
1328 opt
.option
= PR_SockOpt_AddMember
;
1329 opt
.value
.add_member
.mcaddr
= aAddr
;
1330 opt
.value
.add_member
.ifaddr
= aIface
;
1332 nsresult rv
= SetSocketOption(opt
);
1333 if (NS_WARN_IF(NS_FAILED(rv
))) {
1334 return NS_ERROR_FAILURE
;
1341 nsUDPSocket::LeaveMulticast(const nsACString
& aAddr
, const nsACString
& aIface
) {
1342 if (NS_WARN_IF(aAddr
.IsEmpty())) {
1343 return NS_ERROR_INVALID_ARG
;
1345 if (NS_WARN_IF(!mFD
)) {
1346 return NS_ERROR_NOT_INITIALIZED
;
1350 if (PR_StringToNetAddr(aAddr
.BeginReading(), &prAddr
) != PR_SUCCESS
) {
1351 return NS_ERROR_FAILURE
;
1355 if (aIface
.IsEmpty()) {
1356 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1358 if (PR_StringToNetAddr(aIface
.BeginReading(), &prIface
) != PR_SUCCESS
) {
1359 return NS_ERROR_FAILURE
;
1363 return LeaveMulticastInternal(prAddr
, prIface
);
1367 nsUDPSocket::LeaveMulticastAddr(const NetAddr aAddr
, const NetAddr
* aIface
) {
1368 if (NS_WARN_IF(!mFD
)) {
1369 return NS_ERROR_NOT_INITIALIZED
;
1373 NetAddrToPRNetAddr(&aAddr
, &prAddr
);
1377 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1379 NetAddrToPRNetAddr(aIface
, &prIface
);
1382 return LeaveMulticastInternal(prAddr
, prIface
);
1385 nsresult
nsUDPSocket::LeaveMulticastInternal(const PRNetAddr
& aAddr
,
1386 const PRNetAddr
& aIface
) {
1387 PRSocketOptionData opt
;
1389 opt
.option
= PR_SockOpt_DropMember
;
1390 opt
.value
.drop_member
.mcaddr
= aAddr
;
1391 opt
.value
.drop_member
.ifaddr
= aIface
;
1393 nsresult rv
= SetSocketOption(opt
);
1394 if (NS_WARN_IF(NS_FAILED(rv
))) {
1395 return NS_ERROR_FAILURE
;
1402 nsUDPSocket::GetMulticastLoopback(bool* aLoopback
) {
1403 return NS_ERROR_NOT_IMPLEMENTED
;
1407 nsUDPSocket::SetMulticastLoopback(bool aLoopback
) {
1408 if (NS_WARN_IF(!mFD
)) {
1409 return NS_ERROR_NOT_INITIALIZED
;
1412 PRSocketOptionData opt
;
1414 opt
.option
= PR_SockOpt_McastLoopback
;
1415 opt
.value
.mcast_loopback
= aLoopback
;
1417 nsresult rv
= SetSocketOption(opt
);
1418 if (NS_WARN_IF(NS_FAILED(rv
))) {
1419 return NS_ERROR_FAILURE
;
1426 nsUDPSocket::GetRecvBufferSize(int* size
) {
1427 // Bug 1252759 - missing support for GetSocketOption
1428 return NS_ERROR_NOT_IMPLEMENTED
;
1432 nsUDPSocket::SetRecvBufferSize(int size
) {
1433 if (NS_WARN_IF(!mFD
)) {
1434 return NS_ERROR_NOT_INITIALIZED
;
1437 PRSocketOptionData opt
;
1439 opt
.option
= PR_SockOpt_RecvBufferSize
;
1440 opt
.value
.recv_buffer_size
= size
;
1442 nsresult rv
= SetSocketOption(opt
);
1443 if (NS_WARN_IF(NS_FAILED(rv
))) {
1444 return NS_ERROR_FAILURE
;
1451 nsUDPSocket::GetDontFragment(bool* dontFragment
) {
1452 // Bug 1252759 - missing support for GetSocketOption
1453 return NS_ERROR_NOT_IMPLEMENTED
;
1457 nsUDPSocket::SetDontFragment(bool dontFragment
) {
1458 if (NS_WARN_IF(!mFD
)) {
1459 return NS_ERROR_NOT_INITIALIZED
;
1462 PRSocketOptionData opt
;
1463 opt
.option
= PR_SockOpt_DontFrag
;
1464 opt
.value
.dont_fragment
= dontFragment
;
1466 nsresult rv
= SetSocketOption(opt
);
1467 if (NS_WARN_IF(NS_FAILED(rv
))) {
1468 return NS_ERROR_FAILURE
;
1474 nsUDPSocket::GetSendBufferSize(int* size
) {
1475 // Bug 1252759 - missing support for GetSocketOption
1476 return NS_ERROR_NOT_IMPLEMENTED
;
1480 nsUDPSocket::SetSendBufferSize(int size
) {
1481 if (NS_WARN_IF(!mFD
)) {
1482 return NS_ERROR_NOT_INITIALIZED
;
1485 PRSocketOptionData opt
;
1487 opt
.option
= PR_SockOpt_SendBufferSize
;
1488 opt
.value
.send_buffer_size
= size
;
1490 nsresult rv
= SetSocketOption(opt
);
1491 if (NS_WARN_IF(NS_FAILED(rv
))) {
1492 return NS_ERROR_FAILURE
;
1499 nsUDPSocket::GetMulticastInterface(nsACString
& aIface
) {
1500 return NS_ERROR_NOT_IMPLEMENTED
;
1504 nsUDPSocket::GetMulticastInterfaceAddr(NetAddr
* aIface
) {
1505 return NS_ERROR_NOT_IMPLEMENTED
;
1509 nsUDPSocket::SetMulticastInterface(const nsACString
& aIface
) {
1510 if (NS_WARN_IF(!mFD
)) {
1511 return NS_ERROR_NOT_INITIALIZED
;
1515 if (aIface
.IsEmpty()) {
1516 PR_InitializeNetAddr(PR_IpAddrAny
, 0, &prIface
);
1518 if (PR_StringToNetAddr(aIface
.BeginReading(), &prIface
) != PR_SUCCESS
) {
1519 return NS_ERROR_FAILURE
;
1523 return SetMulticastInterfaceInternal(prIface
);
1527 nsUDPSocket::SetMulticastInterfaceAddr(NetAddr aIface
) {
1528 if (NS_WARN_IF(!mFD
)) {
1529 return NS_ERROR_NOT_INITIALIZED
;
1533 NetAddrToPRNetAddr(&aIface
, &prIface
);
1535 return SetMulticastInterfaceInternal(prIface
);
1538 nsresult
nsUDPSocket::SetMulticastInterfaceInternal(const PRNetAddr
& aIface
) {
1539 PRSocketOptionData opt
;
1541 opt
.option
= PR_SockOpt_McastInterface
;
1542 opt
.value
.mcast_if
= aIface
;
1544 nsresult rv
= SetSocketOption(opt
);
1545 if (NS_WARN_IF(NS_FAILED(rv
))) {
1546 return NS_ERROR_FAILURE
;
1553 } // namespace mozilla