Backed out 2 changesets (bug 1881078, bug 1879806) for causing dt failures @ devtools...
[gecko.git] / netwerk / base / nsUDPSocket.cpp
blob991c28acf8e371a553f09e35756a10a92389d0f5
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"
16 #include "nsError.h"
17 #include "nsNetCID.h"
18 #include "nsNetUtil.h"
19 #include "nsIOService.h"
20 #include "prnetdb.h"
21 #include "prio.h"
22 #include "nsNetAddr.h"
23 #include "nsNetSegmentUtils.h"
24 #include "IOActivityMonitor.h"
25 #include "nsServiceManagerUtils.h"
26 #include "nsStreamUtils.h"
27 #include "prerror.h"
28 #include "nsThreadUtils.h"
29 #include "nsIDNSRecord.h"
30 #include "nsIDNSService.h"
31 #include "nsICancelable.h"
32 #include "nsIPipe.h"
33 #include "nsWrapperCacheInlines.h"
34 #include "HttpConnectionUDP.h"
35 #include "mozilla/ProfilerBandwidthCounter.h"
36 #include "mozilla/StaticPrefs_network.h"
38 #if defined(FUZZING)
39 # include "FuzzyLayer.h"
40 # include "mozilla/StaticPrefs_fuzzing.h"
41 #endif
43 namespace mozilla {
44 namespace net {
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) {
62 nsresult rv;
64 nsCOMPtr<nsIDNSService> dns =
65 do_GetService("@mozilla.org/network/dns-service;1", &rv);
66 if (NS_FAILED(rv)) {
67 return 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;
90 return NS_OK;
93 //-----------------------------------------------------------------------------
95 class SetSocketOptionRunnable : public Runnable {
96 public:
97 SetSocketOptionRunnable(nsUDPSocket* aSocket, const PRSocketOptionData& aOpt)
98 : Runnable("net::SetSocketOptionRunnable"),
99 mSocket(aSocket),
100 mOpt(aOpt) {}
102 NS_IMETHOD Run() override { return mSocket->SetSocketOption(mOpt); }
104 private:
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)
116 : mSocket(aSocket),
117 mFD(aFD),
118 mPrClientAddr(aPrClientAddr),
119 mIsClosed(false) {}
121 NS_IMETHODIMP nsUDPOutputStream::Close() {
122 if (mIsClosed) return NS_BASE_STREAM_CLOSED;
124 mIsClosed = true;
125 return NS_OK;
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,
135 uint32_t* _retval) {
136 if (mIsClosed) return NS_BASE_STREAM_CLOSED;
138 *_retval = 0;
139 int32_t count =
140 PR_SendTo(mFD, aBuf, aCount, 0, &mPrClientAddr, PR_INTERVAL_NO_WAIT);
141 if (count < 0) {
142 PRErrorCode code = PR_GetError();
143 return ErrorAccordingToNSPR(code);
146 *_retval = count;
148 mSocket->AddOutputBytes(count);
150 return NS_OK;
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,
160 uint32_t* _retval) {
161 return NS_ERROR_NOT_IMPLEMENTED;
164 NS_IMETHODIMP nsUDPOutputStream::IsNonBlocking(bool* _retval) {
165 *_retval = true;
166 return NS_OK;
169 //-----------------------------------------------------------------------------
170 // nsUDPMessage impl
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)
180 NS_INTERFACE_MAP_END
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); }
201 NS_IMETHODIMP
202 nsUDPMessage::GetFromAddr(nsINetAddr** aFromAddr) {
203 NS_ENSURE_ARG_POINTER(aFromAddr);
205 nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
206 result.forget(aFromAddr);
208 return NS_OK;
211 NS_IMETHODIMP
212 nsUDPMessage::GetData(nsACString& aData) {
213 aData.Assign(reinterpret_cast<const char*>(mData.Elements()), mData.Length());
214 return NS_OK;
217 NS_IMETHODIMP
218 nsUDPMessage::GetOutputStream(nsIOutputStream** aOutputStream) {
219 NS_ENSURE_ARG_POINTER(aOutputStream);
220 *aOutputStream = do_AddRef(mOutputStream).take();
221 return NS_OK;
224 NS_IMETHODIMP
225 nsUDPMessage::GetRawData(JSContext* cx, JS::MutableHandle<JS::Value> aRawData) {
226 if (!mJsobj) {
227 ErrorResult error;
228 mJsobj = dom::Uint8Array::Create(cx, nullptr, mData, error);
229 if (error.Failed()) {
230 return error.StealNSResult();
232 HoldJSObjects(this);
234 aRawData.setObject(*mJsobj);
235 return NS_OK;
238 FallibleTArray<uint8_t>& nsUDPMessage::GetDataAsTArray() { return mData; }
240 //-----------------------------------------------------------------------------
241 // nsUDPSocket
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
287 " [this=%p]\n",
288 static_cast<uint32_t>(mCondition), this));
289 NS_ASSERTION(!mAttached, "should not be attached already");
290 OnSocketDetached(mFD);
294 nsresult nsUDPSocket::TryAttach() {
295 nsresult rv;
297 if (!gSocketTransportService) return NS_ERROR_FAILURE;
299 rv = CheckIOStatus(&mAddr);
300 if (NS_FAILED(rv)) {
301 return rv;
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;
330 mAttached = true;
333 // now, configure our poll flags for listening...
335 mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT);
336 return NS_OK;
339 namespace {
340 //-----------------------------------------------------------------------------
341 // UDPMessageProxy
342 //-----------------------------------------------------------------------------
343 class UDPMessageProxy final : public nsIUDPMessage {
344 public:
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
354 private:
355 ~UDPMessageProxy() = default;
357 NetAddr mAddr;
358 nsCOMPtr<nsIOutputStream> mOutputStream;
359 FallibleTArray<uint8_t> mData;
362 NS_IMPL_ISUPPORTS(UDPMessageProxy, nsIUDPMessage)
364 NS_IMETHODIMP
365 UDPMessageProxy::GetFromAddr(nsINetAddr** aFromAddr) {
366 NS_ENSURE_ARG_POINTER(aFromAddr);
368 nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
369 result.forget(aFromAddr);
371 return NS_OK;
374 NS_IMETHODIMP
375 UDPMessageProxy::GetData(nsACString& aData) {
376 aData.Assign(reinterpret_cast<const char*>(mData.Elements()), mData.Length());
377 return NS_OK;
380 FallibleTArray<uint8_t>& UDPMessageProxy::GetDataAsTArray() { return mData; }
382 NS_IMETHODIMP
383 UDPMessageProxy::GetRawData(JSContext* cx,
384 JS::MutableHandle<JS::Value> aRawData) {
385 return NS_ERROR_NOT_IMPLEMENTED;
388 NS_IMETHODIMP
389 UDPMessageProxy::GetOutputStream(nsIOutputStream** aOutputStream) {
390 NS_ENSURE_ARG_POINTER(aOutputStream);
391 *aOutputStream = do_AddRef(mOutputStream).take();
392 return NS_OK;
395 } // anonymous namespace
397 //-----------------------------------------------------------------------------
398 // nsUDPSocket::nsASocketHandler
399 //-----------------------------------------------------------------------------
401 void nsUDPSocket::OnSocketReady(PRFileDesc* fd, int16_t outFlags) {
402 UDPSOCKET_LOG(
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;
411 return;
414 if (mSyncListener) {
415 mSyncListener->OnPacketReceived(this);
416 return;
419 PRNetAddr prClientAddr;
420 int32_t count;
421 // Bug 1252755 - use 9216 bytes to allign with nICEr and transportlayer to
422 // support the maximum size of jumbo frames
423 char buff[9216];
424 count = PR_RecvFrom(mFD, buff, sizeof(buff), 0, &prClientAddr,
425 PR_INTERVAL_NO_WAIT);
426 if (count < 0) {
427 UDPSOCKET_LOG(
428 ("nsUDPSocket::OnSocketReady: PR_RecvFrom failed [this=%p]\n", this));
429 return;
431 mByteReadCount += count;
432 profiler_count_bandwidth_read_bytes(count);
434 FallibleTArray<uint8_t> data;
435 if (!data.AppendElements(buff, count, fallible)) {
436 UDPSOCKET_LOG((
437 "nsUDPSocket::OnSocketReady: AppendElements FAILED [this=%p]\n", this));
438 mCondition = NS_ERROR_UNEXPECTED;
439 return;
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,
449 segsize, segcount);
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);
455 if (NS_FAILED(rv)) {
456 return;
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;
470 if (mFD) {
471 NS_ASSERTION(mFD == fd, "wrong file descriptor");
472 CloseSocket();
475 if (mSyncListener) {
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));
486 if (listener) {
487 listener->OnStopListening(this, mCondition);
488 NS_ProxyRelease("nsUDPSocket::mListener", mListenerTarget,
489 listener.forget());
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);
504 if (!connUDP) {
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 //-----------------------------------------------------------------------------
520 NS_IMETHODIMP
521 nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly, nsIPrincipal* aPrincipal,
522 bool aAddressReuse, uint8_t aOptionalArgc) {
523 NetAddr addr;
525 if (aPort < 0) aPort = 0;
527 addr.raw.family = AF_INET;
528 addr.inet.port = htons(aPort);
530 if (aLoopbackOnly) {
531 addr.inet.ip = htonl(INADDR_LOOPBACK);
532 } else {
533 addr.inet.ip = htonl(INADDR_ANY);
536 return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
539 NS_IMETHODIMP
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;
547 if (aPort < 0) {
548 aPort = 0;
551 NetAddr addr;
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);
564 NS_IMETHODIMP
565 nsUDPSocket::InitWithAddress(const NetAddr* aAddr, nsIPrincipal* aPrincipal,
566 bool aAddressReuse, uint8_t aOptionalArgc) {
567 NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
569 nsresult rv;
571 rv = CheckIOStatus(aAddr);
572 if (NS_FAILED(rv)) {
573 return rv;
576 bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
578 if (aPrincipal) {
579 mOriginAttributes = aPrincipal->OriginAttributesRef();
582 // configure listening socket...
585 mFD = PR_OpenUDPSocket(aAddr->raw.family);
586 if (!mFD) {
587 NS_WARNING("unable to create UDP socket");
588 return NS_ERROR_FAILURE;
591 #ifdef FUZZING
592 if (StaticPrefs::fuzzing_necko_enabled()) {
593 rv = AttachFuzzyIOLayer(mFD);
594 if (NS_FAILED(rv)) {
595 UDPSOCKET_LOG(("Failed to attach fuzzing IOLayer [rv=%" PRIx32 "].\n",
596 static_cast<uint32_t>(rv)));
597 return rv;
599 UDPSOCKET_LOG(("Successfully attached fuzzing IOLayer.\n"));
601 #endif
603 uint16_t port;
604 if (NS_FAILED(aAddr->GetPort(&port))) {
605 NS_WARNING("invalid bind address");
606 goto fail;
609 PRSocketOptionData opt;
611 // Linux kernel will sometimes hand out a used port if we bind
612 // to port 0 with SO_REUSEADDR
613 if (port) {
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);
623 PRNetAddr addr;
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");
630 goto fail;
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");
637 goto fail;
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.
647 return NS_OK;
649 fail:
650 Close();
651 return NS_ERROR_FAILURE;
654 NS_IMETHODIMP
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;
664 nsresult rv;
666 rv = CheckIOStatus(aAddr);
667 if (NS_FAILED(rv)) {
668 return rv;
671 bool onSTSThread = false;
672 mSts->IsOnCurrentThread(&onSTSThread);
673 NS_ASSERTION(onSTSThread, "NOT ON STS THREAD");
674 if (!onSTSThread) {
675 return NS_ERROR_FAILURE;
678 PRNetAddr prAddr;
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.
689 PRNetAddr addr;
690 if (PR_GetSockName(mFD, &addr) != PR_SUCCESS) {
691 NS_WARNING("cannot get socket name");
692 return NS_ERROR_FAILURE;
695 PRNetAddrToNetAddr(&addr, &mAddr);
697 return NS_OK;
700 NS_IMETHODIMP
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.
709 CloseSocket();
711 return NS_OK;
714 return PostEvent(this, &nsUDPSocket::OnMsgClose);
717 NS_IMETHODIMP
718 nsUDPSocket::GetPort(int32_t* aResult) {
719 // no need to enter the lock here
720 uint16_t result;
721 nsresult rv = mAddr.GetPort(&result);
722 *aResult = static_cast<int32_t>(result);
723 return rv;
726 NS_IMETHODIMP
727 nsUDPSocket::GetLocalAddr(nsINetAddr** aResult) {
728 NS_ENSURE_ARG_POINTER(aResult);
730 nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
731 result.forget(aResult);
733 return NS_OK;
736 void nsUDPSocket::CloseSocket() {
737 if (mFD) {
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"));
743 } else {
744 PRIntervalTime closeStarted = 0;
745 if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase()) {
746 closeStarted = PR_IntervalNow();
749 PR_Close(mFD);
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));
774 } else {
775 Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL,
776 PR_IntervalToMilliseconds(now - closeStarted));
780 mFD = nullptr;
784 NS_IMETHODIMP
785 nsUDPSocket::GetAddress(NetAddr* aResult) {
786 // no need to enter the lock here
787 memcpy(aResult, &mAddr, sizeof(mAddr));
788 return NS_OK;
791 namespace {
792 //-----------------------------------------------------------------------------
793 // SocketListenerProxy
794 //-----------------------------------------------------------------------------
795 class SocketListenerProxy final : public nsIUDPSocketListener {
796 ~SocketListenerProxy() = default;
798 public:
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 {
808 public:
809 OnPacketReceivedRunnable(
810 const nsMainThreadPtrHandle<nsIUDPSocketListener>& aListener,
811 nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
812 : Runnable("net::SocketListenerProxy::OnPacketReceivedRunnable"),
813 mListener(aListener),
814 mSocket(aSocket),
815 mMessage(aMessage) {}
817 NS_DECL_NSIRUNNABLE
819 private:
820 nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
821 nsCOMPtr<nsIUDPSocket> mSocket;
822 nsCOMPtr<nsIUDPMessage> mMessage;
825 class OnStopListeningRunnable : public Runnable {
826 public:
827 OnStopListeningRunnable(
828 const nsMainThreadPtrHandle<nsIUDPSocketListener>& aListener,
829 nsIUDPSocket* aSocket, nsresult aStatus)
830 : Runnable("net::SocketListenerProxy::OnStopListeningRunnable"),
831 mListener(aListener),
832 mSocket(aSocket),
833 mStatus(aStatus) {}
835 NS_DECL_NSIRUNNABLE
837 private:
838 nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
839 nsCOMPtr<nsIUDPSocket> mSocket;
840 nsresult mStatus;
843 private:
844 nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
845 nsCOMPtr<nsIEventTarget> mTarget;
848 NS_IMPL_ISUPPORTS(SocketListenerProxy, nsIUDPSocketListener)
850 NS_IMETHODIMP
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);
858 NS_IMETHODIMP
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);
865 NS_IMETHODIMP
866 SocketListenerProxy::OnPacketReceivedRunnable::Run() {
867 NetAddr netAddr;
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);
880 return NS_OK;
883 NS_IMETHODIMP
884 SocketListenerProxy::OnStopListeningRunnable::Run() {
885 mListener->OnStopListening(mSocket, mStatus);
886 return NS_OK;
889 class SocketListenerProxyBackground final : public nsIUDPSocketListener {
890 ~SocketListenerProxyBackground() = default;
892 public:
893 explicit SocketListenerProxyBackground(nsIUDPSocketListener* aListener)
894 : mListener(aListener), mTarget(GetCurrentSerialEventTarget()) {}
896 NS_DECL_THREADSAFE_ISUPPORTS
897 NS_DECL_NSIUDPSOCKETLISTENER
899 class OnPacketReceivedRunnable : public Runnable {
900 public:
901 OnPacketReceivedRunnable(const nsCOMPtr<nsIUDPSocketListener>& aListener,
902 nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
903 : Runnable(
904 "net::SocketListenerProxyBackground::OnPacketReceivedRunnable"),
905 mListener(aListener),
906 mSocket(aSocket),
907 mMessage(aMessage) {}
909 NS_DECL_NSIRUNNABLE
911 private:
912 nsCOMPtr<nsIUDPSocketListener> mListener;
913 nsCOMPtr<nsIUDPSocket> mSocket;
914 nsCOMPtr<nsIUDPMessage> mMessage;
917 class OnStopListeningRunnable : public Runnable {
918 public:
919 OnStopListeningRunnable(const nsCOMPtr<nsIUDPSocketListener>& aListener,
920 nsIUDPSocket* aSocket, nsresult aStatus)
921 : Runnable(
922 "net::SocketListenerProxyBackground::OnStopListeningRunnable"),
923 mListener(aListener),
924 mSocket(aSocket),
925 mStatus(aStatus) {}
927 NS_DECL_NSIRUNNABLE
929 private:
930 nsCOMPtr<nsIUDPSocketListener> mListener;
931 nsCOMPtr<nsIUDPSocket> mSocket;
932 nsresult mStatus;
935 private:
936 nsCOMPtr<nsIUDPSocketListener> mListener;
937 nsCOMPtr<nsIEventTarget> mTarget;
940 NS_IMPL_ISUPPORTS(SocketListenerProxyBackground, nsIUDPSocketListener)
942 NS_IMETHODIMP
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);
950 NS_IMETHODIMP
951 SocketListenerProxyBackground::OnStopListening(nsIUDPSocket* aSocket,
952 nsresult aStatus) {
953 RefPtr<OnStopListeningRunnable> r =
954 new OnStopListeningRunnable(mListener, aSocket, aStatus);
955 return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
958 NS_IMETHODIMP
959 SocketListenerProxyBackground::OnPacketReceivedRunnable::Run() {
960 NetAddr netAddr;
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);
974 return NS_OK;
977 NS_IMETHODIMP
978 SocketListenerProxyBackground::OnStopListeningRunnable::Run() {
979 mListener->OnStopListening(mSocket, mStatus);
980 return NS_OK;
983 class PendingSend : public nsIDNSListener {
984 public:
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)) {}
992 private:
993 virtual ~PendingSend() = default;
995 RefPtr<nsUDPSocket> mSocket;
996 uint16_t mPort;
997 FallibleTArray<uint8_t> mData;
1000 NS_IMPL_ISUPPORTS(PendingSend, nsIDNSListener)
1002 NS_IMETHODIMP
1003 PendingSend::OnLookupComplete(nsICancelable* request, nsIDNSRecord* aRecord,
1004 nsresult status) {
1005 if (NS_FAILED(status)) {
1006 NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
1007 return NS_OK;
1010 nsCOMPtr<nsIDNSAddrRecord> rec = do_QueryInterface(aRecord);
1011 MOZ_ASSERT(rec);
1012 NetAddr addr;
1013 if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
1014 uint32_t count;
1015 nsresult rv = mSocket->SendWithAddress(&addr, mData.Elements(),
1016 mData.Length(), &count);
1017 NS_ENSURE_SUCCESS(rv, rv);
1020 return NS_OK;
1023 class PendingSendStream : public nsIDNSListener {
1024 public:
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) {}
1032 private:
1033 virtual ~PendingSendStream() = default;
1035 RefPtr<nsUDPSocket> mSocket;
1036 uint16_t mPort;
1037 nsCOMPtr<nsIInputStream> mStream;
1040 NS_IMPL_ISUPPORTS(PendingSendStream, nsIDNSListener)
1042 NS_IMETHODIMP
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");
1047 return NS_OK;
1050 nsCOMPtr<nsIDNSAddrRecord> rec = do_QueryInterface(aRecord);
1051 MOZ_ASSERT(rec);
1052 NetAddr addr;
1053 if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
1054 nsresult rv = mSocket->SendBinaryStreamWithAddress(&addr, mStream);
1055 NS_ENSURE_SUCCESS(rv, rv);
1058 return NS_OK;
1061 class SendRequestRunnable : public Runnable {
1062 public:
1063 SendRequestRunnable(nsUDPSocket* aSocket, const NetAddr& aAddr,
1064 FallibleTArray<uint8_t>&& aData)
1065 : Runnable("net::SendRequestRunnable"),
1066 mSocket(aSocket),
1067 mAddr(aAddr),
1068 mData(std::move(aData)) {}
1070 NS_DECL_NSIRUNNABLE
1072 private:
1073 RefPtr<nsUDPSocket> mSocket;
1074 const NetAddr mAddr;
1075 FallibleTArray<uint8_t> mData;
1078 NS_IMETHODIMP
1079 SendRequestRunnable::Run() {
1080 uint32_t count;
1081 mSocket->SendWithAddress(&mAddr, mData.Elements(), mData.Length(), &count);
1082 return NS_OK;
1085 } // namespace
1087 NS_IMETHODIMP
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()) {
1097 // PNecko usage
1098 mListener = new SocketListenerProxy(aListener);
1099 } else {
1100 // PBackground usage from dom/media/webrtc/transport
1101 mListener = new SocketListenerProxyBackground(aListener);
1104 return PostEvent(this, &nsUDPSocket::OnMsgAttach);
1107 NS_IMETHODIMP
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);
1119 NS_IMETHODIMP
1120 nsUDPSocket::Send(const nsACString& aHost, uint16_t aPort,
1121 const nsTArray<uint8_t>& aData, uint32_t* _retval) {
1122 NS_ENSURE_ARG_POINTER(_retval);
1124 *_retval = 0;
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();
1138 return NS_OK;
1141 NS_IMETHODIMP
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);
1147 NetAddr netAddr;
1148 aAddr->GetNetAddr(&netAddr);
1149 return SendWithAddress(&netAddr, aData.Elements(), aData.Length(), _retval);
1152 NS_IMETHODIMP
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;
1163 *_retval = 0;
1165 PRNetAddr prAddr;
1166 NetAddrToPRNetAddr(aAddr, &prAddr);
1168 bool onSTSThread = false;
1169 mSts->IsOnCurrentThread(&onSTSThread);
1171 if (onSTSThread) {
1172 MutexAutoLock lock(mLock);
1173 if (!mFD) {
1174 // socket is not initialized or has been closed
1175 return NS_ERROR_FAILURE;
1177 int32_t count =
1178 PR_SendTo(mFD, aData, aLength, 0, &prAddr, PR_INTERVAL_NO_WAIT);
1179 if (count < 0) {
1180 PRErrorCode code = PR_GetError();
1181 return ErrorAccordingToNSPR(code);
1183 this->AddOutputBytes(count);
1184 *_retval = count;
1185 } else {
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);
1195 *_retval = aLength;
1197 return NS_OK;
1200 NS_IMETHODIMP
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);
1211 NS_IMETHODIMP
1212 nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr* aAddr,
1213 nsIInputStream* aStream) {
1214 NS_ENSURE_ARG(aAddr);
1215 NS_ENSURE_ARG(aStream);
1217 PRNetAddr prAddr;
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);
1226 NS_IMETHODIMP
1227 nsUDPSocket::RecvWithAddr(NetAddr* addr, nsTArray<uint8_t>& aData) {
1228 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1229 PRNetAddr prAddr;
1230 int32_t count;
1231 char buff[9216];
1232 count = PR_RecvFrom(mFD, buff, sizeof(buff), 0, &prAddr, PR_INTERVAL_NO_WAIT);
1233 if (count < 0) {
1234 UDPSOCKET_LOG(
1235 ("nsUDPSocket::RecvWithAddr: PR_RecvFrom failed [this=%p]\n", this));
1236 return NS_OK;
1238 mByteReadCount += count;
1239 profiler_count_bandwidth_read_bytes(count);
1240 PRNetAddrToNetAddr(&prAddr, addr);
1242 if (!aData.AppendElements(buff, count, fallible)) {
1243 UDPSOCKET_LOG((
1244 "nsUDPSocket::OnSocketReady: AppendElements FAILED [this=%p]\n", this));
1245 mCondition = NS_ERROR_UNEXPECTED;
1247 return NS_OK;
1250 nsresult nsUDPSocket::SetSocketOption(const PRSocketOptionData& aOpt) {
1251 bool onSTSThread = false;
1252 mSts->IsOnCurrentThread(&onSTSThread);
1254 if (!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))) {
1259 return rv;
1261 return NS_OK;
1264 if (NS_WARN_IF(!mFD)) {
1265 return NS_ERROR_NOT_INITIALIZED;
1268 if (PR_SetSocketOption(mFD, &aOpt) != PR_SUCCESS) {
1269 UDPSOCKET_LOG(
1270 ("nsUDPSocket::SetSocketOption [this=%p] failed for type %d, "
1271 "error %d\n",
1272 this, aOpt.option, PR_GetError()));
1273 return NS_ERROR_FAILURE;
1276 return NS_OK;
1279 NS_IMETHODIMP
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;
1288 PRNetAddr prAddr;
1289 if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
1290 return NS_ERROR_FAILURE;
1293 PRNetAddr prIface;
1294 if (aIface.IsEmpty()) {
1295 PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
1296 } else {
1297 if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
1298 return NS_ERROR_FAILURE;
1302 return JoinMulticastInternal(prAddr, prIface);
1305 NS_IMETHODIMP
1306 nsUDPSocket::JoinMulticastAddr(const NetAddr aAddr, const NetAddr* aIface) {
1307 if (NS_WARN_IF(!mFD)) {
1308 return NS_ERROR_NOT_INITIALIZED;
1311 PRNetAddr prAddr;
1312 NetAddrToPRNetAddr(&aAddr, &prAddr);
1314 PRNetAddr prIface;
1315 if (!aIface) {
1316 PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
1317 } else {
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;
1337 return NS_OK;
1340 NS_IMETHODIMP
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;
1349 PRNetAddr prAddr;
1350 if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
1351 return NS_ERROR_FAILURE;
1354 PRNetAddr prIface;
1355 if (aIface.IsEmpty()) {
1356 PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
1357 } else {
1358 if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
1359 return NS_ERROR_FAILURE;
1363 return LeaveMulticastInternal(prAddr, prIface);
1366 NS_IMETHODIMP
1367 nsUDPSocket::LeaveMulticastAddr(const NetAddr aAddr, const NetAddr* aIface) {
1368 if (NS_WARN_IF(!mFD)) {
1369 return NS_ERROR_NOT_INITIALIZED;
1372 PRNetAddr prAddr;
1373 NetAddrToPRNetAddr(&aAddr, &prAddr);
1375 PRNetAddr prIface;
1376 if (!aIface) {
1377 PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
1378 } else {
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;
1398 return NS_OK;
1401 NS_IMETHODIMP
1402 nsUDPSocket::GetMulticastLoopback(bool* aLoopback) {
1403 return NS_ERROR_NOT_IMPLEMENTED;
1406 NS_IMETHODIMP
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;
1422 return NS_OK;
1425 NS_IMETHODIMP
1426 nsUDPSocket::GetRecvBufferSize(int* size) {
1427 // Bug 1252759 - missing support for GetSocketOption
1428 return NS_ERROR_NOT_IMPLEMENTED;
1431 NS_IMETHODIMP
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;
1447 return NS_OK;
1450 NS_IMETHODIMP
1451 nsUDPSocket::GetDontFragment(bool* dontFragment) {
1452 // Bug 1252759 - missing support for GetSocketOption
1453 return NS_ERROR_NOT_IMPLEMENTED;
1456 NS_IMETHODIMP
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;
1470 return NS_OK;
1473 NS_IMETHODIMP
1474 nsUDPSocket::GetSendBufferSize(int* size) {
1475 // Bug 1252759 - missing support for GetSocketOption
1476 return NS_ERROR_NOT_IMPLEMENTED;
1479 NS_IMETHODIMP
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;
1495 return NS_OK;
1498 NS_IMETHODIMP
1499 nsUDPSocket::GetMulticastInterface(nsACString& aIface) {
1500 return NS_ERROR_NOT_IMPLEMENTED;
1503 NS_IMETHODIMP
1504 nsUDPSocket::GetMulticastInterfaceAddr(NetAddr* aIface) {
1505 return NS_ERROR_NOT_IMPLEMENTED;
1508 NS_IMETHODIMP
1509 nsUDPSocket::SetMulticastInterface(const nsACString& aIface) {
1510 if (NS_WARN_IF(!mFD)) {
1511 return NS_ERROR_NOT_INITIALIZED;
1514 PRNetAddr prIface;
1515 if (aIface.IsEmpty()) {
1516 PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
1517 } else {
1518 if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
1519 return NS_ERROR_FAILURE;
1523 return SetMulticastInterfaceInternal(prIface);
1526 NS_IMETHODIMP
1527 nsUDPSocket::SetMulticastInterfaceAddr(NetAddr aIface) {
1528 if (NS_WARN_IF(!mFD)) {
1529 return NS_ERROR_NOT_INITIALIZED;
1532 PRNetAddr prIface;
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;
1549 return NS_OK;
1552 } // namespace net
1553 } // namespace mozilla