Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=4 sw=2 et cindent: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsSocketTransport2.h"
8
9
#include "mozilla/Attributes.h"
10
#include "mozilla/Telemetry.h"
11
#include "nsIOService.h"
12
#include "nsStreamUtils.h"
13
#include "nsNetSegmentUtils.h"
14
#include "nsNetAddr.h"
15
#include "nsTransportUtils.h"
16
#include "nsProxyInfo.h"
17
#include "nsNetCID.h"
18
#include "nsNetUtil.h"
19
#include "nsCOMPtr.h"
20
#include "plstr.h"
21
#include "prerr.h"
22
#include "IOActivityMonitor.h"
23
#include "NSSErrorsService.h"
24
#include "mozilla/dom/ToJSValue.h"
25
#include "mozilla/net/NeckoChild.h"
26
#include "nsThreadUtils.h"
27
#include "nsSocketProviderService.h"
28
#include "nsISocketProvider.h"
29
#include "nsISSLSocketControl.h"
30
#include "nsIPipe.h"
31
#include "nsIClassInfoImpl.h"
32
#include "nsURLHelper.h"
33
#include "nsIDNSService.h"
34
#include "nsIDNSRecord.h"
35
#include "nsIDNSByTypeRecord.h"
36
#include "nsICancelable.h"
37
#include "QuicSocketControl.h"
38
#include "TCPFastOpenLayer.h"
39
#include <algorithm>
40
#include "sslexp.h"
41
#include "mozilla/net/SSLTokensCache.h"
42
43
#include "nsPrintfCString.h"
44
#include "xpcpublic.h"
45
46
#if defined(FUZZING)
47
# include "FuzzyLayer.h"
48
# include "FuzzySecurityInfo.h"
49
# include "mozilla/StaticPrefs_fuzzing.h"
50
#endif
51
52
#if defined(XP_WIN)
53
# include "ShutdownLayer.h"
54
#endif
55
56
/* Following inclusions required for keepalive config not supported by NSPR. */
57
#include "private/pprio.h"
58
#if defined(XP_WIN)
59
# include <winsock2.h>
60
# include <mstcpip.h>
61
#elif defined(XP_UNIX)
62
# include <errno.h>
63
# include <netinet/tcp.h>
64
#endif
65
/* End keepalive config inclusions. */
66
67
#define SUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS 0
68
#define UNSUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS 1
69
#define SUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS 2
70
#define UNSUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS 3
71
72
//-----------------------------------------------------------------------------
73
74
static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
75
76
//-----------------------------------------------------------------------------
77
78
namespace mozilla {
79
namespace net {
80
81
class nsSocketEvent : public Runnable {
82
public:
83
nsSocketEvent(nsSocketTransport* transport, uint32_t type,
84
nsresult status = NS_OK, nsISupports* param = nullptr)
85
: Runnable("net::nsSocketEvent"),
86
mTransport(transport),
87
mType(type),
88
mStatus(status),
89
mParam(param) {}
90
91
NS_IMETHOD Run() override {
92
mTransport->OnSocketEvent(mType, mStatus, mParam);
93
return NS_OK;
94
}
95
96
private:
97
RefPtr<nsSocketTransport> mTransport;
98
99
uint32_t mType;
100
nsresult mStatus;
101
nsCOMPtr<nsISupports> mParam;
102
};
103
104
//-----------------------------------------------------------------------------
105
106
//#define TEST_CONNECT_ERRORS
107
#ifdef TEST_CONNECT_ERRORS
108
# include <stdlib.h>
109
static PRErrorCode RandomizeConnectError(PRErrorCode code) {
110
//
111
// To test out these errors, load http://www.yahoo.com/. It should load
112
// correctly despite the random occurrence of these errors.
113
//
114
int n = rand();
115
if (n > RAND_MAX / 2) {
116
struct {
117
PRErrorCode err_code;
118
const char* err_name;
119
} errors[] = {
120
//
121
// These errors should be recoverable provided there is another
122
// IP address in mDNSRecord.
123
//
124
{PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"},
125
{PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"},
126
//
127
// This error will cause this socket transport to error out;
128
// however, if the consumer is HTTP, then the HTTP transaction
129
// should be restarted when this error occurs.
130
//
131
{PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"},
132
};
133
n = n % (sizeof(errors) / sizeof(errors[0]));
134
code = errors[n].err_code;
135
SOCKET_LOG(("simulating NSPR error %d [%s]\n", code, errors[n].err_name));
136
}
137
return code;
138
}
139
#endif
140
141
//-----------------------------------------------------------------------------
142
143
nsresult ErrorAccordingToNSPR(PRErrorCode errorCode) {
144
nsresult rv = NS_ERROR_FAILURE;
145
switch (errorCode) {
146
case PR_WOULD_BLOCK_ERROR:
147
rv = NS_BASE_STREAM_WOULD_BLOCK;
148
break;
149
case PR_CONNECT_ABORTED_ERROR:
150
case PR_CONNECT_RESET_ERROR:
151
rv = NS_ERROR_NET_RESET;
152
break;
153
case PR_END_OF_FILE_ERROR: // XXX document this correlation
154
rv = NS_ERROR_NET_INTERRUPT;
155
break;
156
case PR_CONNECT_REFUSED_ERROR:
157
// We lump the following NSPR codes in with PR_CONNECT_REFUSED_ERROR. We
158
// could get better diagnostics by adding distinct XPCOM error codes for
159
// each of these, but there are a lot of places in Gecko that check
160
// specifically for NS_ERROR_CONNECTION_REFUSED, all of which would need to
161
// be checked.
162
case PR_NETWORK_UNREACHABLE_ERROR:
163
case PR_HOST_UNREACHABLE_ERROR:
164
case PR_ADDRESS_NOT_AVAILABLE_ERROR:
165
// Treat EACCES as a soft error since (at least on Linux) connect() returns
166
// EACCES when an IPv6 connection is blocked by a firewall. See bug 270784.
167
case PR_NO_ACCESS_RIGHTS_ERROR:
168
rv = NS_ERROR_CONNECTION_REFUSED;
169
break;
170
case PR_ADDRESS_NOT_SUPPORTED_ERROR:
171
rv = NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
172
break;
173
case PR_IO_TIMEOUT_ERROR:
174
case PR_CONNECT_TIMEOUT_ERROR:
175
rv = NS_ERROR_NET_TIMEOUT;
176
break;
177
case PR_OUT_OF_MEMORY_ERROR:
178
// These really indicate that the descriptor table filled up, or that the
179
// kernel ran out of network buffers - but nobody really cares which part of
180
// the system ran out of memory.
181
case PR_PROC_DESC_TABLE_FULL_ERROR:
182
case PR_SYS_DESC_TABLE_FULL_ERROR:
183
case PR_INSUFFICIENT_RESOURCES_ERROR:
184
rv = NS_ERROR_OUT_OF_MEMORY;
185
break;
186
case PR_ADDRESS_IN_USE_ERROR:
187
rv = NS_ERROR_SOCKET_ADDRESS_IN_USE;
188
break;
189
// These filename-related errors can arise when using Unix-domain sockets.
190
case PR_FILE_NOT_FOUND_ERROR:
191
rv = NS_ERROR_FILE_NOT_FOUND;
192
break;
193
case PR_IS_DIRECTORY_ERROR:
194
rv = NS_ERROR_FILE_IS_DIRECTORY;
195
break;
196
case PR_LOOP_ERROR:
197
rv = NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
198
break;
199
case PR_NAME_TOO_LONG_ERROR:
200
rv = NS_ERROR_FILE_NAME_TOO_LONG;
201
break;
202
case PR_NO_DEVICE_SPACE_ERROR:
203
rv = NS_ERROR_FILE_NO_DEVICE_SPACE;
204
break;
205
case PR_NOT_DIRECTORY_ERROR:
206
rv = NS_ERROR_FILE_NOT_DIRECTORY;
207
break;
208
case PR_READ_ONLY_FILESYSTEM_ERROR:
209
rv = NS_ERROR_FILE_READ_ONLY;
210
break;
211
case PR_BAD_ADDRESS_ERROR:
212
rv = NS_ERROR_UNKNOWN_HOST;
213
break;
214
default:
215
if (psm::IsNSSErrorCode(errorCode)) {
216
rv = psm::GetXPCOMFromNSSError(errorCode);
217
}
218
break;
219
220
// NSPR's socket code can return these, but they're not worth breaking out
221
// into their own error codes, distinct from NS_ERROR_FAILURE:
222
//
223
// PR_BAD_DESCRIPTOR_ERROR
224
// PR_INVALID_ARGUMENT_ERROR
225
// PR_NOT_SOCKET_ERROR
226
// PR_NOT_TCP_SOCKET_ERROR
227
// These would indicate a bug internal to the component.
228
//
229
// PR_PROTOCOL_NOT_SUPPORTED_ERROR
230
// This means that we can't use the given "protocol" (like
231
// IPPROTO_TCP or IPPROTO_UDP) with a socket of the given type. As
232
// above, this indicates an internal bug.
233
//
234
// PR_IS_CONNECTED_ERROR
235
// This indicates that we've applied a system call like 'bind' or
236
// 'connect' to a socket that is already connected. The socket
237
// components manage each file descriptor's state, and in some cases
238
// handle this error result internally. We shouldn't be returning
239
// this to our callers.
240
//
241
// PR_IO_ERROR
242
// This is so vague that NS_ERROR_FAILURE is just as good.
243
}
244
SOCKET_LOG(("ErrorAccordingToNSPR [in=%d out=%" PRIx32 "]\n", errorCode,
245
static_cast<uint32_t>(rv)));
246
return rv;
247
}
248
249
//-----------------------------------------------------------------------------
250
// socket input stream impl
251
//-----------------------------------------------------------------------------
252
253
nsSocketInputStream::nsSocketInputStream(nsSocketTransport* trans)
254
: mTransport(trans),
255
mReaderRefCnt(0),
256
mCondition(NS_OK),
257
mCallbackFlags(0),
258
mByteCount(0) {}
259
260
// called on the socket transport thread...
261
//
262
// condition : failure code if socket has been closed
263
//
264
void nsSocketInputStream::OnSocketReady(nsresult condition) {
265
SOCKET_LOG(("nsSocketInputStream::OnSocketReady [this=%p cond=%" PRIx32 "]\n",
266
this, static_cast<uint32_t>(condition)));
267
268
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
269
270
nsCOMPtr<nsIInputStreamCallback> callback;
271
{
272
MutexAutoLock lock(mTransport->mLock);
273
274
// update condition, but be careful not to erase an already
275
// existing error condition.
276
if (NS_SUCCEEDED(mCondition)) mCondition = condition;
277
278
// ignore event if only waiting for closure and not closed.
279
if (NS_FAILED(mCondition) || !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
280
callback = std::move(mCallback);
281
mCallbackFlags = 0;
282
}
283
}
284
285
if (callback) callback->OnInputStreamReady(this);
286
}
287
288
NS_IMPL_QUERY_INTERFACE(nsSocketInputStream, nsIInputStream,
289
nsIAsyncInputStream)
290
291
NS_IMETHODIMP_(MozExternalRefCountType)
292
nsSocketInputStream::AddRef() {
293
++mReaderRefCnt;
294
return mTransport->AddRef();
295
}
296
297
NS_IMETHODIMP_(MozExternalRefCountType)
298
nsSocketInputStream::Release() {
299
if (--mReaderRefCnt == 0) Close();
300
return mTransport->Release();
301
}
302
303
NS_IMETHODIMP
304
nsSocketInputStream::Close() { return CloseWithStatus(NS_BASE_STREAM_CLOSED); }
305
306
NS_IMETHODIMP
307
nsSocketInputStream::Available(uint64_t* avail) {
308
SOCKET_LOG(("nsSocketInputStream::Available [this=%p]\n", this));
309
310
*avail = 0;
311
312
PRFileDesc* fd;
313
{
314
MutexAutoLock lock(mTransport->mLock);
315
316
if (NS_FAILED(mCondition)) return mCondition;
317
318
fd = mTransport->GetFD_Locked();
319
if (!fd) return NS_OK;
320
}
321
322
// cannot hold lock while calling NSPR. (worried about the fact that PSM
323
// synchronously proxies notifications over to the UI thread, which could
324
// mistakenly try to re-enter this code.)
325
int32_t n = PR_Available(fd);
326
327
// PSM does not implement PR_Available() so do a best approximation of it
328
// with MSG_PEEK
329
if ((n == -1) && (PR_GetError() == PR_NOT_IMPLEMENTED_ERROR)) {
330
char c;
331
332
n = PR_Recv(fd, &c, 1, PR_MSG_PEEK, 0);
333
SOCKET_LOG(
334
("nsSocketInputStream::Available [this=%p] "
335
"using PEEK backup n=%d]\n",
336
this, n));
337
}
338
339
nsresult rv;
340
{
341
MutexAutoLock lock(mTransport->mLock);
342
343
mTransport->ReleaseFD_Locked(fd);
344
345
if (n >= 0)
346
*avail = n;
347
else {
348
PRErrorCode code = PR_GetError();
349
if (code == PR_WOULD_BLOCK_ERROR) return NS_OK;
350
mCondition = ErrorAccordingToNSPR(code);
351
}
352
rv = mCondition;
353
}
354
if (NS_FAILED(rv)) mTransport->OnInputClosed(rv);
355
return rv;
356
}
357
358
NS_IMETHODIMP
359
nsSocketInputStream::Read(char* buf, uint32_t count, uint32_t* countRead) {
360
SOCKET_LOG(("nsSocketInputStream::Read [this=%p count=%u]\n", this, count));
361
362
*countRead = 0;
363
364
PRFileDesc* fd = nullptr;
365
{
366
MutexAutoLock lock(mTransport->mLock);
367
368
if (NS_FAILED(mCondition))
369
return (mCondition == NS_BASE_STREAM_CLOSED) ? NS_OK : mCondition;
370
371
fd = mTransport->GetFD_Locked();
372
if (!fd) return NS_BASE_STREAM_WOULD_BLOCK;
373
}
374
375
SOCKET_LOG((" calling PR_Read [count=%u]\n", count));
376
377
// cannot hold lock while calling NSPR. (worried about the fact that PSM
378
// synchronously proxies notifications over to the UI thread, which could
379
// mistakenly try to re-enter this code.)
380
int32_t n = PR_Read(fd, buf, count);
381
382
SOCKET_LOG((" PR_Read returned [n=%d]\n", n));
383
384
nsresult rv = NS_OK;
385
{
386
MutexAutoLock lock(mTransport->mLock);
387
388
#ifdef ENABLE_SOCKET_TRACING
389
if (n > 0) mTransport->TraceInBuf(buf, n);
390
#endif
391
392
mTransport->ReleaseFD_Locked(fd);
393
394
if (n > 0)
395
mByteCount += (*countRead = n);
396
else if (n < 0) {
397
PRErrorCode code = PR_GetError();
398
if (code == PR_WOULD_BLOCK_ERROR) return NS_BASE_STREAM_WOULD_BLOCK;
399
mCondition = ErrorAccordingToNSPR(code);
400
}
401
rv = mCondition;
402
}
403
if (NS_FAILED(rv)) mTransport->OnInputClosed(rv);
404
405
// only send this notification if we have indeed read some data.
406
// see bug 196827 for an example of why this is important.
407
if (n > 0) mTransport->SendStatus(NS_NET_STATUS_RECEIVING_FROM);
408
return rv;
409
}
410
411
NS_IMETHODIMP
412
nsSocketInputStream::ReadSegments(nsWriteSegmentFun writer, void* closure,
413
uint32_t count, uint32_t* countRead) {
414
// socket stream is unbuffered
415
return NS_ERROR_NOT_IMPLEMENTED;
416
}
417
418
NS_IMETHODIMP
419
nsSocketInputStream::IsNonBlocking(bool* nonblocking) {
420
*nonblocking = true;
421
return NS_OK;
422
}
423
424
NS_IMETHODIMP
425
nsSocketInputStream::CloseWithStatus(nsresult reason) {
426
SOCKET_LOG(("nsSocketInputStream::CloseWithStatus [this=%p reason=%" PRIx32
427
"]\n",
428
this, static_cast<uint32_t>(reason)));
429
430
// may be called from any thread
431
432
nsresult rv;
433
{
434
MutexAutoLock lock(mTransport->mLock);
435
436
if (NS_SUCCEEDED(mCondition))
437
rv = mCondition = reason;
438
else
439
rv = NS_OK;
440
}
441
if (NS_FAILED(rv)) mTransport->OnInputClosed(rv);
442
return NS_OK;
443
}
444
445
NS_IMETHODIMP
446
nsSocketInputStream::AsyncWait(nsIInputStreamCallback* callback, uint32_t flags,
447
uint32_t amount, nsIEventTarget* target) {
448
SOCKET_LOG(("nsSocketInputStream::AsyncWait [this=%p]\n", this));
449
450
bool hasError = false;
451
{
452
MutexAutoLock lock(mTransport->mLock);
453
454
if (callback && target) {
455
//
456
// build event proxy
457
//
458
mCallback = NS_NewInputStreamReadyEvent("nsSocketInputStream::AsyncWait",
459
callback, target);
460
} else
461
mCallback = callback;
462
mCallbackFlags = flags;
463
464
hasError = NS_FAILED(mCondition);
465
} // unlock mTransport->mLock
466
467
if (hasError) {
468
// OnSocketEvent will call OnInputStreamReady with an error code after
469
// going through the event loop. We do this because most socket callers
470
// do not expect AsyncWait() to synchronously execute the OnInputStreamReady
471
// callback.
472
mTransport->PostEvent(nsSocketTransport::MSG_INPUT_PENDING);
473
} else {
474
mTransport->OnInputPending();
475
}
476
477
return NS_OK;
478
}
479
480
//-----------------------------------------------------------------------------
481
// socket output stream impl
482
//-----------------------------------------------------------------------------
483
484
nsSocketOutputStream::nsSocketOutputStream(nsSocketTransport* trans)
485
: mTransport(trans),
486
mWriterRefCnt(0),
487
mCondition(NS_OK),
488
mCallbackFlags(0),
489
mByteCount(0) {}
490
491
// called on the socket transport thread...
492
//
493
// condition : failure code if socket has been closed
494
//
495
void nsSocketOutputStream::OnSocketReady(nsresult condition) {
496
SOCKET_LOG(("nsSocketOutputStream::OnSocketReady [this=%p cond=%" PRIx32
497
"]\n",
498
this, static_cast<uint32_t>(condition)));
499
500
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
501
502
nsCOMPtr<nsIOutputStreamCallback> callback;
503
{
504
MutexAutoLock lock(mTransport->mLock);
505
506
// update condition, but be careful not to erase an already
507
// existing error condition.
508
if (NS_SUCCEEDED(mCondition)) mCondition = condition;
509
510
// ignore event if only waiting for closure and not closed.
511
if (NS_FAILED(mCondition) || !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
512
callback = std::move(mCallback);
513
mCallbackFlags = 0;
514
}
515
}
516
517
if (callback) callback->OnOutputStreamReady(this);
518
}
519
520
NS_IMPL_QUERY_INTERFACE(nsSocketOutputStream, nsIOutputStream,
521
nsIAsyncOutputStream)
522
523
NS_IMETHODIMP_(MozExternalRefCountType)
524
nsSocketOutputStream::AddRef() {
525
++mWriterRefCnt;
526
return mTransport->AddRef();
527
}
528
529
NS_IMETHODIMP_(MozExternalRefCountType)
530
nsSocketOutputStream::Release() {
531
if (--mWriterRefCnt == 0) Close();
532
return mTransport->Release();
533
}
534
535
NS_IMETHODIMP
536
nsSocketOutputStream::Close() { return CloseWithStatus(NS_BASE_STREAM_CLOSED); }
537
538
NS_IMETHODIMP
539
nsSocketOutputStream::Flush() { return NS_OK; }
540
541
NS_IMETHODIMP
542
nsSocketOutputStream::Write(const char* buf, uint32_t count,
543
uint32_t* countWritten) {
544
SOCKET_LOG(("nsSocketOutputStream::Write [this=%p count=%u]\n", this, count));
545
546
*countWritten = 0;
547
548
// A write of 0 bytes can be used to force the initial SSL handshake, so do
549
// not reject that.
550
551
PRFileDesc* fd = nullptr;
552
bool fastOpenInProgress;
553
{
554
MutexAutoLock lock(mTransport->mLock);
555
556
if (NS_FAILED(mCondition)) return mCondition;
557
558
fd = mTransport->GetFD_LockedAlsoDuringFastOpen();
559
if (!fd) return NS_BASE_STREAM_WOULD_BLOCK;
560
561
fastOpenInProgress = mTransport->FastOpenInProgress();
562
}
563
564
if (fastOpenInProgress) {
565
// If we are in the fast open phase, we should not write more data
566
// than TCPFastOpenLayer can accept. If we write more data, this data
567
// will be buffered in tls and we want to avoid that.
568
uint32_t availableSpace = TCPFastOpenGetBufferSizeLeft(fd);
569
count = (count > availableSpace) ? availableSpace : count;
570
if (!count) {
571
{
572
MutexAutoLock lock(mTransport->mLock);
573
mTransport->ReleaseFD_Locked(fd);
574
}
575
return NS_BASE_STREAM_WOULD_BLOCK;
576
}
577
}
578
579
SOCKET_LOG((" calling PR_Write [count=%u]\n", count));
580
581
// cannot hold lock while calling NSPR. (worried about the fact that PSM
582
// synchronously proxies notifications over to the UI thread, which could
583
// mistakenly try to re-enter this code.)
584
int32_t n = PR_Write(fd, buf, count);
585
586
SOCKET_LOG((" PR_Write returned [n=%d]\n", n));
587
588
nsresult rv = NS_OK;
589
{
590
MutexAutoLock lock(mTransport->mLock);
591
592
#ifdef ENABLE_SOCKET_TRACING
593
if (n > 0) mTransport->TraceOutBuf(buf, n);
594
#endif
595
596
mTransport->ReleaseFD_Locked(fd);
597
598
if (n > 0)
599
mByteCount += (*countWritten = n);
600
else if (n < 0) {
601
PRErrorCode code = PR_GetError();
602
if (code == PR_WOULD_BLOCK_ERROR) return NS_BASE_STREAM_WOULD_BLOCK;
603
mCondition = ErrorAccordingToNSPR(code);
604
}
605
rv = mCondition;
606
}
607
if (NS_FAILED(rv)) mTransport->OnOutputClosed(rv);
608
609
// only send this notification if we have indeed written some data.
610
// see bug 196827 for an example of why this is important.
611
// During a fast open we are actually not sending data, the data will be
612
// only buffered in the TCPFastOpenLayer. Therefore we will call
613
// SendStatus(NS_NET_STATUS_SENDING_TO) when we really send data (i.e. when
614
// TCPFastOpenFinish is called.
615
if ((n > 0) && !fastOpenInProgress) {
616
mTransport->SendStatus(NS_NET_STATUS_SENDING_TO);
617
}
618
619
return rv;
620
}
621
622
NS_IMETHODIMP
623
nsSocketOutputStream::WriteSegments(nsReadSegmentFun reader, void* closure,
624
uint32_t count, uint32_t* countRead) {
625
// socket stream is unbuffered
626
return NS_ERROR_NOT_IMPLEMENTED;
627
}
628
629
nsresult nsSocketOutputStream::WriteFromSegments(
630
nsIInputStream* input, void* closure, const char* fromSegment,
631
uint32_t offset, uint32_t count, uint32_t* countRead) {
632
nsSocketOutputStream* self = (nsSocketOutputStream*)closure;
633
return self->Write(fromSegment, count, countRead);
634
}
635
636
NS_IMETHODIMP
637
nsSocketOutputStream::WriteFrom(nsIInputStream* stream, uint32_t count,
638
uint32_t* countRead) {
639
return stream->ReadSegments(WriteFromSegments, this, count, countRead);
640
}
641
642
NS_IMETHODIMP
643
nsSocketOutputStream::IsNonBlocking(bool* nonblocking) {
644
*nonblocking = true;
645
return NS_OK;
646
}
647
648
NS_IMETHODIMP
649
nsSocketOutputStream::CloseWithStatus(nsresult reason) {
650
SOCKET_LOG(("nsSocketOutputStream::CloseWithStatus [this=%p reason=%" PRIx32
651
"]\n",
652
this, static_cast<uint32_t>(reason)));
653
654
// may be called from any thread
655
656
nsresult rv;
657
{
658
MutexAutoLock lock(mTransport->mLock);
659
660
if (NS_SUCCEEDED(mCondition))
661
rv = mCondition = reason;
662
else
663
rv = NS_OK;
664
}
665
if (NS_FAILED(rv)) mTransport->OnOutputClosed(rv);
666
return NS_OK;
667
}
668
669
NS_IMETHODIMP
670
nsSocketOutputStream::AsyncWait(nsIOutputStreamCallback* callback,
671
uint32_t flags, uint32_t amount,
672
nsIEventTarget* target) {
673
SOCKET_LOG(("nsSocketOutputStream::AsyncWait [this=%p]\n", this));
674
675
{
676
MutexAutoLock lock(mTransport->mLock);
677
678
if (callback && target) {
679
//
680
// build event proxy
681
//
682
mCallback = NS_NewOutputStreamReadyEvent(callback, target);
683
} else
684
mCallback = callback;
685
686
mCallbackFlags = flags;
687
}
688
mTransport->OnOutputPending();
689
return NS_OK;
690
}
691
692
//-----------------------------------------------------------------------------
693
// socket transport impl
694
//-----------------------------------------------------------------------------
695
696
nsSocketTransport::nsSocketTransport()
697
: mPort(0),
698
mProxyPort(0),
699
mOriginPort(0),
700
mProxyTransparent(false),
701
mProxyTransparentResolvesHost(false),
702
mHttpsProxy(false),
703
mConnectionFlags(0),
704
mResetFamilyPreference(false),
705
mTlsFlags(0),
706
mReuseAddrPort(false),
707
mState(STATE_CLOSED),
708
mAttached(false),
709
mInputClosed(true),
710
mOutputClosed(true),
711
mResolving(false),
712
mDNSLookupStatus(NS_OK),
713
mDNSARequestFinished(0),
714
mEsniQueried(false),
715
mEsniUsed(false),
716
mResolvedByTRR(false),
717
mNetAddrIsSet(false),
718
mSelfAddrIsSet(false),
719
mLock("nsSocketTransport.mLock"),
720
mFD(this),
721
mFDref(0),
722
mFDconnected(false),
723
mFDFastOpenInProgress(false),
724
mSocketTransportService(gSocketTransportService),
725
mInput(this),
726
mOutput(this),
727
mLingerPolarity(false),
728
mLingerTimeout(0),
729
mQoSBits(0x00),
730
mKeepaliveEnabled(false),
731
mKeepaliveIdleTimeS(-1),
732
mKeepaliveRetryIntervalS(-1),
733
mKeepaliveProbeCount(-1),
734
mFastOpenCallback(nullptr),
735
mFastOpenLayerHasBufferedData(false),
736
mFastOpenStatus(TFO_NOT_SET),
737
mFirstRetryError(NS_OK),
738
mDoNotRetryToConnect(false),
739
mSSLCallbackSet(false),
740
mUsingQuic(false) {
741
this->mNetAddr.raw.family = 0;
742
this->mNetAddr.inet = {};
743
this->mSelfAddr.raw.family = 0;
744
this->mSelfAddr.inet = {};
745
SOCKET_LOG(("creating nsSocketTransport @%p\n", this));
746
747
mTimeouts[TIMEOUT_CONNECT] = UINT16_MAX; // no timeout
748
mTimeouts[TIMEOUT_READ_WRITE] = UINT16_MAX; // no timeout
749
}
750
751
nsSocketTransport::~nsSocketTransport() {
752
SOCKET_LOG(("destroying nsSocketTransport @%p\n", this));
753
}
754
755
nsresult nsSocketTransport::Init(const nsTArray<nsCString>& types,
756
const nsACString& host, uint16_t port,
757
const nsACString& hostRoute,
758
uint16_t portRoute,
759
nsIProxyInfo* givenProxyInfo) {
760
nsCOMPtr<nsProxyInfo> proxyInfo;
761
if (givenProxyInfo) {
762
proxyInfo = do_QueryInterface(givenProxyInfo);
763
NS_ENSURE_ARG(proxyInfo);
764
}
765
766
// init socket type info
767
768
mOriginHost = host;
769
mOriginPort = port;
770
if (!hostRoute.IsEmpty()) {
771
mHost = hostRoute;
772
mPort = portRoute;
773
} else {
774
mHost = host;
775
mPort = port;
776
}
777
778
// A subtle check we don't enter this method more than once for the socket
779
// transport lifetime. Disable on TSan builds to prevent race checking, we
780
// don't want an atomic here for perf reasons!
781
#ifndef MOZ_TSAN
782
MOZ_ASSERT(!mPortRemappingApplied);
783
#endif // !MOZ_TSAN
784
785
if (proxyInfo) {
786
mHttpsProxy = proxyInfo->IsHTTPS();
787
}
788
789
const char* proxyType = nullptr;
790
mProxyInfo = proxyInfo;
791
if (proxyInfo) {
792
mProxyPort = proxyInfo->Port();
793
mProxyHost = proxyInfo->Host();
794
// grab proxy type (looking for "socks" for example)
795
proxyType = proxyInfo->Type();
796
if (proxyType && (proxyInfo->IsHTTP() || proxyInfo->IsHTTPS() ||
797
proxyInfo->IsDirect() || !strcmp(proxyType, "unknown"))) {
798
proxyType = nullptr;
799
}
800
}
801
802
SOCKET_LOG1(
803
("nsSocketTransport::Init [this=%p host=%s:%hu origin=%s:%d "
804
"proxy=%s:%hu]\n",
805
this, mHost.get(), mPort, mOriginHost.get(), mOriginPort,
806
mProxyHost.get(), mProxyPort));
807
808
// include proxy type as a socket type if proxy type is not "http"
809
uint32_t typeCount = types.Length() + (proxyType != nullptr);
810
if (!typeCount) return NS_OK;
811
812
// if we have socket types, then the socket provider service had
813
// better exist!
814
nsresult rv;
815
nsCOMPtr<nsISocketProviderService> spserv =
816
nsSocketProviderService::GetOrCreate();
817
818
if (!mTypes.SetCapacity(typeCount, fallible)) {
819
return NS_ERROR_OUT_OF_MEMORY;
820
}
821
822
// now verify that each socket type has a registered socket provider.
823
for (uint32_t i = 0, type = 0; i < typeCount; ++i) {
824
// store socket types
825
if (i == 0 && proxyType)
826
mTypes.AppendElement(proxyType);
827
else
828
mTypes.AppendElement(types[type++]);
829
830
// quic does not have a socketProvider.
831
if (!mTypes[i].EqualsLiteral("quic")) {
832
nsCOMPtr<nsISocketProvider> provider;
833
rv = spserv->GetSocketProvider(mTypes[i].get(), getter_AddRefs(provider));
834
if (NS_FAILED(rv)) {
835
NS_WARNING("no registered socket provider");
836
return rv;
837
}
838
}
839
840
// note if socket type corresponds to a transparent proxy
841
// XXX don't hardcode SOCKS here (use proxy info's flags instead).
842
if (mTypes[i].EqualsLiteral("socks") || mTypes[i].EqualsLiteral("socks4")) {
843
mProxyTransparent = true;
844
845
if (proxyInfo->Flags() & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST) {
846
// we want the SOCKS layer to send the hostname
847
// and port to the proxy and let it do the DNS.
848
mProxyTransparentResolvesHost = true;
849
}
850
}
851
}
852
853
return NS_OK;
854
}
855
856
#if defined(XP_UNIX)
857
nsresult nsSocketTransport::InitWithFilename(const char* filename) {
858
return InitWithName(filename, strlen(filename));
859
}
860
861
nsresult nsSocketTransport::InitWithName(const char* name, size_t length) {
862
if (length > sizeof(mNetAddr.local.path) - 1) {
863
return NS_ERROR_FILE_NAME_TOO_LONG;
864
}
865
866
if (!name[0] && length > 1) {
867
// name is abstract address name that is supported on Linux only
868
# if defined(XP_LINUX)
869
mHost.Assign(name + 1, length - 1);
870
# else
871
return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
872
# endif
873
} else {
874
// The name isn't abstract socket address. So this is Unix domain
875
// socket that has file path.
876
mHost.Assign(name, length);
877
}
878
mPort = 0;
879
880
mNetAddr.local.family = AF_LOCAL;
881
memcpy(mNetAddr.local.path, name, length);
882
mNetAddr.local.path[length] = '\0';
883
mNetAddrIsSet = true;
884
885
return NS_OK;
886
}
887
#endif
888
889
nsresult nsSocketTransport::InitWithConnectedSocket(PRFileDesc* fd,
890
const NetAddr* addr) {
891
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
892
NS_ASSERTION(!mFD.IsInitialized(), "already initialized");
893
894
char buf[kNetAddrMaxCStrBufSize];
895
NetAddrToString(addr, buf, sizeof(buf));
896
mHost.Assign(buf);
897
898
uint16_t port;
899
if (addr->raw.family == AF_INET)
900
port = addr->inet.port;
901
else if (addr->raw.family == AF_INET6)
902
port = addr->inet6.port;
903
else
904
port = 0;
905
mPort = ntohs(port);
906
907
memcpy(&mNetAddr, addr, sizeof(NetAddr));
908
909
mPollFlags = (PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT);
910
mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
911
mState = STATE_TRANSFERRING;
912
SetSocketName(fd);
913
mNetAddrIsSet = true;
914
915
{
916
MutexAutoLock lock(mLock);
917
918
mFD = fd;
919
mFDref = 1;
920
mFDconnected = true;
921
}
922
923
// make sure new socket is non-blocking
924
PRSocketOptionData opt;
925
opt.option = PR_SockOpt_Nonblocking;
926
opt.value.non_blocking = true;
927
PR_SetSocketOption(fd, &opt);
928
929
SOCKET_LOG(
930
("nsSocketTransport::InitWithConnectedSocket [this=%p addr=%s:%hu]\n",
931
this, mHost.get(), mPort));
932
933
// jump to InitiateSocket to get ourselves attached to the STS poll list.
934
return PostEvent(MSG_RETRY_INIT_SOCKET);
935
}
936
937
nsresult nsSocketTransport::InitWithConnectedSocket(PRFileDesc* aFD,
938
const NetAddr* aAddr,
939
nsISupports* aSecInfo) {
940
mSecInfo = aSecInfo;
941
return InitWithConnectedSocket(aFD, aAddr);
942
}
943
944
nsresult nsSocketTransport::PostEvent(uint32_t type, nsresult status,
945
nsISupports* param) {
946
SOCKET_LOG(("nsSocketTransport::PostEvent [this=%p type=%u status=%" PRIx32
947
" param=%p]\n",
948
this, type, static_cast<uint32_t>(status), param));
949
950
nsCOMPtr<nsIRunnable> event = new nsSocketEvent(this, type, status, param);
951
if (!event) return NS_ERROR_OUT_OF_MEMORY;
952
953
return mSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
954
}
955
956
void nsSocketTransport::SendStatus(nsresult status) {
957
SOCKET_LOG1(("nsSocketTransport::SendStatus [this=%p status=%" PRIx32 "]\n",
958
this, static_cast<uint32_t>(status)));
959
960
nsCOMPtr<nsITransportEventSink> sink;
961
uint64_t progress;
962
{
963
MutexAutoLock lock(mLock);
964
sink = mEventSink;
965
switch (status) {
966
case NS_NET_STATUS_SENDING_TO:
967
progress = mOutput.ByteCount();
968
// If Fast Open is used, we buffer some data in TCPFastOpenLayer,
969
// This data can be only tls data or application data as well.
970
// socketTransport should send status only if it really has sent
971
// application data. socketTransport cannot query transaction for
972
// that info but it can know if transaction has send data if
973
// mOutput.ByteCount() is > 0.
974
if (progress == 0) {
975
return;
976
}
977
break;
978
case NS_NET_STATUS_RECEIVING_FROM:
979
progress = mInput.ByteCount();
980
break;
981
default:
982
progress = 0;
983
break;
984
}
985
}
986
if (sink) {
987
sink->OnTransportStatus(this, status, progress, -1);
988
}
989
}
990
991
nsresult nsSocketTransport::ResolveHost() {
992
SOCKET_LOG((
993
"nsSocketTransport::ResolveHost [this=%p %s:%d%s] "
994
"mProxyTransparentResolvesHost=%d\n",
995
this, SocketHost().get(), SocketPort(),
996
mConnectionFlags & nsSocketTransport::BYPASS_CACHE ? " bypass cache" : "",
997
mProxyTransparentResolvesHost));
998
999
nsresult rv;
1000
1001
if (!mProxyHost.IsEmpty()) {
1002
if (!mProxyTransparent || mProxyTransparentResolvesHost) {
1003
#if defined(XP_UNIX)
1004
MOZ_ASSERT(!mNetAddrIsSet || mNetAddr.raw.family != AF_LOCAL,
1005
"Unix domain sockets can't be used with proxies");
1006
#endif
1007
// When not resolving mHost locally, we still want to ensure that
1008
// it only contains valid characters. See bug 304904 for details.
1009
// Sometimes the end host is not yet known and mHost is *
1010
if (!net_IsValidHostName(mHost) && !mHost.EqualsLiteral("*")) {
1011
SOCKET_LOG((" invalid hostname %s\n", mHost.get()));
1012
return NS_ERROR_UNKNOWN_HOST;
1013
}
1014
}
1015
if (mProxyTransparentResolvesHost) {
1016
// Name resolution is done on the server side. Just pretend
1017
// client resolution is complete, this will get picked up later.
1018
// since we don't need to do DNS now, we bypass the resolving
1019
// step by initializing mNetAddr to an empty address, but we
1020
// must keep the port. The SOCKS IO layer will use the hostname
1021
// we send it when it's created, rather than the empty address
1022
// we send with the connect call.
1023
mState = STATE_RESOLVING;
1024
mNetAddr.raw.family = AF_INET;
1025
mNetAddr.inet.port = htons(SocketPort());
1026
mNetAddr.inet.ip = htonl(INADDR_ANY);
1027
return PostEvent(MSG_DNS_LOOKUP_COMPLETE, NS_OK, nullptr);
1028
}
1029
}
1030
1031
nsCOMPtr<nsIDNSService> dns = do_GetService(kDNSServiceCID, &rv);
1032
if (NS_FAILED(rv)) return rv;
1033
1034
mResolving = true;
1035
1036
uint32_t dnsFlags = 0;
1037
if (mConnectionFlags & nsSocketTransport::BYPASS_CACHE)
1038
dnsFlags = nsIDNSService::RESOLVE_BYPASS_CACHE;
1039
if (mConnectionFlags & nsSocketTransport::REFRESH_CACHE)
1040
dnsFlags = nsIDNSService::RESOLVE_REFRESH_CACHE;
1041
if (mConnectionFlags & nsSocketTransport::DISABLE_IPV6)
1042
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
1043
if (mConnectionFlags & nsSocketTransport::DISABLE_IPV4)
1044
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
1045
if (mConnectionFlags & nsSocketTransport::DISABLE_TRR)
1046
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_TRR;
1047
1048
dnsFlags |= nsIDNSService::GetFlagsFromTRRMode(
1049
nsISocketTransport::GetTRRModeFromFlags(mConnectionFlags));
1050
1051
NS_ASSERTION(!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV6) ||
1052
!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV4),
1053
"Setting both RESOLVE_DISABLE_IPV6 and RESOLVE_DISABLE_IPV4");
1054
1055
SendStatus(NS_NET_STATUS_RESOLVING_HOST);
1056
1057
if (!SocketHost().Equals(mOriginHost)) {
1058
SOCKET_LOG(("nsSocketTransport %p origin %s doing dns for %s\n", this,
1059
mOriginHost.get(), SocketHost().get()));
1060
}
1061
rv = dns->AsyncResolveNative(SocketHost(), dnsFlags, this,
1062
mSocketTransportService, mOriginAttributes,
1063
getter_AddRefs(mDNSRequest));
1064
mEsniQueried = false;
1065
if (mSocketTransportService->IsEsniEnabled() && NS_SUCCEEDED(rv) &&
1066
!(mConnectionFlags & (DONT_TRY_ESNI | BE_CONSERVATIVE))) {
1067
bool isSSL = false;
1068
for (unsigned int i = 0; i < mTypes.Length(); ++i) {
1069
if (mTypes[i].EqualsLiteral("ssl")) {
1070
isSSL = true;
1071
break;
1072
}
1073
}
1074
if (isSSL) {
1075
SOCKET_LOG((" look for esni txt record"));
1076
nsAutoCString esniHost;
1077
esniHost.Append("_esni.");
1078
// This might end up being the SocketHost
1080
esniHost.Append(SocketHost());
1081
rv = dns->AsyncResolveByTypeNative(
1082
esniHost, nsIDNSService::RESOLVE_TYPE_TXT, dnsFlags, this,
1083
mSocketTransportService, mOriginAttributes,
1084
getter_AddRefs(mDNSTxtRequest));
1085
if (NS_FAILED(rv)) {
1086
SOCKET_LOG((" dns request by type failed."));
1087
mDNSTxtRequest = nullptr;
1088
rv = NS_OK;
1089
} else {
1090
mEsniQueried = true;
1091
}
1092
}
1093
}
1094
1095
if (NS_SUCCEEDED(rv)) {
1096
SOCKET_LOG((" advancing to STATE_RESOLVING\n"));
1097
mState = STATE_RESOLVING;
1098
}
1099
return rv;
1100
}
1101
1102
nsresult nsSocketTransport::BuildSocket(PRFileDesc*& fd, bool& proxyTransparent,
1103
bool& usingSSL) {
1104
SOCKET_LOG(("nsSocketTransport::BuildSocket [this=%p]\n", this));
1105
1106
nsresult rv = NS_OK;
1107
1108
proxyTransparent = false;
1109
usingSSL = false;
1110
1111
if (mTypes.IsEmpty()) {
1112
fd = PR_OpenTCPSocket(mNetAddr.raw.family);
1113
if (!fd) {
1114
SOCKET_LOG((" error creating TCP nspr socket [rv=%" PRIx32 "]\n",
1115
static_cast<uint32_t>(rv)));
1116
return NS_ERROR_OUT_OF_MEMORY;
1117
}
1118
return NS_OK;
1119
}
1120
1121
#if defined(XP_UNIX)
1122
MOZ_ASSERT(!mNetAddrIsSet || mNetAddr.raw.family != AF_LOCAL,
1123
"Unix domain sockets can't be used with socket types");
1124
#endif
1125
1126
fd = nullptr;
1127
1128
uint32_t controlFlags = 0;
1129
if (mProxyTransparentResolvesHost)
1130
controlFlags |= nsISocketProvider::PROXY_RESOLVES_HOST;
1131
1132
if (mConnectionFlags & nsISocketTransport::ANONYMOUS_CONNECT)
1133
controlFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
1134
1135
if (mConnectionFlags & nsISocketTransport::NO_PERMANENT_STORAGE)
1136
controlFlags |= nsISocketProvider::NO_PERMANENT_STORAGE;
1137
1138
if (mConnectionFlags & nsISocketTransport::BE_CONSERVATIVE)
1139
controlFlags |= nsISocketProvider::BE_CONSERVATIVE;
1140
1141
// by setting host to mOriginHost, instead of mHost we send the
1142
// SocketProvider (e.g. PSM) the origin hostname but can still do DNS
1143
// on an explicit alternate service host name
1144
const char* host = mOriginHost.get();
1145
int32_t port = (int32_t)mOriginPort;
1146
1147
if (mTypes[0].EqualsLiteral("quic")) {
1148
fd = PR_OpenUDPSocket(mNetAddr.raw.family);
1149
if (!fd) {
1150
SOCKET_LOG((" error creating UDP nspr socket [rv=%" PRIx32 "]\n",
1151
static_cast<uint32_t>(rv)));
1152
return NS_ERROR_OUT_OF_MEMORY;
1153
}
1154
1155
mUsingQuic = true;
1156
// Create security control and info object for quic.
1157
RefPtr<QuicSocketControl> quicCtrl = new QuicSocketControl(controlFlags);
1158
quicCtrl->SetHostName(mHttpsProxy ? mProxyHost.get() : host);
1159
quicCtrl->SetPort(mHttpsProxy ? mProxyPort : port);
1160
nsCOMPtr<nsISupports> secinfo;
1161
quicCtrl->QueryInterface(NS_GET_IID(nsISupports), (void**)(&secinfo));
1162
1163
// remember security info and give notification callbacks to PSM...
1164
nsCOMPtr<nsIInterfaceRequestor> callbacks;
1165
{
1166
MutexAutoLock lock(mLock);
1167
mSecInfo = secinfo;
1168
callbacks = mCallbacks;
1169
SOCKET_LOG(
1170
(" [secinfo=%p callbacks=%p]\n", mSecInfo.get(), mCallbacks.get()));
1171
}
1172
// don't call into PSM while holding mLock!!
1173
quicCtrl->SetNotificationCallbacks(callbacks);
1174
1175
return NS_OK;
1176
}
1177
1178
nsCOMPtr<nsISocketProviderService> spserv =
1179
nsSocketProviderService::GetOrCreate();
1180
nsCOMPtr<nsIProxyInfo> proxyInfo = mProxyInfo;
1181
1182
uint32_t i;
1183
for (i = 0; i < mTypes.Length(); ++i) {
1184
nsCOMPtr<nsISocketProvider> provider;
1185
1186
SOCKET_LOG((" pushing io layer [%u:%s]\n", i, mTypes[i].get()));
1187
1188
rv = spserv->GetSocketProvider(mTypes[i].get(), getter_AddRefs(provider));
1189
if (NS_FAILED(rv)) break;
1190
1191
nsCOMPtr<nsISupports> secinfo;
1192
if (i == 0) {
1193
// if this is the first type, we'll want the
1194
// service to allocate a new socket
1195
1196
// Most layers _ESPECIALLY_ PSM want the origin name here as they
1197
// will use it for secure checks, etc.. and any connection management
1198
// differences between the origin name and the routed name can be
1199
// taken care of via DNS. However, SOCKS is a special case as there is
1200
// no DNS. in the case of SOCKS and PSM the PSM is a separate layer
1201
// and receives the origin name.
1202
const char* socketProviderHost = host;
1203
int32_t socketProviderPort = port;
1204
if (mProxyTransparentResolvesHost &&
1205
(mTypes[0].EqualsLiteral("socks") ||
1206
mTypes[0].EqualsLiteral("socks4"))) {
1207
SOCKET_LOG(("SOCKS %d Host/Route override: %s:%d -> %s:%d\n",
1208
mHttpsProxy, socketProviderHost, socketProviderPort,
1209
mHost.get(), mPort));
1210
socketProviderHost = mHost.get();
1211
socketProviderPort = mPort;
1212
}
1213
1214
// when https proxying we want to just connect to the proxy as if
1215
// it were the end host (i.e. expect the proxy's cert)
1216
1217
rv = provider->NewSocket(
1218
mNetAddr.raw.family,
1219
mHttpsProxy ? mProxyHost.get() : socketProviderHost,
1220
mHttpsProxy ? mProxyPort : socketProviderPort, proxyInfo,
1221
mOriginAttributes, controlFlags, mTlsFlags, &fd,
1222
getter_AddRefs(secinfo));
1223
1224
if (NS_SUCCEEDED(rv) && !fd) {
1225
MOZ_ASSERT_UNREACHABLE(
1226
"NewSocket succeeded but failed to "
1227
"create a PRFileDesc");
1228
rv = NS_ERROR_UNEXPECTED;
1229
}
1230
} else {
1231
// the socket has already been allocated,
1232
// so we just want the service to add itself
1233
// to the stack (such as pushing an io layer)
1234
rv = provider->AddToSocket(mNetAddr.raw.family, host, port, proxyInfo,
1235
mOriginAttributes, controlFlags, mTlsFlags, fd,
1236
getter_AddRefs(secinfo));
1237
}
1238
1239
// controlFlags = 0; not used below this point...
1240
if (NS_FAILED(rv)) break;
1241
1242
// if the service was ssl or starttls, we want to hold onto the socket
1243
// info
1244
bool isSSL = mTypes[i].EqualsLiteral("ssl");
1245
if (isSSL || mTypes[i].EqualsLiteral("starttls")) {
1246
// remember security info and give notification callbacks to PSM...
1247
nsCOMPtr<nsIInterfaceRequestor> callbacks;
1248
{
1249
MutexAutoLock lock(mLock);
1250
mSecInfo = secinfo;
1251
callbacks = mCallbacks;
1252
SOCKET_LOG((" [secinfo=%p callbacks=%p]\n", mSecInfo.get(),
1253
mCallbacks.get()));
1254
}
1255
// don't call into PSM while holding mLock!!
1256
nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(secinfo));
1257
if (secCtrl) secCtrl->SetNotificationCallbacks(callbacks);
1258
// remember if socket type is SSL so we can ProxyStartSSL if need be.
1259
usingSSL = isSSL;
1260
} else if (mTypes[i].EqualsLiteral("socks") ||
1261
mTypes[i].EqualsLiteral("socks4")) {
1262
// since socks is transparent, any layers above
1263
// it do not have to worry about proxy stuff
1264
proxyInfo = nullptr;
1265
proxyTransparent = true;
1266
}
1267
}
1268
1269
if (NS_FAILED(rv)) {
1270
SOCKET_LOG((" error pushing io layer [%u:%s rv=%" PRIx32 "]\n", i,
1271
mTypes[i].get(), static_cast<uint32_t>(rv)));
1272
if (fd) {
1273
CloseSocket(
1274
fd, mSocketTransportService->IsTelemetryEnabledAndNotSleepPhase());
1275
}
1276
}
1277
return rv;
1278
}
1279
1280
// static
1281
SECStatus nsSocketTransport::StoreResumptionToken(
1282
PRFileDesc* fd, const PRUint8* resumptionToken, unsigned int len,
1283
void* ctx) {
1284
PRIntn val;
1285
if (SSL_OptionGet(fd, SSL_ENABLE_SESSION_TICKETS, &val) != SECSuccess ||
1286
val == 0) {
1287
return SECFailure;
1288
}
1289
1290
nsCOMPtr<nsISSLSocketControl> secCtrl =
1291
do_QueryInterface(static_cast<nsSocketTransport*>(ctx)->mSecInfo);
1292
if (!secCtrl) {
1293
return SECFailure;
1294
}
1295
nsAutoCString peerId;
1296
secCtrl->GetPeerId(peerId);
1297
1298
nsCOMPtr<nsITransportSecurityInfo> secInfo = do_QueryInterface(secCtrl);
1299
if (!secInfo) {
1300
return SECFailure;
1301
}
1302
1303
if (NS_FAILED(SSLTokensCache::Put(peerId, resumptionToken, len, secInfo))) {
1304
return SECFailure;
1305
}
1306
1307
return SECSuccess;
1308
}
1309
1310
nsresult nsSocketTransport::InitiateSocket() {
1311
SOCKET_LOG(("nsSocketTransport::InitiateSocket [this=%p]\n", this));
1312
1313
nsresult rv;
1314
bool isLocal;
1315
IsLocal(&isLocal);
1316
1317
if (gIOService->IsNetTearingDown()) {
1318
return NS_ERROR_ABORT;
1319
}
1320
if (gIOService->IsOffline()) {
1321
if (!isLocal) return NS_ERROR_OFFLINE;
1322
} else if (!isLocal) {
1323
#ifdef DEBUG
1324
// all IP networking has to be done from the parent
1325
if (NS_SUCCEEDED(mCondition) && ((mNetAddr.raw.family == AF_INET) ||
1326
(mNetAddr.raw.family == AF_INET6))) {
1327
MOZ_ASSERT(!IsNeckoChild());
1328
}
1329
#endif
1330
1331
if (NS_SUCCEEDED(mCondition) && xpc::AreNonLocalConnectionsDisabled() &&
1332
!(IsIPAddrAny(&mNetAddr) || IsIPAddrLocal(&mNetAddr) ||
1333
IsIPAddrShared(&mNetAddr))) {
1334
nsAutoCString ipaddr;
1335
RefPtr<nsNetAddr> netaddr = new nsNetAddr(&mNetAddr);
1336
netaddr->GetAddress(ipaddr);
1337
fprintf_stderr(
1338
stderr,
1339
"FATAL ERROR: Non-local network connections are disabled and a "
1340
"connection "
1341
"attempt to %s (%s) was made.\nYou should only access hostnames "
1342
"available via the test networking proxy (if running mochitests) "
1343
"or from a test-specific httpd.js server (if running xpcshell "
1344
"tests). "
1345
"Browser services should be disabled or redirected to a local "
1346
"server.\n",
1347
mHost.get(), ipaddr.get());
1348
MOZ_CRASH("Attempting to connect to non-local address!");
1349
}
1350
}
1351
1352
// Hosts/Proxy Hosts that are Local IP Literals should not be speculatively
1353
// connected - Bug 853423.
1354
if (mConnectionFlags & nsISocketTransport::DISABLE_RFC1918 &&
1355
IsIPAddrLocal(&mNetAddr)) {
1356
if (SOCKET_LOG_ENABLED()) {
1357
nsAutoCString netAddrCString;
1358
netAddrCString.SetLength(kIPv6CStrBufSize);
1359
if (!NetAddrToString(&mNetAddr, netAddrCString.BeginWriting(),
1360
kIPv6CStrBufSize))
1361
netAddrCString = NS_LITERAL_CSTRING("<IP-to-string failed>");
1362
SOCKET_LOG(
1363
("nsSocketTransport::InitiateSocket skipping "
1364
"speculative connection for host [%s:%d] proxy "
1365
"[%s:%d] with Local IP address [%s]",
1366
mHost.get(), mPort, mProxyHost.get(), mProxyPort,
1367
netAddrCString.get()));
1368
}
1369
mCondition = NS_ERROR_CONNECTION_REFUSED;
1370
OnSocketDetached(nullptr);
1371
return mCondition;
1372
}
1373
1374
//
1375
// find out if it is going to be ok to attach another socket to the STS.
1376
// if not then we have to wait for the STS to tell us that it is ok.
1377
// the notification is asynchronous, which means that when we could be
1378
// in a race to call AttachSocket once notified. for this reason, when
1379
// we get notified, we just re-enter this function. as a result, we are
1380
// sure to ask again before calling AttachSocket. in this way we deal
1381
// with the race condition. though it isn't the most elegant solution,
1382
// it is far simpler than trying to build a system that would guarantee
1383
// FIFO ordering (which wouldn't even be that valuable IMO). see bug
1384
// 194402 for more info.
1385
//
1386
if (!mSocketTransportService->CanAttachSocket()) {
1387
nsCOMPtr<nsIRunnable> event =
1388
new nsSocketEvent(this, MSG_RETRY_INIT_SOCKET);
1389
if (!event) return NS_ERROR_OUT_OF_MEMORY;
1390
return mSocketTransportService->NotifyWhenCanAttachSocket(event);
1391
}
1392
1393
//
1394
// if we already have a connected socket, then just attach and return.
1395
//
1396
if (mFD.IsInitialized()) {
1397
rv = mSocketTransportService->AttachSocket(mFD, this);
1398
if (NS_SUCCEEDED(rv)) mAttached = true;
1399
return rv;
1400
}
1401
1402
//
1403
// create new socket fd, push io layers, etc.
1404
//
1405
PRFileDesc* fd;
1406
bool proxyTransparent;
1407
bool usingSSL;
1408
1409
rv = BuildSocket(fd, proxyTransparent, usingSSL);
1410
if (NS_FAILED(rv)) {
1411
SOCKET_LOG(
1412
(" BuildSocket failed [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
1413
return rv;
1414
}
1415
1416
// create proxy via IOActivityMonitor
1417
IOActivityMonitor::MonitorSocket(fd);
1418
1419
#ifdef FUZZING
1420
if (StaticPrefs::fuzzing_necko_enabled()) {
1421
rv = AttachFuzzyIOLayer(fd);
1422
if (NS_FAILED(rv)) {
1423
SOCKET_LOG(("Failed to attach fuzzing IOLayer [rv=%" PRIx32 "].\n",
1424
static_cast<uint32_t>(rv)));
1425
return rv;
1426
}
1427
SOCKET_LOG(("Successfully attached fuzzing IOLayer.\n"));
1428
1429
if (usingSSL) {
1430
mSecInfo = static_cast<nsISupports*>(
1431
static_cast<nsISSLSocketControl*>(new FuzzySecurityInfo()));
1432
}
1433
}
1434
#endif
1435
1436
PRStatus status;
1437
1438
// Make the socket non-blocking...
1439
PRSocketOptionData opt;
1440
opt.option = PR_SockOpt_Nonblocking;
1441
opt.value.non_blocking = true;
1442
status = PR_SetSocketOption(fd, &opt);
1443
NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
1444
1445
if (!mUsingQuic) {
1446
if (mReuseAddrPort) {
1447
SOCKET_LOG((" Setting port/addr reuse socket options\n"));
1448
1449
// Set ReuseAddr for TCP sockets to enable having several
1450
// sockets bound to same local IP and port
1451
PRSocketOptionData opt_reuseaddr;
1452
opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
1453
opt_reuseaddr.value.reuse_addr = PR_TRUE;
1454
status = PR_SetSocketOption(fd, &opt_reuseaddr);
1455
if (status != PR_SUCCESS) {
1456
SOCKET_LOG((" Couldn't set reuse addr socket option: %d\n", status));
1457
}
1458
1459
// And also set ReusePort for platforms supporting this socket option
1460
PRSocketOptionData opt_reuseport;
1461
opt_reuseport.option = PR_SockOpt_Reuseport;
1462
opt_reuseport.value.reuse_port = PR_TRUE;
1463
status = PR_SetSocketOption(fd, &opt_reuseport);
1464
if (status != PR_SUCCESS &&
1465
PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
1466
SOCKET_LOG((" Couldn't set reuse port socket option: %d\n", status));
1467
}
1468
}
1469
1470
// disable the nagle algorithm - if we rely on it to coalesce writes into
1471
// full packets the final packet of a multi segment POST/PUT or pipeline
1472
// sequence is delayed a full rtt
1473
opt.option = PR_SockOpt_NoDelay;
1474
opt.value.no_delay = true;
1475
PR_SetSocketOption(fd, &opt);
1476
1477
// if the network.tcp.sendbuffer preference is set, use it to size SO_SNDBUF
1478
// The Windows default of 8KB is too small and as of vista sp1, autotuning
1479
// only applies to receive window
1480
int32_t sndBufferSize;
1481
mSocketTransportService->GetSendBufferSize(&sndBufferSize);
1482
if (sndBufferSize > 0) {
1483
opt.option = PR_SockOpt_SendBufferSize;
1484
opt.value.send_buffer_size = sndBufferSize;
1485
PR_SetSocketOption(fd, &opt);
1486
}
1487
1488
if (mQoSBits) {
1489
opt.option = PR_SockOpt_IpTypeOfService;
1490
opt.value.tos = mQoSBits;
1491
PR_SetSocketOption(fd, &opt);
1492
}
1493
1494
#if defined(XP_WIN)
1495
// The linger is turned off by default. This is not a hard close, but
1496
// closesocket should return immediately and operating system tries to send
1497
// remaining data for certain, implementation specific, amount of time.
1499
//
1500
// Turn the linger option on an set the interval to 0. This will cause hard
1501
// close of the socket.
1502
opt.option = PR_SockOpt_Linger;
1503
opt.value.linger.polarity = 1;
1504
opt.value.linger.linger = 0;
1505
PR_SetSocketOption(fd, &opt);
1506
#endif
1507
}
1508
1509
// inform socket transport about this newly created socket...
1510
rv = mSocketTransportService->AttachSocket(fd, this);
1511
if (NS_FAILED(rv)) {
1512
CloseSocket(fd,
1513
mSocketTransportService->IsTelemetryEnabledAndNotSleepPhase());
1514
return rv;
1515
}
1516
mAttached = true;
1517
1518
// assign mFD so that we can properly handle OnSocketDetached before we've
1519
// established a connection.
1520
{
1521
MutexAutoLock lock(mLock);
1522
mFD = fd;
1523
mFDref = 1;
1524
mFDconnected = false;
1525
}
1526
1527
SOCKET_LOG((" advancing to STATE_CONNECTING\n"));
1528
mState = STATE_CONNECTING;
1529
mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
1530
SendStatus(NS_NET_STATUS_CONNECTING_TO);
1531
1532
if (SOCKET_LOG_ENABLED()) {
1533
char buf[kNetAddrMaxCStrBufSize];
1534
NetAddrToString(&mNetAddr, buf, sizeof(buf));
1535
SOCKET_LOG((" trying address: %s\n", buf));
1536
}
1537
1538
//
1539
// Initiate the connect() to the host...
1540
//
1541
PRNetAddr prAddr;
1542
{
1543
if (mBindAddr) {
1544
MutexAutoLock lock(mLock);
1545
NetAddrToPRNetAddr(mBindAddr.get(), &prAddr);
1546
status = PR_Bind(fd, &prAddr);
1547
if (status != PR_SUCCESS) {
1548
return NS_ERROR_FAILURE;
1549
}
1550
mBindAddr = nullptr;
1551
}
1552
}
1553
1554
NetAddrToPRNetAddr(&mNetAddr, &prAddr);
1555
1556
#ifdef XP_WIN
1557
// Find the real tcp socket and set non-blocking once again!
1558
// Bug 1158189.
1559
PRFileDesc* bottom = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
1560
if (bottom) {
1561
PROsfd osfd = PR_FileDesc2NativeHandle(bottom);
1562
u_long nonblocking = 1;
1563
if (ioctlsocket(osfd, FIONBIO, &nonblocking) != 0) {
1564
NS_WARNING("Socket could not be set non-blocking!");
1565
return NS_ERROR_FAILURE;
1566
}
1567
}
1568
#endif
1569
1570
if (!mDNSRecordTxt.IsEmpty() && !mUsingQuic && mSecInfo) {
1571
nsCOMPtr<nsISSLSocketControl> secCtrl = do_QueryInterface(mSecInfo);
1572
if (secCtrl) {
1573
SOCKET_LOG(("nsSocketTransport::InitiateSocket set esni keys."));
1574
rv = secCtrl->SetEsniTxt(mDNSRecordTxt);
1575
if (NS_FAILED(rv)) {
1576
return rv;
1577
}
1578
mEsniUsed = true;
1579
}
1580
}
1581
1582
if (mUsingQuic) {
1583
//
1584
// we pretend that we are connected!
1585
//
1586
if (PR_Connect(fd, &prAddr, NS_SOCKET_CONNECT_TIMEOUT) == PR_SUCCESS) {
1587
OnSocketConnected();
1588
return NS_OK;
1589
}
1590
PRErrorCode code = PR_GetError();
1591
return ErrorAccordingToNSPR(code);
1592
}
1593
1594
// We use PRIntervalTime here because we need
1595
// nsIOService::LastOfflineStateChange time and
1596
// nsIOService::LastConectivityChange time to be atomic.
1597
PRIntervalTime connectStarted = 0;
1598
if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase()) {
1599
connectStarted = PR_IntervalNow();
1600
}
1601
1602
bool tfo = false;
1603
if (!mProxyTransparent && mFastOpenCallback &&
1604
mFastOpenCallback->FastOpenEnabled()) {
1605
if (NS_SUCCEEDED(AttachTCPFastOpenIOLayer(fd))) {
1606
tfo = true;
1607
SOCKET_LOG(
1608
("nsSocketTransport::InitiateSocket TCP Fast Open "
1609
"started [this=%p]\n",
1610
this));
1611
}
1612
}
1613
1614
nsCOMPtr<nsISSLSocketControl> secCtrl = do_QueryInterface(mSecInfo);
1615
if (usingSSL && secCtrl && SSLTokensCache::IsEnabled()) {
1616
PRIntn val;
1617
// If SSL_NO_CACHE option was set, we must not use the cache
1618
if (SSL_OptionGet(fd, SSL_NO_CACHE, &val) == SECSuccess && val == 0) {
1619
nsTArray<uint8_t> token;
1620
nsAutoCString peerId;
1621
secCtrl->GetPeerId(peerId);
1622
nsresult rv2 = SSLTokensCache::Get(peerId, token);
1623
if (NS_SUCCEEDED(rv2) && token.Length() != 0) {
1624
SECStatus srv =
1625
SSL_SetResumptionToken(fd, token.Elements(), token.Length());
1626
if (srv == SECFailure) {
1627
SOCKET_LOG(("Setting token failed with NSS error %d [id=%s]",
1628
PORT_GetError(), PromiseFlatCString(peerId).get()));
1629
SSLTokensCache::Remove(peerId);
1630
}
1631
}
1632
}
1633
1634
SSL_SetResumptionTokenCallback(fd, &StoreResumptionToken, this);
1635
mSSLCallbackSet = true;
1636
}
1637
1638
bool connectCalled = true; // This is only needed for telemetry.
1639
status = PR_Connect(fd, &prAddr, NS_SOCKET_CONNECT_TIMEOUT);
1640
PRErrorCode code = PR_GetError();
1641
if (status == PR_SUCCESS) {
1642
PR_SetFDInheritable(fd, false);
1643
}
1644
if ((status == PR_SUCCESS) && tfo) {
1645
{
1646
MutexAutoLock lock(mLock);
1647
mFDFastOpenInProgress = true;
1648
}
1649
SOCKET_LOG(("Using TCP Fast Open."));
1650
rv = mFastOpenCallback->StartFastOpen();
1651
if (NS_FAILED(rv)) {
1652
if (NS_SUCCEEDED(mCondition)) {
1653
mCondition = rv;
1654
}
1655
mFastOpenCallback = nullptr;
1656
MutexAutoLock lock(mLock);
1657
mFDFastOpenInProgress = false;
1658
return rv;
1659
}
1660
status = PR_FAILURE;
1661
connectCalled = false;
1662
bool fastOpenNotSupported = false;
1663
TCPFastOpenFinish(fd, code, fastOpenNotSupported, mFastOpenStatus);
1664
1665
// If we have sent data, trigger a socket status event.
1666
if (mFastOpenStatus == TFO_DATA_SENT) {
1667
SendStatus(NS_NET_STATUS_SENDING_TO);
1668
}
1669
1670
// If we have still some data buffered this data must be flush before
1671
// mOutput.OnSocketReady(NS_OK) is called in
1672
// nsSocketTransport::OnSocketReady, partially to keep socket status
1673
// event in order.
1674
mFastOpenLayerHasBufferedData = TCPFastOpenGetCurrentBufferSize(fd);
1675
1676
MOZ_ASSERT((mFastOpenStatus == TFO_NOT_TRIED) ||
1677
(mFastOpenStatus == TFO_DISABLED) ||
1678
(mFastOpenStatus == TFO_DATA_SENT) ||
1679
(mFastOpenStatus == TFO_TRIED));
1680
mFastOpenCallback->SetFastOpenStatus(mFastOpenStatus);
1681
SOCKET_LOG(
1682
("called StartFastOpen - code=%d; fastOpen is %s "
1683
"supported.\n",
1684
code, fastOpenNotSupported ? "not" : ""));
1685
SOCKET_LOG(("TFO status %d\n", mFastOpenStatus));
1686
1687
if (fastOpenNotSupported) {
1688
// When TCP_FastOpen is turned off on the local host
1689
// SendTo will return PR_NOT_TCP_SOCKET_ERROR. This is only
1690
// on Linux.
1691
// If a windows version does not support Fast Open, the return value
1692
// will be PR_NOT_IMPLEMENTED_ERROR. This is only for windows 10
1693
// versions older than version 1607, because we do not have subverion
1694
// to check, we need to call PR_SendTo to check if it is supported.
1695
mFastOpenCallback->FastOpenNotSupported();
1696
// FastOpenNotSupported will set Fast Open as not supported globally.
1697
// For this connection we will pretend that we still use fast open,
1698
// because of the fallback mechanism in case we need to restart the
1699
// attached transaction.
1700
connectCalled = true;
1701
}
1702
} else {
1703
mFastOpenCallback = nullptr;
1704
}
1705
1706
if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() &&
1707
connectStarted && connectCalled) {
1708
SendPRBlockingTelemetry(
1709
connectStarted, Telemetry::PRCONNECT_BLOCKING_TIME_NORMAL,
1710
Telemetry::PRCONNECT_BLOCKING_TIME_SHUTDOWN,
1711
Telemetry::PRCONNECT_BLOCKING_TIME_CONNECTIVITY_CHANGE,
1712
Telemetry::PRCONNECT_BLOCKING_TIME_LINK_CHANGE,
1713
Telemetry::PRCONNECT_BLOCKING_TIME_OFFLINE);
1714
}
1715
1716
if (status == PR_SUCCESS) {
1717
//
1718
// we are connected!
1719
//
1720
OnSocketConnected();
1721
} else {
1722
#if defined(TEST_CONNECT_ERRORS)
1723
code = RandomizeConnectError(code);
1724
#endif
1725
//
1726
// If the PR_Connect(...) would block, then poll for a connection.
1727
//
1728
if ((PR_WOULD_BLOCK_ERROR == code) || (PR_IN_PROGRESS_ERROR == code))
1729
mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
1730
//
1731
// If the socket is already connected, then return success...
1732
//
1733
else if (PR_IS_CONNECTED_ERROR == code) {
1734
//
1735
// we are connected!
1736
//
1737
OnSocketConnected();
1738
1739
if (mSecInfo && !mProxyHost.IsEmpty() && proxyTransparent && usingSSL) {
1740
// if the connection phase is finished, and the ssl layer has
1741
// been pushed, and we were proxying (transparently; ie. nothing
1742
// has to happen in the protocol layer above us), it's time for
1743
// the ssl to start doing it's thing.
1744
nsCOMPtr<nsISSLSocketControl> secCtrl = do_QueryInterface(mSecInfo);
1745
if (secCtrl) {
1746
SOCKET_LOG((" calling ProxyStartSSL()\n"));
1747
secCtrl->ProxyStartSSL();
1748
}
1749
// XXX what if we were forced to poll on the socket for a successful
1750
// connection... wouldn't we need to call ProxyStartSSL after a call
1751
// to PR_ConnectContinue indicates that we are connected?
1752
//
1753
// XXX this appears to be what the old socket transport did. why
1754
// isn't this broken?
1755
}
1756
}
1757
//
1758
// A SOCKS request was rejected; get the actual error code from
1759
// the OS error
1760
//
1761
else if (PR_UNKNOWN_ERROR == code && mProxyTransparent &&
1762
!mProxyHost.IsEmpty()) {
1763
code = PR_GetOSError();
1764
rv = ErrorAccordingToNSPR(code);
1765
}
1766
//
1767
// The connection was refused...
1768
//
1769
else {
1770
if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() &&