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