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