Coverage Report

Created: 2018-09-25 14:53

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