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
|