Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#ifndef nsSocketTransport2_h__
6
#define nsSocketTransport2_h__
7
8
#ifdef DEBUG_darinf
9
# define ENABLE_SOCKET_TRACING
10
#endif
11
12
#include "mozilla/Mutex.h"
13
#include "nsSocketTransportService2.h"
14
#include "nsString.h"
15
#include "nsCOMPtr.h"
16
17
#include "nsIInterfaceRequestor.h"
18
#include "nsISocketTransport.h"
19
#include "nsIAsyncInputStream.h"
20
#include "nsIAsyncOutputStream.h"
21
#include "nsIDNSListener.h"
22
#include "nsIClassInfo.h"
23
#include "TCPFastOpen.h"
24
#include "mozilla/net/DNS.h"
25
#include "nsASocketHandler.h"
26
#include "mozilla/Telemetry.h"
27
28
#include "prerror.h"
29
#include "ssl.h"
30
31
class nsICancelable;
32
class nsIDNSRecord;
33
class nsIInterfaceRequestor;
34
35
//-----------------------------------------------------------------------------
36
37
// after this short interval, we will return to PR_Poll
38
#define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
39
40
//-----------------------------------------------------------------------------
41
42
namespace mozilla {
43
namespace net {
44
45
nsresult ErrorAccordingToNSPR(PRErrorCode errorCode);
46
47
class nsSocketTransport;
48
49
class nsSocketInputStream : public nsIAsyncInputStream {
50
public:
51
NS_DECL_ISUPPORTS_INHERITED
52
NS_DECL_NSIINPUTSTREAM
53
NS_DECL_NSIASYNCINPUTSTREAM
54
55
explicit nsSocketInputStream(nsSocketTransport*);
56
virtual ~nsSocketInputStream() = default;
57
58
bool IsReferenced() { return mReaderRefCnt > 0; }
59
nsresult Condition() { return mCondition; }
60
uint64_t ByteCount() { return mByteCount; }
61
62
// called by the socket transport on the socket thread...
63
void OnSocketReady(nsresult condition);
64
65
private:
66
nsSocketTransport* mTransport;
67
ThreadSafeAutoRefCnt mReaderRefCnt;
68
69
// access to these is protected by mTransport->mLock
70
nsresult mCondition;
71
nsCOMPtr<nsIInputStreamCallback> mCallback;
72
uint32_t mCallbackFlags;
73
uint64_t mByteCount;
74
};
75
76
//-----------------------------------------------------------------------------
77
78
class nsSocketOutputStream : public nsIAsyncOutputStream {
79
public:
80
NS_DECL_ISUPPORTS_INHERITED
81
NS_DECL_NSIOUTPUTSTREAM
82
NS_DECL_NSIASYNCOUTPUTSTREAM
83
84
explicit nsSocketOutputStream(nsSocketTransport*);
85
virtual ~nsSocketOutputStream() = default;
86
87
bool IsReferenced() { return mWriterRefCnt > 0; }
88
nsresult Condition() { return mCondition; }
89
uint64_t ByteCount() { return mByteCount; }
90
91
// called by the socket transport on the socket thread...
92
void OnSocketReady(nsresult condition);
93
94
private:
95
static nsresult WriteFromSegments(nsIInputStream*, void*, const char*,
96
uint32_t offset, uint32_t count,
97
uint32_t* countRead);
98
99
nsSocketTransport* mTransport;
100
ThreadSafeAutoRefCnt mWriterRefCnt;
101
102
// access to these is protected by mTransport->mLock
103
nsresult mCondition;
104
nsCOMPtr<nsIOutputStreamCallback> mCallback;
105
uint32_t mCallbackFlags;
106
uint64_t mByteCount;
107
};
108
109
//-----------------------------------------------------------------------------
110
111
class nsSocketTransport final : public nsASocketHandler,
112
public nsISocketTransport,
113
public nsIDNSListener,
114
public nsIClassInfo,
115
public nsIInterfaceRequestor {
116
public:
117
NS_DECL_THREADSAFE_ISUPPORTS
118
NS_DECL_NSITRANSPORT
119
NS_DECL_NSISOCKETTRANSPORT
120
NS_DECL_NSIDNSLISTENER
121
NS_DECL_NSICLASSINFO
122
NS_DECL_NSIINTERFACEREQUESTOR
123
124
nsSocketTransport();
125
126
// this method instructs the socket transport to open a socket of the
127
// given type(s) to the given host or proxy.
128
nsresult Init(const nsTArray<nsCString>& socketTypes, const nsACString& host,
129
uint16_t port, const nsACString& hostRoute, uint16_t portRoute,
130
nsIProxyInfo* proxyInfo);
131
132
// this method instructs the socket transport to use an already connected
133
// socket with the given address.
134
nsresult InitWithConnectedSocket(PRFileDesc* socketFD, const NetAddr* addr);
135
136
// this method instructs the socket transport to use an already connected
137
// socket with the given address, and additionally supplies security info.
138
nsresult InitWithConnectedSocket(PRFileDesc* aSocketFD, const NetAddr* aAddr,
139
nsISupports* aSecInfo);
140
141
#ifdef XP_UNIX
142
// This method instructs the socket transport to open a socket
143
// connected to the given Unix domain address. We can only create
144
// unlayered, simple, stream sockets.
145
nsresult InitWithFilename(const char* filename);
146
147
// This method instructs the socket transport to open a socket
148
// connected to the given Unix domain address that includes abstract
149
// socket address. If using abstract socket address, first character of
150
// name parameter has to be \0.
151
// We can only create unlayered, simple, stream sockets.
152
nsresult InitWithName(const char* name, size_t len);
153
#endif
154
155
// nsASocketHandler methods:
156
void OnSocketReady(PRFileDesc*, int16_t outFlags) override;
157
void OnSocketDetached(PRFileDesc*) override;
158
void IsLocal(bool* aIsLocal) override;
159
void OnKeepaliveEnabledPrefChange(bool aEnabled) final;
160
161
// called when a socket event is handled
162
void OnSocketEvent(uint32_t type, nsresult status, nsISupports* param);
163
164
uint64_t ByteCountReceived() override { return mInput.ByteCount(); }
165
uint64_t ByteCountSent() override { return mOutput.ByteCount(); }
166
static void CloseSocket(PRFileDesc* aFd, bool aTelemetryEnabled);
167
static void SendPRBlockingTelemetry(
168
PRIntervalTime aStart, Telemetry::HistogramID aIDNormal,
169
Telemetry::HistogramID aIDShutdown,
170
Telemetry::HistogramID aIDConnectivityChange,
171
Telemetry::HistogramID aIDLinkChange, Telemetry::HistogramID aIDOffline);
172
173
protected:
174
virtual ~nsSocketTransport();
175
176
private:
177
static SECStatus StoreResumptionToken(PRFileDesc* fd,
178
const PRUint8* resumptionToken,
179
unsigned int len, void* ctx);
180
181
// event types
182
enum {
183
MSG_ENSURE_CONNECT,
184
MSG_DNS_LOOKUP_COMPLETE,
185
MSG_RETRY_INIT_SOCKET,
186
MSG_TIMEOUT_CHANGED,
187
MSG_INPUT_CLOSED,
188
MSG_INPUT_PENDING,
189
MSG_OUTPUT_CLOSED,
190
MSG_OUTPUT_PENDING
191
};
192
nsresult PostEvent(uint32_t type, nsresult status = NS_OK,
193
nsISupports* param = nullptr);
194
195
enum {
196
STATE_CLOSED,
197
STATE_IDLE,
198
STATE_RESOLVING,
199
STATE_CONNECTING,
200
STATE_TRANSFERRING
201
};
202
203
// Safer way to get and automatically release PRFileDesc objects.
204
class MOZ_STACK_CLASS PRFileDescAutoLock {
205
public:
206
explicit PRFileDescAutoLock(nsSocketTransport* aSocketTransport,
207
bool aAlsoDuringFastOpen,
208
nsresult* aConditionWhileLocked = nullptr)
209
: mSocketTransport(aSocketTransport), mFd(nullptr) {
210
MOZ_ASSERT(aSocketTransport);
211
MutexAutoLock lock(mSocketTransport->mLock);
212
if (aConditionWhileLocked) {
213
*aConditionWhileLocked = mSocketTransport->mCondition;
214
if (NS_FAILED(mSocketTransport->mCondition)) {
215
return;
216
}
217
}
218
if (!aAlsoDuringFastOpen) {
219
mFd = mSocketTransport->GetFD_Locked();
220
} else {
221
mFd = mSocketTransport->GetFD_LockedAlsoDuringFastOpen();
222
}
223
}
224
~PRFileDescAutoLock() {
225
MutexAutoLock lock(mSocketTransport->mLock);
226
if (mFd) {
227
mSocketTransport->ReleaseFD_Locked(mFd);
228
}
229
}
230
bool IsInitialized() { return mFd; }
231
operator PRFileDesc*() { return mFd; }
232
nsresult SetKeepaliveEnabled(bool aEnable);
233
nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime, int aRetryInterval,
234
int aProbeCount);
235
236
private:
237
operator PRFileDescAutoLock*() { return nullptr; }
238
239
// Weak ptr to nsSocketTransport since this is a stack class only.
240
nsSocketTransport* mSocketTransport;
241
PRFileDesc* mFd;
242
};
243
friend class PRFileDescAutoLock;
244
245
class LockedPRFileDesc {
246
public:
247
explicit LockedPRFileDesc(nsSocketTransport* aSocketTransport)
248
: mSocketTransport(aSocketTransport), mFd(nullptr) {
249
MOZ_ASSERT(aSocketTransport);
250
}
251
~LockedPRFileDesc() = default;
252
bool IsInitialized() { return mFd; }
253
LockedPRFileDesc& operator=(PRFileDesc* aFd) {
254
mSocketTransport->mLock.AssertCurrentThreadOwns();
255
mFd = aFd;
256
return *this;
257
}
258
operator PRFileDesc*() {
259
if (mSocketTransport->mAttached) {
260
mSocketTransport->mLock.AssertCurrentThreadOwns();
261
}
262
return mFd;
263
}
264
bool operator==(PRFileDesc* aFd) {
265
mSocketTransport->mLock.AssertCurrentThreadOwns();
266
return mFd == aFd;
267
}
268
269
private:
270
operator LockedPRFileDesc*() { return nullptr; }
271
// Weak ptr to nsSocketTransport since it owns this class.
272
nsSocketTransport* mSocketTransport;
273
PRFileDesc* mFd;
274
};
275
friend class LockedPRFileDesc;
276
277
//-------------------------------------------------------------------------
278
// these members are "set" at initialization time and are never modified
279
// afterwards. this allows them to be safely accessed from any thread.
280
//-------------------------------------------------------------------------
281
282
// socket type info:
283
nsTArray<nsCString> mTypes;
284
nsCString mHost;
285
nsCString mProxyHost;
286
nsCString mOriginHost;
287
uint16_t mPort;
288
nsCOMPtr<nsIProxyInfo> mProxyInfo;
289
uint16_t mProxyPort;
290
uint16_t mOriginPort;
291
bool mProxyTransparent;
292
bool mProxyTransparentResolvesHost;
293
bool mHttpsProxy;
294
uint32_t mConnectionFlags;
295
// When we fail to connect using a prefered IP family, we tell the consumer to
296
// reset the IP family preference on the connection entry.
297
bool mResetFamilyPreference;
298
uint32_t mTlsFlags;
299
bool mReuseAddrPort;
300
301
// The origin attributes are used to create sockets. The first party domain
302
// will eventually be used to isolate OCSP cache and is only non-empty when
303
// "privacy.firstparty.isolate" is enabled. Setting this is the only way to
304
// carry origin attributes down to NSPR layers which are final consumers.
305
// It must be set before the socket transport is built.
306
OriginAttributes mOriginAttributes;
307
308
uint16_t SocketPort() {
309
return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort;
310
}
311
const nsCString& SocketHost() {
312
return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost;
313
}
314
315
//-------------------------------------------------------------------------
316
// members accessible only on the socket transport thread:
317
// (the exception being initialization/shutdown time)
318
//-------------------------------------------------------------------------
319
320
// socket state vars:
321
uint32_t mState; // STATE_??? flags
322
bool mAttached;
323
bool mInputClosed;
324
bool mOutputClosed;
325
326
// this flag is used to determine if the results of a host lookup arrive
327
// recursively or not. this flag is not protected by any lock.
328
bool mResolving;
329
330
nsCOMPtr<nsICancelable> mDNSRequest;
331
nsCOMPtr<nsIDNSRecord> mDNSRecord;
332
333
nsresult mDNSLookupStatus;
334
PRIntervalTime mDNSARequestFinished;
335
nsCOMPtr<nsICancelable> mDNSTxtRequest;
336
nsCString mDNSRecordTxt;
337
bool mEsniQueried;
338
bool mEsniUsed;
339
bool mResolvedByTRR;
340
341
// mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
342
// reached STATE_TRANSFERRING. It must not change after that.
343
void SetSocketName(PRFileDesc* fd);
344
NetAddr mNetAddr;
345
NetAddr mSelfAddr; // getsockname()
346
Atomic<bool, Relaxed> mNetAddrIsSet;
347
Atomic<bool, Relaxed> mSelfAddrIsSet;
348
349
UniquePtr<NetAddr> mBindAddr;
350
351
// socket methods (these can only be called on the socket thread):
352
353
void SendStatus(nsresult status);
354
nsresult ResolveHost();
355
nsresult BuildSocket(PRFileDesc*&, bool&, bool&);
356
nsresult InitiateSocket();
357
bool RecoverFromError();
358
359
void OnMsgInputPending() {
360
if (mState == STATE_TRANSFERRING)
361
mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
362
}
363
void OnMsgOutputPending() {
364
if (mState == STATE_TRANSFERRING)
365
mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
366
}
367
void OnMsgInputClosed(nsresult reason);
368
void OnMsgOutputClosed(nsresult reason);
369
370
// called when the socket is connected
371
void OnSocketConnected();
372
373
//-------------------------------------------------------------------------
374
// socket input/output objects. these may be accessed on any thread with
375
// the exception of some specific methods (XXX).
376
377
Mutex mLock; // protects members in this section.
378
LockedPRFileDesc mFD;
379
nsrefcnt mFDref; // mFD is closed when mFDref goes to zero.
380
bool mFDconnected; // mFD is available to consumer when TRUE.
381
bool mFDFastOpenInProgress; // Fast Open is in progress, so
382
// socket available for some
383
// operations.
384
385
// A delete protector reference to gSocketTransportService held for lifetime
386
// of 'this'. Sometimes used interchangably with gSocketTransportService due
387
// to scoping.
388
RefPtr<nsSocketTransportService> mSocketTransportService;
389
390
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
391
nsCOMPtr<nsITransportEventSink> mEventSink;
392
nsCOMPtr<nsISupports> mSecInfo;
393
394
nsSocketInputStream mInput;
395
nsSocketOutputStream mOutput;
396
397
friend class nsSocketInputStream;
398
friend class nsSocketOutputStream;
399
400
// socket timeouts are not protected by any lock.
401
uint16_t mTimeouts[2];
402
403
// linger options to use when closing
404
bool mLingerPolarity;
405
int16_t mLingerTimeout;
406
407
// QoS setting for socket
408
uint8_t mQoSBits;
409
410
//
411
// mFD access methods: called with mLock held.
412
//
413
PRFileDesc* GetFD_Locked();
414
PRFileDesc* GetFD_LockedAlsoDuringFastOpen();
415
void ReleaseFD_Locked(PRFileDesc* fd);
416
bool FastOpenInProgress();
417
418
//
419
// stream state changes (called outside mLock):
420
//
421
void OnInputClosed(nsresult reason) {
422
// no need to post an event if called on the socket thread
423
if (OnSocketThread())
424
OnMsgInputClosed(reason);
425
else
426
PostEvent(MSG_INPUT_CLOSED, reason);
427
}
428
void OnInputPending() {
429
// no need to post an event if called on the socket thread
430
if (OnSocketThread())
431
OnMsgInputPending();
432
else
433
PostEvent(MSG_INPUT_PENDING);
434
}
435
void OnOutputClosed(nsresult reason) {
436
// no need to post an event if called on the socket thread
437
if (OnSocketThread())
438
OnMsgOutputClosed(reason); // XXX need to not be inside lock!
439
else
440
PostEvent(MSG_OUTPUT_CLOSED, reason);
441
}
442
void OnOutputPending() {
443
// no need to post an event if called on the socket thread
444
if (OnSocketThread())
445
OnMsgOutputPending();
446
else
447
PostEvent(MSG_OUTPUT_PENDING);
448
}
449
450
#ifdef ENABLE_SOCKET_TRACING
451
void TraceInBuf(const char* buf, int32_t n);
452
void TraceOutBuf(const char* buf, int32_t n);
453
#endif
454
455
// Reads prefs to get default keepalive config.
456
nsresult EnsureKeepaliveValsAreInitialized();
457
458
// Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
459
nsresult SetKeepaliveEnabledInternal(bool aEnable);
460
461
// True if keepalive has been enabled by the socket owner. Note: Keepalive
462
// must also be enabled globally for it to be enabled in TCP.
463
bool mKeepaliveEnabled;
464
465
// Keepalive config (support varies by platform).
466
int32_t mKeepaliveIdleTimeS;
467
int32_t mKeepaliveRetryIntervalS;
468
int32_t mKeepaliveProbeCount;
469
470
// A Fast Open callback.
471
TCPFastOpen* mFastOpenCallback;
472
bool mFastOpenLayerHasBufferedData;
473
uint8_t mFastOpenStatus;
474
nsresult mFirstRetryError;
475
476
bool mDoNotRetryToConnect;
477
478
// True if SSL_SetResumptionTokenCallback was called. We need to clear the
479
// callback when mFD is nulled out to make sure the ssl layer cannot call
480
// the callback after nsSocketTransport is destroyed.
481
bool mSSLCallbackSet;
482
483
// If the connection is used for QUIC this is set to true. That will mean
484
// that UDP will be used. QUIC do not have a SocketProvider because it is a
485
// mix of transport and application(HTTP) level protocol. nsSocketTransport
486
// will creat a UDP socket and SecInfo(QuicSocketControl). The protocol
487
// handler will be created by nsHttpconnectionMgr.
488
bool mUsingQuic;
489
490
// Whether the port remapping has already been applied. We definitely want to
491
// prevent duplicate calls in case of chaining remapping.
492
bool mPortRemappingApplied = false;
493
};
494
495
} // namespace net
496
} // namespace mozilla
497
498
#endif // !nsSocketTransport_h__