LCOV - code coverage report
Current view: top level - netwerk/base - nsUDPSocket.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 656 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 138 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #include "mozilla/Attributes.h"
       7             : #include "mozilla/EndianUtils.h"
       8             : #include "mozilla/dom/TypedArray.h"
       9             : #include "mozilla/HoldDropJSObjects.h"
      10             : #include "mozilla/SizePrintfMacros.h"
      11             : #include "mozilla/Telemetry.h"
      12             : 
      13             : #include "nsSocketTransport2.h"
      14             : #include "nsUDPSocket.h"
      15             : #include "nsProxyRelease.h"
      16             : #include "nsAutoPtr.h"
      17             : #include "nsError.h"
      18             : #include "nsNetCID.h"
      19             : #include "nsNetUtil.h"
      20             : #include "nsIOService.h"
      21             : #include "prnetdb.h"
      22             : #include "prio.h"
      23             : #include "nsNetAddr.h"
      24             : #include "nsNetSegmentUtils.h"
      25             : #include "NetworkActivityMonitor.h"
      26             : #include "nsServiceManagerUtils.h"
      27             : #include "nsStreamUtils.h"
      28             : #include "nsIPipe.h"
      29             : #include "prerror.h"
      30             : #include "nsThreadUtils.h"
      31             : #include "nsIDNSRecord.h"
      32             : #include "nsIDNSService.h"
      33             : #include "nsICancelable.h"
      34             : #include "nsWrapperCacheInlines.h"
      35             : 
      36             : namespace mozilla {
      37             : namespace net {
      38             : 
      39             : static const uint32_t UDP_PACKET_CHUNK_SIZE = 1400;
      40             : 
      41             : //-----------------------------------------------------------------------------
      42             : 
      43             : typedef void (nsUDPSocket:: *nsUDPSocketFunc)(void);
      44             : 
      45             : static nsresult
      46           0 : PostEvent(nsUDPSocket *s, nsUDPSocketFunc func)
      47             : {
      48           0 :   if (!gSocketTransportService)
      49           0 :     return NS_ERROR_FAILURE;
      50             : 
      51           0 :   return gSocketTransportService->Dispatch(
      52           0 :     NewRunnableMethod("net::PostEvent", s, func), NS_DISPATCH_NORMAL);
      53             : }
      54             : 
      55             : static nsresult
      56           0 : ResolveHost(const nsACString &host, const OriginAttributes& aOriginAttributes,
      57             :             nsIDNSListener *listener)
      58             : {
      59             :   nsresult rv;
      60             : 
      61             :   nsCOMPtr<nsIDNSService> dns =
      62           0 :       do_GetService("@mozilla.org/network/dns-service;1", &rv);
      63           0 :   if (NS_FAILED(rv)) {
      64           0 :     return rv;
      65             :   }
      66             : 
      67           0 :   nsCOMPtr<nsICancelable> tmpOutstanding;
      68           0 :   return dns->AsyncResolveNative(host, 0, listener, nullptr, aOriginAttributes,
      69           0 :                                  getter_AddRefs(tmpOutstanding));
      70             : 
      71             : }
      72             : 
      73             : static nsresult
      74           0 : CheckIOStatus(const NetAddr *aAddr)
      75             : {
      76           0 :   MOZ_ASSERT(gIOService);
      77             : 
      78           0 :   if (gIOService->IsNetTearingDown()) {
      79           0 :     return NS_ERROR_FAILURE;
      80             :   }
      81             : 
      82           0 :   if (gIOService->IsOffline() && !IsLoopBackAddress(aAddr)) {
      83           0 :     return NS_ERROR_OFFLINE;
      84             :   }
      85             : 
      86           0 :   return NS_OK;
      87             : }
      88             : 
      89             : //-----------------------------------------------------------------------------
      90             : 
      91           0 : class SetSocketOptionRunnable : public Runnable
      92             : {
      93             : public:
      94           0 :   SetSocketOptionRunnable(nsUDPSocket* aSocket, const PRSocketOptionData& aOpt)
      95           0 :     : Runnable("net::SetSocketOptionRunnable")
      96             :     , mSocket(aSocket)
      97           0 :     , mOpt(aOpt)
      98           0 :   {}
      99             : 
     100           0 :   NS_IMETHOD Run() override
     101             :   {
     102           0 :     return mSocket->SetSocketOption(mOpt);
     103             :   }
     104             : 
     105             : private:
     106             :   RefPtr<nsUDPSocket> mSocket;
     107             :   PRSocketOptionData    mOpt;
     108             : };
     109             : 
     110             : //-----------------------------------------------------------------------------
     111             : // nsUDPOutputStream impl
     112             : //-----------------------------------------------------------------------------
     113           0 : NS_IMPL_ISUPPORTS(nsUDPOutputStream, nsIOutputStream)
     114             : 
     115           0 : nsUDPOutputStream::nsUDPOutputStream(nsUDPSocket* aSocket,
     116             :                                      PRFileDesc* aFD,
     117           0 :                                      PRNetAddr& aPrClientAddr)
     118             :   : mSocket(aSocket)
     119             :   , mFD(aFD)
     120             :   , mPrClientAddr(aPrClientAddr)
     121           0 :   , mIsClosed(false)
     122             : {
     123           0 : }
     124             : 
     125           0 : nsUDPOutputStream::~nsUDPOutputStream()
     126             : {
     127           0 : }
     128             : 
     129           0 : NS_IMETHODIMP nsUDPOutputStream::Close()
     130             : {
     131           0 :   if (mIsClosed)
     132           0 :     return NS_BASE_STREAM_CLOSED;
     133             : 
     134           0 :   mIsClosed = true;
     135           0 :   return NS_OK;
     136             : }
     137             : 
     138           0 : NS_IMETHODIMP nsUDPOutputStream::Flush()
     139             : {
     140           0 :   return NS_OK;
     141             : }
     142             : 
     143           0 : NS_IMETHODIMP nsUDPOutputStream::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval)
     144             : {
     145           0 :   if (mIsClosed)
     146           0 :     return NS_BASE_STREAM_CLOSED;
     147             : 
     148           0 :   *_retval = 0;
     149           0 :   int32_t count = PR_SendTo(mFD, aBuf, aCount, 0, &mPrClientAddr, PR_INTERVAL_NO_WAIT);
     150           0 :   if (count < 0) {
     151           0 :     PRErrorCode code = PR_GetError();
     152           0 :     return ErrorAccordingToNSPR(code);
     153             :   }
     154             : 
     155           0 :   *_retval = count;
     156             : 
     157           0 :   mSocket->AddOutputBytes(count);
     158             : 
     159           0 :   return NS_OK;
     160             : }
     161             : 
     162           0 : NS_IMETHODIMP nsUDPOutputStream::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval)
     163             : {
     164           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     165             : }
     166             : 
     167           0 : NS_IMETHODIMP nsUDPOutputStream::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval)
     168             : {
     169           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     170             : }
     171             : 
     172           0 : NS_IMETHODIMP nsUDPOutputStream::IsNonBlocking(bool *_retval)
     173             : {
     174           0 :   *_retval = true;
     175           0 :   return NS_OK;
     176             : }
     177             : 
     178             : //-----------------------------------------------------------------------------
     179             : // nsUDPMessage impl
     180             : //-----------------------------------------------------------------------------
     181           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsUDPMessage)
     182           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsUDPMessage)
     183             : 
     184             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsUDPMessage)
     185             : 
     186           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsUDPMessage)
     187           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     188           0 :   NS_INTERFACE_MAP_ENTRY(nsIUDPMessage)
     189           0 : NS_INTERFACE_MAP_END
     190             : 
     191           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsUDPMessage)
     192           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsobj)
     193           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     194             : 
     195           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsUDPMessage)
     196           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     197             : 
     198           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsUDPMessage)
     199           0 :   tmp->mJsobj = nullptr;
     200           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     201             : 
     202           0 : nsUDPMessage::nsUDPMessage(NetAddr* aAddr,
     203             :                            nsIOutputStream* aOutputStream,
     204           0 :                            FallibleTArray<uint8_t>& aData)
     205           0 :   : mOutputStream(aOutputStream)
     206             : {
     207           0 :   memcpy(&mAddr, aAddr, sizeof(NetAddr));
     208           0 :   aData.SwapElements(mData);
     209           0 : }
     210             : 
     211           0 : nsUDPMessage::~nsUDPMessage()
     212             : {
     213           0 :   DropJSObjects(this);
     214           0 : }
     215             : 
     216             : NS_IMETHODIMP
     217           0 : nsUDPMessage::GetFromAddr(nsINetAddr * *aFromAddr)
     218             : {
     219           0 :   NS_ENSURE_ARG_POINTER(aFromAddr);
     220             : 
     221           0 :   nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
     222           0 :   result.forget(aFromAddr);
     223             : 
     224           0 :   return NS_OK;
     225             : }
     226             : 
     227             : NS_IMETHODIMP
     228           0 : nsUDPMessage::GetData(nsACString & aData)
     229             : {
     230           0 :   aData.Assign(reinterpret_cast<const char*>(mData.Elements()), mData.Length());
     231           0 :   return NS_OK;
     232             : }
     233             : 
     234             : NS_IMETHODIMP
     235           0 : nsUDPMessage::GetOutputStream(nsIOutputStream * *aOutputStream)
     236             : {
     237           0 :   NS_ENSURE_ARG_POINTER(aOutputStream);
     238           0 :   NS_IF_ADDREF(*aOutputStream = mOutputStream);
     239           0 :   return NS_OK;
     240             : }
     241             : 
     242             : NS_IMETHODIMP
     243           0 : nsUDPMessage::GetRawData(JSContext* cx,
     244             :                          JS::MutableHandleValue aRawData)
     245             : {
     246           0 :   if(!mJsobj){
     247           0 :     mJsobj = dom::Uint8Array::Create(cx, nullptr, mData.Length(), mData.Elements());
     248           0 :     HoldJSObjects(this);
     249             :   }
     250           0 :   aRawData.setObject(*mJsobj);
     251           0 :   return NS_OK;
     252             : }
     253             : 
     254             : FallibleTArray<uint8_t>&
     255           0 : nsUDPMessage::GetDataAsTArray()
     256             : {
     257           0 :   return mData;
     258             : }
     259             : 
     260             : //-----------------------------------------------------------------------------
     261             : // nsUDPSocket
     262             : //-----------------------------------------------------------------------------
     263             : 
     264           0 : nsUDPSocket::nsUDPSocket()
     265             :   : mLock("nsUDPSocket.mLock")
     266             :   , mFD(nullptr)
     267             :   , mOriginAttributes()
     268             :   , mAttached(false)
     269             :   , mByteReadCount(0)
     270           0 :   , mByteWriteCount(0)
     271             : {
     272           0 :   mAddr.raw.family = PR_AF_UNSPEC;
     273             :   // we want to be able to access the STS directly, and it may not have been
     274             :   // constructed yet.  the STS constructor sets gSocketTransportService.
     275           0 :   if (!gSocketTransportService)
     276             :   {
     277             :     // This call can fail if we're offline, for example.
     278             :     nsCOMPtr<nsISocketTransportService> sts =
     279           0 :         do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
     280             :   }
     281             : 
     282           0 :   mSts = gSocketTransportService;
     283           0 : }
     284             : 
     285           0 : nsUDPSocket::~nsUDPSocket()
     286             : {
     287           0 :   CloseSocket();
     288           0 : }
     289             : 
     290             : void
     291           0 : nsUDPSocket::AddOutputBytes(uint64_t aBytes)
     292             : {
     293           0 :   mByteWriteCount += aBytes;
     294           0 : }
     295             : 
     296             : void
     297           0 : nsUDPSocket::OnMsgClose()
     298             : {
     299           0 :   UDPSOCKET_LOG(("nsUDPSocket::OnMsgClose [this=%p]\n", this));
     300             : 
     301           0 :   if (NS_FAILED(mCondition))
     302           0 :     return;
     303             : 
     304             :   // tear down socket.  this signals the STS to detach our socket handler.
     305           0 :   mCondition = NS_BINDING_ABORTED;
     306             : 
     307             :   // if we are attached, then socket transport service will call our
     308             :   // OnSocketDetached method automatically. Otherwise, we have to call it
     309             :   // (and thus close the socket) manually.
     310           0 :   if (!mAttached)
     311           0 :     OnSocketDetached(mFD);
     312             : }
     313             : 
     314             : void
     315           0 : nsUDPSocket::OnMsgAttach()
     316             : {
     317           0 :   UDPSOCKET_LOG(("nsUDPSocket::OnMsgAttach [this=%p]\n", this));
     318             : 
     319           0 :   if (NS_FAILED(mCondition))
     320           0 :     return;
     321             : 
     322           0 :   mCondition = TryAttach();
     323             : 
     324             :   // if we hit an error while trying to attach then bail...
     325           0 :   if (NS_FAILED(mCondition))
     326             :   {
     327           0 :     NS_ASSERTION(!mAttached, "should not be attached already");
     328           0 :     OnSocketDetached(mFD);
     329             :   }
     330             : }
     331             : 
     332             : nsresult
     333           0 : nsUDPSocket::TryAttach()
     334             : {
     335             :   nsresult rv;
     336             : 
     337           0 :   if (!gSocketTransportService)
     338           0 :     return NS_ERROR_FAILURE;
     339             : 
     340           0 :   rv = CheckIOStatus(&mAddr);
     341           0 :   if (NS_FAILED(rv)) {
     342           0 :     return rv;
     343             :   }
     344             : 
     345             :   //
     346             :   // find out if it is going to be ok to attach another socket to the STS.
     347             :   // if not then we have to wait for the STS to tell us that it is ok.
     348             :   // the notification is asynchronous, which means that when we could be
     349             :   // in a race to call AttachSocket once notified.  for this reason, when
     350             :   // we get notified, we just re-enter this function.  as a result, we are
     351             :   // sure to ask again before calling AttachSocket.  in this way we deal
     352             :   // with the race condition.  though it isn't the most elegant solution,
     353             :   // it is far simpler than trying to build a system that would guarantee
     354             :   // FIFO ordering (which wouldn't even be that valuable IMO).  see bug
     355             :   // 194402 for more info.
     356             :   //
     357           0 :   if (!gSocketTransportService->CanAttachSocket())
     358             :   {
     359           0 :     nsCOMPtr<nsIRunnable> event = NewRunnableMethod(
     360           0 :       "net::nsUDPSocket::OnMsgAttach", this, &nsUDPSocket::OnMsgAttach);
     361             : 
     362           0 :     nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event);
     363           0 :     if (NS_FAILED(rv))
     364           0 :       return rv;
     365             :   }
     366             : 
     367             :   //
     368             :   // ok, we can now attach our socket to the STS for polling
     369             :   //
     370           0 :   rv = gSocketTransportService->AttachSocket(mFD, this);
     371           0 :   if (NS_FAILED(rv))
     372           0 :     return rv;
     373             : 
     374           0 :   mAttached = true;
     375             : 
     376             :   //
     377             :   // now, configure our poll flags for listening...
     378             :   //
     379           0 :   mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT);
     380           0 :   return NS_OK;
     381             : }
     382             : 
     383             : namespace {
     384             : //-----------------------------------------------------------------------------
     385             : // UDPMessageProxy
     386             : //-----------------------------------------------------------------------------
     387             : class UDPMessageProxy final : public nsIUDPMessage
     388             : {
     389             : public:
     390           0 :   UDPMessageProxy(NetAddr* aAddr,
     391             :                   nsIOutputStream* aOutputStream,
     392             :                   FallibleTArray<uint8_t>& aData)
     393           0 :   : mOutputStream(aOutputStream)
     394             :   {
     395           0 :     memcpy(&mAddr, aAddr, sizeof(mAddr));
     396           0 :     aData.SwapElements(mData);
     397           0 :   }
     398             : 
     399             :   NS_DECL_THREADSAFE_ISUPPORTS
     400             :   NS_DECL_NSIUDPMESSAGE
     401             : 
     402             : private:
     403           0 :   ~UDPMessageProxy() {}
     404             : 
     405             :   NetAddr mAddr;
     406             :   nsCOMPtr<nsIOutputStream> mOutputStream;
     407             :   FallibleTArray<uint8_t> mData;
     408             : };
     409             : 
     410           0 : NS_IMPL_ISUPPORTS(UDPMessageProxy, nsIUDPMessage)
     411             : 
     412             : NS_IMETHODIMP
     413           0 : UDPMessageProxy::GetFromAddr(nsINetAddr * *aFromAddr)
     414             : {
     415           0 :   NS_ENSURE_ARG_POINTER(aFromAddr);
     416             : 
     417           0 :   nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
     418           0 :   result.forget(aFromAddr);
     419             : 
     420           0 :   return NS_OK;
     421             : }
     422             : 
     423             : NS_IMETHODIMP
     424           0 : UDPMessageProxy::GetData(nsACString & aData)
     425             : {
     426           0 :   aData.Assign(reinterpret_cast<const char*>(mData.Elements()), mData.Length());
     427           0 :   return NS_OK;
     428             : }
     429             : 
     430             : FallibleTArray<uint8_t>&
     431           0 : UDPMessageProxy::GetDataAsTArray()
     432             : {
     433           0 :   return mData;
     434             : }
     435             : 
     436             : NS_IMETHODIMP
     437           0 : UDPMessageProxy::GetRawData(JSContext* cx,
     438             :                             JS::MutableHandleValue aRawData)
     439             : {
     440           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     441             : }
     442             : 
     443             : NS_IMETHODIMP
     444           0 : UDPMessageProxy::GetOutputStream(nsIOutputStream * *aOutputStream)
     445             : {
     446           0 :   NS_ENSURE_ARG_POINTER(aOutputStream);
     447           0 :   NS_IF_ADDREF(*aOutputStream = mOutputStream);
     448           0 :   return NS_OK;
     449             : }
     450             : 
     451             : } //anonymous namespace
     452             : 
     453             : //-----------------------------------------------------------------------------
     454             : // nsUDPSocket::nsASocketHandler
     455             : //-----------------------------------------------------------------------------
     456             : 
     457             : void
     458           0 : nsUDPSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags)
     459             : {
     460           0 :   NS_ASSERTION(NS_SUCCEEDED(mCondition), "oops");
     461           0 :   NS_ASSERTION(mFD == fd, "wrong file descriptor");
     462           0 :   NS_ASSERTION(outFlags != -1, "unexpected timeout condition reached");
     463             : 
     464           0 :   if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL))
     465             :   {
     466           0 :     NS_WARNING("error polling on listening socket");
     467           0 :     mCondition = NS_ERROR_UNEXPECTED;
     468           0 :     return;
     469             :   }
     470             : 
     471             :   PRNetAddr prClientAddr;
     472             :   uint32_t count;
     473             :   // Bug 1252755 - use 9216 bytes to allign with nICEr and transportlayer to
     474             :   // support the maximum size of jumbo frames
     475             :   char buff[9216];
     476           0 :   count = PR_RecvFrom(mFD, buff, sizeof(buff), 0, &prClientAddr, PR_INTERVAL_NO_WAIT);
     477           0 :   mByteReadCount += count;
     478             : 
     479           0 :   FallibleTArray<uint8_t> data;
     480           0 :   if (!data.AppendElements(buff, count, fallible)) {
     481           0 :     mCondition = NS_ERROR_UNEXPECTED;
     482           0 :     return;
     483             :   }
     484             : 
     485           0 :   nsCOMPtr<nsIAsyncInputStream> pipeIn;
     486           0 :   nsCOMPtr<nsIAsyncOutputStream> pipeOut;
     487             : 
     488           0 :   uint32_t segsize = UDP_PACKET_CHUNK_SIZE;
     489           0 :   uint32_t segcount = 0;
     490           0 :   net_ResolveSegmentParams(segsize, segcount);
     491           0 :   nsresult rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
     492           0 :                 true, true, segsize, segcount);
     493             : 
     494           0 :   if (NS_FAILED(rv)) {
     495           0 :     return;
     496             :   }
     497             : 
     498           0 :   RefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prClientAddr);
     499           0 :   rv = NS_AsyncCopy(pipeIn, os, mSts,
     500           0 :                     NS_ASYNCCOPY_VIA_READSEGMENTS, UDP_PACKET_CHUNK_SIZE);
     501             : 
     502           0 :   if (NS_FAILED(rv)) {
     503           0 :     return;
     504             :   }
     505             : 
     506             :   NetAddr netAddr;
     507           0 :   PRNetAddrToNetAddr(&prClientAddr, &netAddr);
     508           0 :   nsCOMPtr<nsIUDPMessage> message = new UDPMessageProxy(&netAddr, pipeOut, data);
     509           0 :   mListener->OnPacketReceived(this, message);
     510             : }
     511             : 
     512             : void
     513           0 : nsUDPSocket::OnSocketDetached(PRFileDesc *fd)
     514             : {
     515             :   // force a failure condition if none set; maybe the STS is shutting down :-/
     516           0 :   if (NS_SUCCEEDED(mCondition))
     517           0 :     mCondition = NS_ERROR_ABORT;
     518             : 
     519           0 :   if (mFD)
     520             :   {
     521           0 :     NS_ASSERTION(mFD == fd, "wrong file descriptor");
     522           0 :     CloseSocket();
     523             :   }
     524             : 
     525           0 :   if (mListener)
     526             :   {
     527             :     // need to atomically clear mListener.  see our Close() method.
     528           0 :     RefPtr<nsIUDPSocketListener> listener = nullptr;
     529             :     {
     530           0 :       MutexAutoLock lock(mLock);
     531           0 :       listener = mListener.forget();
     532             :     }
     533             : 
     534           0 :     if (listener) {
     535           0 :       listener->OnStopListening(this, mCondition);
     536           0 :       NS_ProxyRelease(
     537           0 :         "nsUDPSocket::mListener", mListenerTarget, listener.forget());
     538             :     }
     539             :   }
     540           0 : }
     541             : 
     542             : void
     543           0 : nsUDPSocket::IsLocal(bool *aIsLocal)
     544             : {
     545             :   // If bound to loopback, this UDP socket only accepts local connections.
     546           0 :   *aIsLocal = IsLoopBackAddress(&mAddr);
     547           0 : }
     548             : 
     549             : //-----------------------------------------------------------------------------
     550             : // nsSocket::nsISupports
     551             : //-----------------------------------------------------------------------------
     552             : 
     553           0 : NS_IMPL_ISUPPORTS(nsUDPSocket, nsIUDPSocket)
     554             : 
     555             : 
     556             : //-----------------------------------------------------------------------------
     557             : // nsSocket::nsISocket
     558             : //-----------------------------------------------------------------------------
     559             : 
     560             : NS_IMETHODIMP
     561           0 : nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly, nsIPrincipal *aPrincipal,
     562             :                   bool aAddressReuse, uint8_t aOptionalArgc)
     563             : {
     564             :   NetAddr addr;
     565             : 
     566           0 :   if (aPort < 0)
     567           0 :     aPort = 0;
     568             : 
     569           0 :   addr.raw.family = AF_INET;
     570           0 :   addr.inet.port = htons(aPort);
     571             : 
     572           0 :   if (aLoopbackOnly)
     573           0 :     addr.inet.ip = htonl(INADDR_LOOPBACK);
     574             :   else
     575           0 :     addr.inet.ip = htonl(INADDR_ANY);
     576             : 
     577           0 :   return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
     578             : }
     579             : 
     580             : NS_IMETHODIMP
     581           0 : nsUDPSocket::Init2(const nsACString& aAddr, int32_t aPort, nsIPrincipal *aPrincipal,
     582             :                    bool aAddressReuse, uint8_t aOptionalArgc)
     583             : {
     584           0 :   if (NS_WARN_IF(aAddr.IsEmpty())) {
     585           0 :     return NS_ERROR_INVALID_ARG;
     586             :   }
     587             : 
     588             :   PRNetAddr prAddr;
     589           0 :   memset(&prAddr, 0, sizeof(prAddr));
     590           0 :   if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
     591           0 :     return NS_ERROR_FAILURE;
     592             :   }
     593             : 
     594           0 :   if (aPort < 0) {
     595           0 :     aPort = 0;
     596             :   }
     597             : 
     598           0 :   switch (prAddr.raw.family) {
     599             :     case PR_AF_INET:
     600           0 :       prAddr.inet.port = PR_htons(aPort);
     601           0 :       break;
     602             :     case PR_AF_INET6:
     603           0 :       prAddr.ipv6.port = PR_htons(aPort);
     604           0 :       break;
     605             :     default:
     606           0 :       MOZ_ASSERT_UNREACHABLE("Dont accept address other than IPv4 and IPv6");
     607             :       return NS_ERROR_ILLEGAL_VALUE;
     608             :   }
     609             : 
     610             :   NetAddr addr;
     611           0 :   PRNetAddrToNetAddr(&prAddr, &addr);
     612             : 
     613           0 :   return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
     614             : }
     615             : 
     616             : NS_IMETHODIMP
     617           0 : nsUDPSocket::InitWithAddress(const NetAddr *aAddr, nsIPrincipal *aPrincipal,
     618             :                              bool aAddressReuse, uint8_t aOptionalArgc)
     619             : {
     620           0 :   NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
     621             : 
     622             :   nsresult rv;
     623             : 
     624           0 :   rv = CheckIOStatus(aAddr);
     625           0 :   if (NS_FAILED(rv)) {
     626           0 :     return rv;
     627             :   }
     628             : 
     629           0 :   bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
     630             : 
     631           0 :   if (aPrincipal) {
     632           0 :     mOriginAttributes = aPrincipal->OriginAttributesRef();
     633             :   }
     634             :   //
     635             :   // configure listening socket...
     636             :   //
     637             : 
     638           0 :   mFD = PR_OpenUDPSocket(aAddr->raw.family);
     639           0 :   if (!mFD)
     640             :   {
     641           0 :     NS_WARNING("unable to create UDP socket");
     642           0 :     return NS_ERROR_FAILURE;
     643             :   }
     644             : 
     645             :   uint16_t port;
     646           0 :   if (NS_FAILED(net::GetPort(aAddr, &port))) {
     647           0 :     NS_WARNING("invalid bind address");
     648           0 :     goto fail;
     649             :   }
     650             : 
     651             :   PRSocketOptionData opt;
     652             : 
     653             :   // Linux kernel will sometimes hand out a used port if we bind
     654             :   // to port 0 with SO_REUSEADDR
     655           0 :   if (port) {
     656           0 :     opt.option = PR_SockOpt_Reuseaddr;
     657           0 :     opt.value.reuse_addr = addressReuse;
     658           0 :     PR_SetSocketOption(mFD, &opt);
     659             :   }
     660             : 
     661           0 :   opt.option = PR_SockOpt_Nonblocking;
     662           0 :   opt.value.non_blocking = true;
     663           0 :   PR_SetSocketOption(mFD, &opt);
     664             : 
     665             :   PRNetAddr addr;
     666             :   // Temporary work around for IPv6 until bug 1330490 is fixed
     667           0 :   memset(&addr, 0, sizeof(addr));
     668           0 :   NetAddrToPRNetAddr(aAddr, &addr);
     669             : 
     670           0 :   if (PR_Bind(mFD, &addr) != PR_SUCCESS)
     671             :   {
     672           0 :     NS_WARNING("failed to bind socket");
     673           0 :     goto fail;
     674             :   }
     675             : 
     676             :   // get the resulting socket address, which may be different than what
     677             :   // we passed to bind.
     678           0 :   if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
     679             :   {
     680           0 :     NS_WARNING("cannot get socket name");
     681           0 :     goto fail;
     682             :   }
     683             : 
     684           0 :   PRNetAddrToNetAddr(&addr, &mAddr);
     685             : 
     686             :   // create proxy via NetworkActivityMonitor
     687           0 :   NetworkActivityMonitor::AttachIOLayer(mFD);
     688             : 
     689             :   // wait until AsyncListen is called before polling the socket for
     690             :   // client connections.
     691           0 :   return NS_OK;
     692             : 
     693             : fail:
     694           0 :   Close();
     695           0 :   return NS_ERROR_FAILURE;
     696             : }
     697             : 
     698             : NS_IMETHODIMP
     699           0 : nsUDPSocket::Connect(const NetAddr *aAddr)
     700             : {
     701           0 :   UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
     702             : 
     703           0 :   NS_ENSURE_ARG(aAddr);
     704             : 
     705           0 :   if (NS_WARN_IF(!mFD)) {
     706           0 :     return NS_ERROR_NOT_INITIALIZED;
     707             :   }
     708             : 
     709             :   nsresult rv;
     710             : 
     711           0 :   rv = CheckIOStatus(aAddr);
     712           0 :   if (NS_FAILED(rv)) {
     713           0 :     return rv;
     714             :   }
     715             : 
     716           0 :   bool onSTSThread = false;
     717           0 :   mSts->IsOnCurrentThread(&onSTSThread);
     718           0 :   NS_ASSERTION(onSTSThread, "NOT ON STS THREAD");
     719           0 :   if (!onSTSThread) {
     720           0 :     return NS_ERROR_FAILURE;
     721             :   }
     722             : 
     723             :   PRNetAddr prAddr;
     724           0 :   memset(&prAddr, 0, sizeof(prAddr));
     725           0 :   NetAddrToPRNetAddr(aAddr, &prAddr);
     726             : 
     727           0 :   if (PR_Connect(mFD, &prAddr, PR_INTERVAL_NO_WAIT) != PR_SUCCESS) {
     728           0 :     NS_WARNING("Cannot PR_Connect");
     729           0 :     return NS_ERROR_FAILURE;
     730             :   }
     731             : 
     732             :   // get the resulting socket address, which may have been updated.
     733             :   PRNetAddr addr;
     734           0 :   if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
     735             :   {
     736           0 :     NS_WARNING("cannot get socket name");
     737           0 :     return NS_ERROR_FAILURE;
     738             :   }
     739             : 
     740           0 :   PRNetAddrToNetAddr(&addr, &mAddr);
     741             : 
     742           0 :   return NS_OK;
     743             : }
     744             : 
     745             : NS_IMETHODIMP
     746           0 : nsUDPSocket::Close()
     747             : {
     748             :   {
     749           0 :     MutexAutoLock lock(mLock);
     750             :     // we want to proxy the close operation to the socket thread if a listener
     751             :     // has been set.  otherwise, we should just close the socket here...
     752           0 :     if (!mListener)
     753             :     {
     754             :       // Here we want to go directly with closing the socket since some tests
     755             :       // expects this happen synchronously.
     756           0 :       CloseSocket();
     757             : 
     758           0 :       return NS_OK;
     759             :     }
     760             :   }
     761           0 :   return PostEvent(this, &nsUDPSocket::OnMsgClose);
     762             : }
     763             : 
     764             : NS_IMETHODIMP
     765           0 : nsUDPSocket::GetPort(int32_t *aResult)
     766             : {
     767             :   // no need to enter the lock here
     768             :   uint16_t result;
     769           0 :   nsresult rv = net::GetPort(&mAddr, &result);
     770           0 :   *aResult = static_cast<int32_t>(result);
     771           0 :   return rv;
     772             : }
     773             : 
     774             : NS_IMETHODIMP
     775           0 : nsUDPSocket::GetLocalAddr(nsINetAddr * *aResult)
     776             : {
     777           0 :   NS_ENSURE_ARG_POINTER(aResult);
     778             : 
     779           0 :   nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
     780           0 :   result.forget(aResult);
     781             : 
     782           0 :   return NS_OK;
     783             : }
     784             : 
     785             : void
     786           0 : nsUDPSocket::CloseSocket()
     787             : {
     788           0 :   if (mFD) {
     789           0 :     if (gIOService->IsNetTearingDown() &&
     790           0 :         ((PR_IntervalNow() - gIOService->NetTearingDownStarted()) >
     791           0 :          gSocketTransportService->MaxTimeForPrClosePref())) {
     792             :       // If shutdown last to long, let the socket leak and do not close it.
     793           0 :       UDPSOCKET_LOG(("Intentional leak"));
     794             :     } else {
     795             : 
     796           0 :       PRIntervalTime closeStarted = 0;
     797           0 :       if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase()) {
     798           0 :         closeStarted = PR_IntervalNow();
     799             :       }
     800             : 
     801           0 :       PR_Close(mFD);
     802             : 
     803           0 :       if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase()) {
     804           0 :         PRIntervalTime now = PR_IntervalNow();
     805           0 :         if (gIOService->IsNetTearingDown()) {
     806           0 :           Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN,
     807           0 :                                 PR_IntervalToMilliseconds(now - closeStarted));
     808             : 
     809           0 :         } else if (PR_IntervalToSeconds(now - gIOService->LastConnectivityChange())
     810             :                    < 60) {
     811           0 :           Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE,
     812           0 :                                 PR_IntervalToMilliseconds(now - closeStarted));
     813             : 
     814           0 :         } else if (PR_IntervalToSeconds(now - gIOService->LastNetworkLinkChange())
     815             :                    < 60) {
     816           0 :           Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE,
     817           0 :                                 PR_IntervalToMilliseconds(now - closeStarted));
     818             : 
     819           0 :         } else if (PR_IntervalToSeconds(now - gIOService->LastOfflineStateChange())
     820             :                    < 60) {
     821           0 :           Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE,
     822           0 :                                 PR_IntervalToMilliseconds(now - closeStarted));
     823             : 
     824             :         } else {
     825           0 :           Telemetry::Accumulate(Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL,
     826           0 :                                 PR_IntervalToMilliseconds(now - closeStarted));
     827             :         }
     828             :       }
     829             :     }
     830           0 :     mFD = nullptr;
     831             :   }
     832           0 : }
     833             : 
     834             : NS_IMETHODIMP
     835           0 : nsUDPSocket::GetAddress(NetAddr *aResult)
     836             : {
     837             :   // no need to enter the lock here
     838           0 :   memcpy(aResult, &mAddr, sizeof(mAddr));
     839           0 :   return NS_OK;
     840             : }
     841             : 
     842             : namespace {
     843             : //-----------------------------------------------------------------------------
     844             : // SocketListenerProxy
     845             : //-----------------------------------------------------------------------------
     846             : class SocketListenerProxy final : public nsIUDPSocketListener
     847             : {
     848           0 :   ~SocketListenerProxy() {}
     849             : 
     850             : public:
     851           0 :   explicit SocketListenerProxy(nsIUDPSocketListener* aListener)
     852           0 :     : mListener(new nsMainThreadPtrHolder<nsIUDPSocketListener>(
     853           0 :         "SocketListenerProxy::mListener", aListener))
     854           0 :     , mTarget(GetCurrentThreadEventTarget())
     855           0 :   { }
     856             : 
     857             :   NS_DECL_THREADSAFE_ISUPPORTS
     858             :   NS_DECL_NSIUDPSOCKETLISTENER
     859             : 
     860           0 :   class OnPacketReceivedRunnable : public Runnable
     861             :   {
     862             :   public:
     863           0 :     OnPacketReceivedRunnable(
     864             :       const nsMainThreadPtrHandle<nsIUDPSocketListener>& aListener,
     865             :       nsIUDPSocket* aSocket,
     866             :       nsIUDPMessage* aMessage)
     867           0 :       : Runnable("net::SocketListenerProxy::OnPacketReceivedRunnable")
     868             :       , mListener(aListener)
     869             :       , mSocket(aSocket)
     870           0 :       , mMessage(aMessage)
     871           0 :     { }
     872             : 
     873             :     NS_DECL_NSIRUNNABLE
     874             : 
     875             :   private:
     876             :     nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
     877             :     nsCOMPtr<nsIUDPSocket> mSocket;
     878             :     nsCOMPtr<nsIUDPMessage> mMessage;
     879             :   };
     880             : 
     881           0 :   class OnStopListeningRunnable : public Runnable
     882             :   {
     883             :   public:
     884           0 :     OnStopListeningRunnable(
     885             :       const nsMainThreadPtrHandle<nsIUDPSocketListener>& aListener,
     886             :       nsIUDPSocket* aSocket,
     887             :       nsresult aStatus)
     888           0 :       : Runnable("net::SocketListenerProxy::OnStopListeningRunnable")
     889             :       , mListener(aListener)
     890             :       , mSocket(aSocket)
     891           0 :       , mStatus(aStatus)
     892           0 :     { }
     893             : 
     894             :     NS_DECL_NSIRUNNABLE
     895             : 
     896             :   private:
     897             :     nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
     898             :     nsCOMPtr<nsIUDPSocket> mSocket;
     899             :     nsresult mStatus;
     900             :   };
     901             : 
     902             : private:
     903             :   nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
     904             :   nsCOMPtr<nsIEventTarget> mTarget;
     905             : };
     906             : 
     907           0 : NS_IMPL_ISUPPORTS(SocketListenerProxy,
     908             :                   nsIUDPSocketListener)
     909             : 
     910             : NS_IMETHODIMP
     911           0 : SocketListenerProxy::OnPacketReceived(nsIUDPSocket* aSocket,
     912             :                                       nsIUDPMessage* aMessage)
     913             : {
     914             :   RefPtr<OnPacketReceivedRunnable> r =
     915           0 :     new OnPacketReceivedRunnable(mListener, aSocket, aMessage);
     916           0 :   return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
     917             : }
     918             : 
     919             : NS_IMETHODIMP
     920           0 : SocketListenerProxy::OnStopListening(nsIUDPSocket* aSocket,
     921             :                                      nsresult aStatus)
     922             : {
     923             :   RefPtr<OnStopListeningRunnable> r =
     924           0 :     new OnStopListeningRunnable(mListener, aSocket, aStatus);
     925           0 :   return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
     926             : }
     927             : 
     928             : NS_IMETHODIMP
     929           0 : SocketListenerProxy::OnPacketReceivedRunnable::Run()
     930             : {
     931             :   NetAddr netAddr;
     932           0 :   nsCOMPtr<nsINetAddr> nsAddr;
     933           0 :   mMessage->GetFromAddr(getter_AddRefs(nsAddr));
     934           0 :   nsAddr->GetNetAddr(&netAddr);
     935             : 
     936           0 :   nsCOMPtr<nsIOutputStream> outputStream;
     937           0 :   mMessage->GetOutputStream(getter_AddRefs(outputStream));
     938             : 
     939           0 :   FallibleTArray<uint8_t>& data = mMessage->GetDataAsTArray();
     940             : 
     941             :   nsCOMPtr<nsIUDPMessage> message = new nsUDPMessage(&netAddr,
     942             :                                                      outputStream,
     943           0 :                                                      data);
     944           0 :   mListener->OnPacketReceived(mSocket, message);
     945           0 :   return NS_OK;
     946             : }
     947             : 
     948             : NS_IMETHODIMP
     949           0 : SocketListenerProxy::OnStopListeningRunnable::Run()
     950             : {
     951           0 :   mListener->OnStopListening(mSocket, mStatus);
     952           0 :   return NS_OK;
     953             : }
     954             : 
     955             : 
     956             : class SocketListenerProxyBackground final : public nsIUDPSocketListener
     957             : {
     958           0 :   ~SocketListenerProxyBackground() {}
     959             : 
     960             : public:
     961           0 :   explicit SocketListenerProxyBackground(nsIUDPSocketListener* aListener)
     962           0 :     : mListener(aListener)
     963           0 :     , mTarget(GetCurrentThreadEventTarget())
     964           0 :   { }
     965             : 
     966             :   NS_DECL_THREADSAFE_ISUPPORTS
     967             :   NS_DECL_NSIUDPSOCKETLISTENER
     968             : 
     969           0 :   class OnPacketReceivedRunnable : public Runnable
     970             :   {
     971             :   public:
     972           0 :     OnPacketReceivedRunnable(const nsCOMPtr<nsIUDPSocketListener>& aListener,
     973             :                              nsIUDPSocket* aSocket,
     974             :                              nsIUDPMessage* aMessage)
     975           0 :       : Runnable("net::SocketListenerProxyBackground::OnPacketReceivedRunnable")
     976             :       , mListener(aListener)
     977             :       , mSocket(aSocket)
     978           0 :       , mMessage(aMessage)
     979           0 :     { }
     980             : 
     981             :     NS_DECL_NSIRUNNABLE
     982             : 
     983             :   private:
     984             :     nsCOMPtr<nsIUDPSocketListener> mListener;
     985             :     nsCOMPtr<nsIUDPSocket> mSocket;
     986             :     nsCOMPtr<nsIUDPMessage> mMessage;
     987             :   };
     988             : 
     989           0 :   class OnStopListeningRunnable : public Runnable
     990             :   {
     991             :   public:
     992           0 :     OnStopListeningRunnable(const nsCOMPtr<nsIUDPSocketListener>& aListener,
     993             :                             nsIUDPSocket* aSocket,
     994             :                             nsresult aStatus)
     995           0 :       : Runnable("net::SocketListenerProxyBackground::OnStopListeningRunnable")
     996             :       , mListener(aListener)
     997             :       , mSocket(aSocket)
     998           0 :       , mStatus(aStatus)
     999           0 :     { }
    1000             : 
    1001             :     NS_DECL_NSIRUNNABLE
    1002             : 
    1003             :   private:
    1004             :     nsCOMPtr<nsIUDPSocketListener> mListener;
    1005             :     nsCOMPtr<nsIUDPSocket> mSocket;
    1006             :     nsresult mStatus;
    1007             :   };
    1008             : 
    1009             : private:
    1010             :   nsCOMPtr<nsIUDPSocketListener> mListener;
    1011             :   nsCOMPtr<nsIEventTarget> mTarget;
    1012             : };
    1013             : 
    1014           0 : NS_IMPL_ISUPPORTS(SocketListenerProxyBackground,
    1015             :                   nsIUDPSocketListener)
    1016             : 
    1017             : NS_IMETHODIMP
    1018           0 : SocketListenerProxyBackground::OnPacketReceived(nsIUDPSocket* aSocket,
    1019             :                                                 nsIUDPMessage* aMessage)
    1020             : {
    1021             :   RefPtr<OnPacketReceivedRunnable> r =
    1022           0 :     new OnPacketReceivedRunnable(mListener, aSocket, aMessage);
    1023           0 :   return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
    1024             : }
    1025             : 
    1026             : NS_IMETHODIMP
    1027           0 : SocketListenerProxyBackground::OnStopListening(nsIUDPSocket* aSocket,
    1028             :                                                nsresult aStatus)
    1029             : {
    1030             :   RefPtr<OnStopListeningRunnable> r =
    1031           0 :     new OnStopListeningRunnable(mListener, aSocket, aStatus);
    1032           0 :   return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
    1033             : }
    1034             : 
    1035             : NS_IMETHODIMP
    1036           0 : SocketListenerProxyBackground::OnPacketReceivedRunnable::Run()
    1037             : {
    1038             :   NetAddr netAddr;
    1039           0 :   nsCOMPtr<nsINetAddr> nsAddr;
    1040           0 :   mMessage->GetFromAddr(getter_AddRefs(nsAddr));
    1041           0 :   nsAddr->GetNetAddr(&netAddr);
    1042             : 
    1043           0 :   nsCOMPtr<nsIOutputStream> outputStream;
    1044           0 :   mMessage->GetOutputStream(getter_AddRefs(outputStream));
    1045             : 
    1046           0 :   FallibleTArray<uint8_t>& data = mMessage->GetDataAsTArray();
    1047             : 
    1048           0 :   UDPSOCKET_LOG(("%s [this=%p], len %" PRIuSIZE, __FUNCTION__, this, data.Length()));
    1049             :   nsCOMPtr<nsIUDPMessage> message = new UDPMessageProxy(&netAddr,
    1050             :                                                         outputStream,
    1051           0 :                                                         data);
    1052           0 :   mListener->OnPacketReceived(mSocket, message);
    1053           0 :   return NS_OK;
    1054             : }
    1055             : 
    1056             : NS_IMETHODIMP
    1057           0 : SocketListenerProxyBackground::OnStopListeningRunnable::Run()
    1058             : {
    1059           0 :   mListener->OnStopListening(mSocket, mStatus);
    1060           0 :   return NS_OK;
    1061             : }
    1062             : 
    1063             : 
    1064             : class PendingSend : public nsIDNSListener
    1065             : {
    1066             : public:
    1067             :   NS_DECL_THREADSAFE_ISUPPORTS
    1068             :   NS_DECL_NSIDNSLISTENER
    1069             : 
    1070           0 :   PendingSend(nsUDPSocket *aSocket, uint16_t aPort,
    1071             :               FallibleTArray<uint8_t> &aData)
    1072           0 :       : mSocket(aSocket)
    1073           0 :       , mPort(aPort)
    1074             :   {
    1075           0 :     mData.SwapElements(aData);
    1076           0 :   }
    1077             : 
    1078             : private:
    1079           0 :   virtual ~PendingSend() {}
    1080             : 
    1081             :   RefPtr<nsUDPSocket> mSocket;
    1082             :   uint16_t mPort;
    1083             :   FallibleTArray<uint8_t> mData;
    1084             : };
    1085             : 
    1086           0 : NS_IMPL_ISUPPORTS(PendingSend, nsIDNSListener)
    1087             : 
    1088             : NS_IMETHODIMP
    1089           0 : PendingSend::OnLookupComplete(nsICancelable *request,
    1090             :                               nsIDNSRecord  *rec,
    1091             :                               nsresult       status)
    1092             : {
    1093           0 :   if (NS_FAILED(status)) {
    1094           0 :     NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
    1095           0 :     return NS_OK;
    1096             :   }
    1097             : 
    1098             :   NetAddr addr;
    1099           0 :   if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
    1100             :     uint32_t count;
    1101           0 :     nsresult rv = mSocket->SendWithAddress(&addr, mData.Elements(),
    1102           0 :                                            mData.Length(), &count);
    1103           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1104             :   }
    1105             : 
    1106           0 :   return NS_OK;
    1107             : }
    1108             : 
    1109             : class PendingSendStream : public nsIDNSListener
    1110             : {
    1111             : public:
    1112             :   NS_DECL_THREADSAFE_ISUPPORTS
    1113             :   NS_DECL_NSIDNSLISTENER
    1114             : 
    1115           0 :   PendingSendStream(nsUDPSocket *aSocket, uint16_t aPort,
    1116             :                     nsIInputStream *aStream)
    1117           0 :       : mSocket(aSocket)
    1118             :       , mPort(aPort)
    1119           0 :       , mStream(aStream) {}
    1120             : 
    1121             : private:
    1122           0 :   virtual ~PendingSendStream() {}
    1123             : 
    1124             :   RefPtr<nsUDPSocket> mSocket;
    1125             :   uint16_t mPort;
    1126             :   nsCOMPtr<nsIInputStream> mStream;
    1127             : };
    1128             : 
    1129           0 : NS_IMPL_ISUPPORTS(PendingSendStream, nsIDNSListener)
    1130             : 
    1131             : NS_IMETHODIMP
    1132           0 : PendingSendStream::OnLookupComplete(nsICancelable *request,
    1133             :                                     nsIDNSRecord  *rec,
    1134             :                                     nsresult       status)
    1135             : {
    1136           0 :   if (NS_FAILED(status)) {
    1137           0 :     NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
    1138           0 :     return NS_OK;
    1139             :   }
    1140             : 
    1141             :   NetAddr addr;
    1142           0 :   if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
    1143           0 :     nsresult rv = mSocket->SendBinaryStreamWithAddress(&addr, mStream);
    1144           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1145             :   }
    1146             : 
    1147           0 :   return NS_OK;
    1148             : }
    1149             : 
    1150           0 : class SendRequestRunnable: public Runnable {
    1151             : public:
    1152           0 :   SendRequestRunnable(nsUDPSocket* aSocket,
    1153             :                       const NetAddr& aAddr,
    1154             :                       FallibleTArray<uint8_t>&& aData)
    1155           0 :     : Runnable("net::SendRequestRunnable")
    1156             :     , mSocket(aSocket)
    1157             :     , mAddr(aAddr)
    1158           0 :     , mData(Move(aData))
    1159           0 :   { }
    1160             : 
    1161             :   NS_DECL_NSIRUNNABLE
    1162             : 
    1163             : private:
    1164             :   RefPtr<nsUDPSocket> mSocket;
    1165             :   const NetAddr mAddr;
    1166             :   FallibleTArray<uint8_t> mData;
    1167             : };
    1168             : 
    1169             : NS_IMETHODIMP
    1170           0 : SendRequestRunnable::Run()
    1171             : {
    1172             :   uint32_t count;
    1173           0 :   mSocket->SendWithAddress(&mAddr, mData.Elements(),
    1174           0 :                            mData.Length(), &count);
    1175           0 :   return NS_OK;
    1176             : }
    1177             : 
    1178             : } // namespace
    1179             : 
    1180             : NS_IMETHODIMP
    1181           0 : nsUDPSocket::AsyncListen(nsIUDPSocketListener *aListener)
    1182             : {
    1183             :   // ensuring mFD implies ensuring mLock
    1184           0 :   NS_ENSURE_TRUE(mFD, NS_ERROR_NOT_INITIALIZED);
    1185           0 :   NS_ENSURE_TRUE(mListener == nullptr, NS_ERROR_IN_PROGRESS);
    1186             :   {
    1187           0 :     MutexAutoLock lock(mLock);
    1188           0 :     mListenerTarget = GetCurrentThreadEventTarget();
    1189           0 :     if (NS_IsMainThread()) {
    1190             :       // PNecko usage
    1191           0 :       mListener = new SocketListenerProxy(aListener);
    1192             :     } else {
    1193             :       // PBackground usage from media/mtransport
    1194           0 :       mListener = new SocketListenerProxyBackground(aListener);
    1195             :     }
    1196             :   }
    1197           0 :   return PostEvent(this, &nsUDPSocket::OnMsgAttach);
    1198             : }
    1199             : 
    1200             : NS_IMETHODIMP
    1201           0 : nsUDPSocket::Send(const nsACString &aHost, uint16_t aPort,
    1202             :                   const uint8_t *aData, uint32_t aDataLength,
    1203             :                   uint32_t *_retval)
    1204             : {
    1205           0 :   NS_ENSURE_ARG_POINTER(_retval);
    1206           0 :   if (!((aData && aDataLength > 0) ||
    1207           0 :         (!aData && !aDataLength))) {
    1208           0 :     return NS_ERROR_INVALID_ARG;
    1209             :   }
    1210             : 
    1211           0 :   *_retval = 0;
    1212             : 
    1213           0 :   FallibleTArray<uint8_t> fallibleArray;
    1214           0 :   if (!fallibleArray.InsertElementsAt(0, aData, aDataLength, fallible)) {
    1215           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1216             :   }
    1217             : 
    1218           0 :   nsCOMPtr<nsIDNSListener> listener = new PendingSend(this, aPort, fallibleArray);
    1219             : 
    1220           0 :   nsresult rv = ResolveHost(aHost, mOriginAttributes, listener);
    1221           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1222             : 
    1223           0 :   *_retval = aDataLength;
    1224           0 :   return NS_OK;
    1225             : }
    1226             : 
    1227             : NS_IMETHODIMP
    1228           0 : nsUDPSocket::SendWithAddr(nsINetAddr *aAddr, const uint8_t *aData,
    1229             :                           uint32_t aDataLength, uint32_t *_retval)
    1230             : {
    1231           0 :   NS_ENSURE_ARG(aAddr);
    1232           0 :   NS_ENSURE_ARG(aData);
    1233           0 :   NS_ENSURE_ARG_POINTER(_retval);
    1234             : 
    1235             :   NetAddr netAddr;
    1236           0 :   aAddr->GetNetAddr(&netAddr);
    1237           0 :   return SendWithAddress(&netAddr, aData, aDataLength, _retval);
    1238             : }
    1239             : 
    1240             : NS_IMETHODIMP
    1241           0 : nsUDPSocket::SendWithAddress(const NetAddr *aAddr, const uint8_t *aData,
    1242             :                              uint32_t aDataLength, uint32_t *_retval)
    1243             : {
    1244           0 :   NS_ENSURE_ARG(aAddr);
    1245           0 :   NS_ENSURE_ARG(aData);
    1246           0 :   NS_ENSURE_ARG_POINTER(_retval);
    1247             : 
    1248           0 :   *_retval = 0;
    1249             : 
    1250             :   PRNetAddr prAddr;
    1251           0 :   NetAddrToPRNetAddr(aAddr, &prAddr);
    1252             : 
    1253           0 :   bool onSTSThread = false;
    1254           0 :   mSts->IsOnCurrentThread(&onSTSThread);
    1255             : 
    1256           0 :   if (onSTSThread) {
    1257           0 :     MutexAutoLock lock(mLock);
    1258           0 :     if (!mFD) {
    1259             :       // socket is not initialized or has been closed
    1260           0 :       return NS_ERROR_FAILURE;
    1261             :     }
    1262           0 :     int32_t count = PR_SendTo(mFD, aData, sizeof(uint8_t) *aDataLength,
    1263           0 :                               0, &prAddr, PR_INTERVAL_NO_WAIT);
    1264           0 :     if (count < 0) {
    1265           0 :       PRErrorCode code = PR_GetError();
    1266           0 :       return ErrorAccordingToNSPR(code);
    1267             :     }
    1268           0 :     this->AddOutputBytes(count);
    1269           0 :     *_retval = count;
    1270             :   } else {
    1271           0 :     FallibleTArray<uint8_t> fallibleArray;
    1272           0 :     if (!fallibleArray.InsertElementsAt(0, aData, aDataLength, fallible)) {
    1273           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1274             :     }
    1275             : 
    1276           0 :     nsresult rv = mSts->Dispatch(
    1277           0 :       new SendRequestRunnable(this, *aAddr, Move(fallibleArray)),
    1278           0 :       NS_DISPATCH_NORMAL);
    1279           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1280           0 :     *_retval = aDataLength;
    1281             :   }
    1282           0 :   return NS_OK;
    1283             : }
    1284             : 
    1285             : NS_IMETHODIMP
    1286           0 : nsUDPSocket::SendBinaryStream(const nsACString &aHost, uint16_t aPort,
    1287             :                               nsIInputStream *aStream)
    1288             : {
    1289           0 :   NS_ENSURE_ARG(aStream);
    1290             : 
    1291           0 :   nsCOMPtr<nsIDNSListener> listener = new PendingSendStream(this, aPort, aStream);
    1292             : 
    1293           0 :   return ResolveHost(aHost, mOriginAttributes, listener);
    1294             : }
    1295             : 
    1296             : NS_IMETHODIMP
    1297           0 : nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr *aAddr, nsIInputStream *aStream)
    1298             : {
    1299           0 :   NS_ENSURE_ARG(aAddr);
    1300           0 :   NS_ENSURE_ARG(aStream);
    1301             : 
    1302             :   PRNetAddr prAddr;
    1303           0 :   PR_InitializeNetAddr(PR_IpAddrAny, 0, &prAddr);
    1304           0 :   NetAddrToPRNetAddr(aAddr, &prAddr);
    1305             : 
    1306           0 :   RefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prAddr);
    1307           0 :   return NS_AsyncCopy(aStream, os, mSts, NS_ASYNCCOPY_VIA_READSEGMENTS,
    1308           0 :                       UDP_PACKET_CHUNK_SIZE);
    1309             : }
    1310             : 
    1311             : nsresult
    1312           0 : nsUDPSocket::SetSocketOption(const PRSocketOptionData& aOpt)
    1313             : {
    1314           0 :   bool onSTSThread = false;
    1315           0 :   mSts->IsOnCurrentThread(&onSTSThread);
    1316             : 
    1317           0 :   if (!onSTSThread) {
    1318             :     // Dispatch to STS thread and re-enter this method there
    1319           0 :     nsCOMPtr<nsIRunnable> runnable = new SetSocketOptionRunnable(this, aOpt);
    1320           0 :     nsresult rv = mSts->Dispatch(runnable, NS_DISPATCH_NORMAL);
    1321           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1322           0 :       return rv;
    1323             :     }
    1324           0 :     return NS_OK;
    1325             :   }
    1326             : 
    1327           0 :   if (NS_WARN_IF(!mFD)) {
    1328           0 :     return NS_ERROR_NOT_INITIALIZED;
    1329             :   }
    1330             : 
    1331           0 :   if (PR_SetSocketOption(mFD, &aOpt) != PR_SUCCESS) {
    1332           0 :     UDPSOCKET_LOG(("nsUDPSocket::SetSocketOption [this=%p] failed for type %d, "
    1333             :       "error %d\n", this, aOpt.option, PR_GetError()));
    1334           0 :     return NS_ERROR_FAILURE;
    1335             :   }
    1336             : 
    1337           0 :   return NS_OK;
    1338             : }
    1339             : 
    1340             : NS_IMETHODIMP
    1341           0 : nsUDPSocket::JoinMulticast(const nsACString& aAddr, const nsACString& aIface)
    1342             : {
    1343           0 :   if (NS_WARN_IF(aAddr.IsEmpty())) {
    1344           0 :     return NS_ERROR_INVALID_ARG;
    1345             :   }
    1346           0 :   if (NS_WARN_IF(!mFD)) {
    1347           0 :     return NS_ERROR_NOT_INITIALIZED;
    1348             :   }
    1349             : 
    1350             :   PRNetAddr prAddr;
    1351           0 :   if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
    1352           0 :     return NS_ERROR_FAILURE;
    1353             :   }
    1354             : 
    1355             :   PRNetAddr prIface;
    1356           0 :   if (aIface.IsEmpty()) {
    1357           0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
    1358             :   } else {
    1359           0 :     if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
    1360           0 :       return NS_ERROR_FAILURE;
    1361             :     }
    1362             :   }
    1363             : 
    1364           0 :   return JoinMulticastInternal(prAddr, prIface);
    1365             : }
    1366             : 
    1367             : NS_IMETHODIMP
    1368           0 : nsUDPSocket::JoinMulticastAddr(const NetAddr aAddr, const NetAddr* aIface)
    1369             : {
    1370           0 :   if (NS_WARN_IF(!mFD)) {
    1371           0 :     return NS_ERROR_NOT_INITIALIZED;
    1372             :   }
    1373             : 
    1374             :   PRNetAddr prAddr;
    1375           0 :   NetAddrToPRNetAddr(&aAddr, &prAddr);
    1376             : 
    1377             :   PRNetAddr prIface;
    1378           0 :   if (!aIface) {
    1379           0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
    1380             :   } else {
    1381           0 :     NetAddrToPRNetAddr(aIface, &prIface);
    1382             :   }
    1383             : 
    1384           0 :   return JoinMulticastInternal(prAddr, prIface);
    1385             : }
    1386             : 
    1387             : nsresult
    1388           0 : nsUDPSocket::JoinMulticastInternal(const PRNetAddr& aAddr,
    1389             :                                    const PRNetAddr& aIface)
    1390             : {
    1391             :   PRSocketOptionData opt;
    1392             : 
    1393           0 :   opt.option = PR_SockOpt_AddMember;
    1394           0 :   opt.value.add_member.mcaddr = aAddr;
    1395           0 :   opt.value.add_member.ifaddr = aIface;
    1396             : 
    1397           0 :   nsresult rv = SetSocketOption(opt);
    1398           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1399           0 :     return NS_ERROR_FAILURE;
    1400             :   }
    1401             : 
    1402           0 :   return NS_OK;
    1403             : }
    1404             : 
    1405             : NS_IMETHODIMP
    1406           0 : nsUDPSocket::LeaveMulticast(const nsACString& aAddr, const nsACString& aIface)
    1407             : {
    1408           0 :   if (NS_WARN_IF(aAddr.IsEmpty())) {
    1409           0 :     return NS_ERROR_INVALID_ARG;
    1410             :   }
    1411           0 :   if (NS_WARN_IF(!mFD)) {
    1412           0 :     return NS_ERROR_NOT_INITIALIZED;
    1413             :   }
    1414             : 
    1415             :   PRNetAddr prAddr;
    1416           0 :   if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
    1417           0 :     return NS_ERROR_FAILURE;
    1418             :   }
    1419             : 
    1420             :   PRNetAddr prIface;
    1421           0 :   if (aIface.IsEmpty()) {
    1422           0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
    1423             :   } else {
    1424           0 :     if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
    1425           0 :       return NS_ERROR_FAILURE;
    1426             :     }
    1427             :   }
    1428             : 
    1429           0 :   return LeaveMulticastInternal(prAddr, prIface);
    1430             : }
    1431             : 
    1432             : NS_IMETHODIMP
    1433           0 : nsUDPSocket::LeaveMulticastAddr(const NetAddr aAddr, const NetAddr* aIface)
    1434             : {
    1435           0 :   if (NS_WARN_IF(!mFD)) {
    1436           0 :     return NS_ERROR_NOT_INITIALIZED;
    1437             :   }
    1438             : 
    1439             :   PRNetAddr prAddr;
    1440           0 :   NetAddrToPRNetAddr(&aAddr, &prAddr);
    1441             : 
    1442             :   PRNetAddr prIface;
    1443           0 :   if (!aIface) {
    1444           0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
    1445             :   } else {
    1446           0 :     NetAddrToPRNetAddr(aIface, &prIface);
    1447             :   }
    1448             : 
    1449           0 :   return LeaveMulticastInternal(prAddr, prIface);
    1450             : }
    1451             : 
    1452             : nsresult
    1453           0 : nsUDPSocket::LeaveMulticastInternal(const PRNetAddr& aAddr,
    1454             :                                     const PRNetAddr& aIface)
    1455             : {
    1456             :   PRSocketOptionData opt;
    1457             : 
    1458           0 :   opt.option = PR_SockOpt_DropMember;
    1459           0 :   opt.value.drop_member.mcaddr = aAddr;
    1460           0 :   opt.value.drop_member.ifaddr = aIface;
    1461             : 
    1462           0 :   nsresult rv = SetSocketOption(opt);
    1463           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1464           0 :     return NS_ERROR_FAILURE;
    1465             :   }
    1466             : 
    1467           0 :   return NS_OK;
    1468             : }
    1469             : 
    1470             : NS_IMETHODIMP
    1471           0 : nsUDPSocket::GetMulticastLoopback(bool* aLoopback)
    1472             : {
    1473           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1474             : }
    1475             : 
    1476             : NS_IMETHODIMP
    1477           0 : nsUDPSocket::SetMulticastLoopback(bool aLoopback)
    1478             : {
    1479           0 :   if (NS_WARN_IF(!mFD)) {
    1480           0 :     return NS_ERROR_NOT_INITIALIZED;
    1481             :   }
    1482             : 
    1483             :   PRSocketOptionData opt;
    1484             : 
    1485           0 :   opt.option = PR_SockOpt_McastLoopback;
    1486           0 :   opt.value.mcast_loopback = aLoopback;
    1487             : 
    1488           0 :   nsresult rv = SetSocketOption(opt);
    1489           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1490           0 :     return NS_ERROR_FAILURE;
    1491             :   }
    1492             : 
    1493           0 :   return NS_OK;
    1494             : }
    1495             : 
    1496             : NS_IMETHODIMP
    1497           0 : nsUDPSocket::GetRecvBufferSize(int* size)
    1498             : {
    1499             :   // Bug 1252759 - missing support for GetSocketOption
    1500           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1501             : }
    1502             : 
    1503             : NS_IMETHODIMP
    1504           0 : nsUDPSocket::SetRecvBufferSize(int size)
    1505             : {
    1506           0 :   if (NS_WARN_IF(!mFD)) {
    1507           0 :     return NS_ERROR_NOT_INITIALIZED;
    1508             :   }
    1509             : 
    1510             :   PRSocketOptionData opt;
    1511             : 
    1512           0 :   opt.option = PR_SockOpt_RecvBufferSize;
    1513           0 :   opt.value.recv_buffer_size = size;
    1514             : 
    1515           0 :   nsresult rv = SetSocketOption(opt);
    1516           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1517           0 :     return NS_ERROR_FAILURE;
    1518             :   }
    1519             : 
    1520           0 :   return NS_OK;
    1521             : }
    1522             : 
    1523             : NS_IMETHODIMP
    1524           0 : nsUDPSocket::GetSendBufferSize(int* size)
    1525             : {
    1526             :   // Bug 1252759 - missing support for GetSocketOption
    1527           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1528             : }
    1529             : 
    1530             : NS_IMETHODIMP
    1531           0 : nsUDPSocket::SetSendBufferSize(int size)
    1532             : {
    1533           0 :   if (NS_WARN_IF(!mFD)) {
    1534           0 :     return NS_ERROR_NOT_INITIALIZED;
    1535             :   }
    1536             : 
    1537             :   PRSocketOptionData opt;
    1538             : 
    1539           0 :   opt.option = PR_SockOpt_SendBufferSize;
    1540           0 :   opt.value.send_buffer_size = size;
    1541             : 
    1542           0 :   nsresult rv = SetSocketOption(opt);
    1543           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1544           0 :     return NS_ERROR_FAILURE;
    1545             :   }
    1546             : 
    1547           0 :   return NS_OK;
    1548             : }
    1549             : 
    1550             : NS_IMETHODIMP
    1551           0 : nsUDPSocket::GetMulticastInterface(nsACString& aIface)
    1552             : {
    1553           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1554             : }
    1555             : 
    1556             : NS_IMETHODIMP
    1557           0 : nsUDPSocket::GetMulticastInterfaceAddr(NetAddr* aIface)
    1558             : {
    1559           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1560             : }
    1561             : 
    1562             : NS_IMETHODIMP
    1563           0 : nsUDPSocket::SetMulticastInterface(const nsACString& aIface)
    1564             : {
    1565           0 :   if (NS_WARN_IF(!mFD)) {
    1566           0 :     return NS_ERROR_NOT_INITIALIZED;
    1567             :   }
    1568             : 
    1569             :   PRNetAddr prIface;
    1570           0 :   if (aIface.IsEmpty()) {
    1571           0 :     PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
    1572             :   } else {
    1573           0 :     if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
    1574           0 :       return NS_ERROR_FAILURE;
    1575             :     }
    1576             :   }
    1577             : 
    1578           0 :   return SetMulticastInterfaceInternal(prIface);
    1579             : }
    1580             : 
    1581             : NS_IMETHODIMP
    1582           0 : nsUDPSocket::SetMulticastInterfaceAddr(NetAddr aIface)
    1583             : {
    1584           0 :   if (NS_WARN_IF(!mFD)) {
    1585           0 :     return NS_ERROR_NOT_INITIALIZED;
    1586             :   }
    1587             : 
    1588             :   PRNetAddr prIface;
    1589           0 :   NetAddrToPRNetAddr(&aIface, &prIface);
    1590             : 
    1591           0 :   return SetMulticastInterfaceInternal(prIface);
    1592             : }
    1593             : 
    1594             : nsresult
    1595           0 : nsUDPSocket::SetMulticastInterfaceInternal(const PRNetAddr& aIface)
    1596             : {
    1597             :   PRSocketOptionData opt;
    1598             : 
    1599           0 :   opt.option = PR_SockOpt_McastInterface;
    1600           0 :   opt.value.mcast_if = aIface;
    1601             : 
    1602           0 :   nsresult rv = SetSocketOption(opt);
    1603           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1604           0 :     return NS_ERROR_FAILURE;
    1605             :   }
    1606             : 
    1607           0 :   return NS_OK;
    1608             : }
    1609             : 
    1610             : } // namespace net
    1611             : } // namespace mozilla

Generated by: LCOV version 1.13