Source code

Revision control

Other Tools

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