summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/DnsAndConnectSocket.h
blob: 8409de3d080f541b841ff68832328ff9e2623be2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/* vim:set ts=4 sw=2 sts=2 et cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef DnsAndConnectSocket_h__
#define DnsAndConnectSocket_h__

#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "nsAHttpConnection.h"
#include "nsHttpConnection.h"
#include "nsHttpTransaction.h"
#include "nsIAsyncOutputStream.h"
#include "nsICancelable.h"
#include "nsIDNSListener.h"
#include "nsIDNSRecord.h"
#include "nsIDNSService.h"
#include "nsINamed.h"
#include "nsITransport.h"
#include "nsWeakReference.h"

namespace mozilla {
namespace net {

// 8d411b53-54bc-4a99-8b78-ff125eab1564
#define NS_DNSANDCONNECTSOCKET_IID                   \
  {                                                  \
    0x8d411b53, 0x54bc, 0x4a99, {                    \
      0x8b, 0x78, 0xff, 0x12, 0x5e, 0xab, 0x15, 0x64 \
    }                                                \
  }

class PendingTransactionInfo;
class ConnectionEntry;

class DnsAndConnectSocket final : public nsIOutputStreamCallback,
                                  public nsITransportEventSink,
                                  public nsIInterfaceRequestor,
                                  public nsITimerCallback,
                                  public nsINamed,
                                  public nsSupportsWeakReference,
                                  public nsIDNSListener {
  ~DnsAndConnectSocket();

 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DNSANDCONNECTSOCKET_IID)
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIOUTPUTSTREAMCALLBACK
  NS_DECL_NSITRANSPORTEVENTSINK
  NS_DECL_NSIINTERFACEREQUESTOR
  NS_DECL_NSITIMERCALLBACK
  NS_DECL_NSINAMED
  NS_DECL_NSIDNSLISTENER

  DnsAndConnectSocket(nsHttpConnectionInfo* ci, nsAHttpTransaction* trans,
                      uint32_t caps, bool speculative, bool isFromPredictor,
                      bool urgentStart);

  [[nodiscard]] nsresult Init(ConnectionEntry* ent);
  void Abandon();
  double Duration(TimeStamp epoch);
  void CloseTransports(nsresult error);

  bool IsSpeculative() { return mSpeculative; }

  bool Allow1918() { return mAllow1918; }
  void SetAllow1918(bool val) { mAllow1918 = val; }

  bool HasConnected() { return mHasConnected; }

  void PrintDiagnostics(nsCString& log);

  // Checks whether the transaction can be dispatched using this
  // half-open's connection.  If this half-open is marked as urgent-start,
  // it only accepts urgent start transactions.  Call only before Claim().
  bool AcceptsTransaction(nsHttpTransaction* trans);
  bool Claim();
  void Unclaim();

 private:
  // This performs checks that the DnsAndConnectSocket has been properly cleand
  // up.
  void CheckIsDone();

  /**
   * State:
   *   INIT: initial state. From this state:
   *         1) change the state to RESOLVING and start the primary DNS lookup
   *            if mSkipDnsResolution is false,
   *         2) or the lookup is skip and the state changes to CONNECTING and
   *            start the backup timer.
   *         3) or changes to DONE in case of an error.
   *   RESOLVING: the primary DNS resolution is in progress. From this state
   *              we transition into CONNECTING or DONE.
   *   CONNECTING: We change to this state when the primary connection has
   *               started. At that point the backup timer is started.
   *   ONE_CONNECTED: We change into this state when one of the connections
   *                  is connected and the second is in progres.
   *   DONE
   *
   * Events:
   *   INIT_EVENT: Start the primary dns resolution (if mSkipDnsResolution is
   *               false), otherwise start the primary connection.
   *   RESOLVED_PRIMARY_EVENT: the primary DNS resolution is done. This event
   *                           may be resent due to DNS retries
   *   CONNECTED_EVENT: A connecion (primary or backup) is done
   */
  enum DnsAndSocketState {
    INIT,
    RESOLVING,
    CONNECTING,
    ONE_CONNECTED,
    DONE
  } mState = INIT;

  enum SetupEvents {
    INIT_EVENT,
    RESOLVED_PRIMARY_EVENT,
    PRIMARY_DONE_EVENT,
    BACKUP_DONE_EVENT,
    BACKUP_TIMER_FIRED_EVENT
  };

  // This structure is responsible for performing DNS lookup, creating socket
  // and connecting the socket.
  struct TransportSetup {
    enum TransportSetupState {
      INIT,
      RESOLVING,
      RESOLVED,
      RETRY_RESOLVING,
      CONNECTING,
      CONNECTING_DONE,
      DONE
    } mState;

    bool FirstResolving() {
      return mState == TransportSetup::TransportSetupState::RESOLVING;
    }
    bool ConnectingOrRetry() {
      return (mState == TransportSetup::TransportSetupState::CONNECTING) ||
             (mState == TransportSetup::TransportSetupState::RETRY_RESOLVING) ||
             (mState == TransportSetup::TransportSetupState::CONNECTING_DONE);
    }
    bool Resolved() {
      return mState == TransportSetup::TransportSetupState::RESOLVED;
    }
    bool DoneConnecting() {
      return (mState == TransportSetup::TransportSetupState::CONNECTING_DONE) ||
             (mState == TransportSetup::TransportSetupState::DONE);
    }

    nsCString mHost;
    nsCOMPtr<nsICancelable> mDNSRequest;
    nsCOMPtr<nsIDNSAddrRecord> mDNSRecord;
    nsIDNSService::DNSFlags mDnsFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
    bool mRetryWithDifferentIPFamily = false;
    bool mResetFamilyPreference = false;
    bool mSkipDnsResolution = false;

    nsCOMPtr<nsISocketTransport> mSocketTransport;
    nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
    nsCOMPtr<nsIAsyncInputStream> mStreamIn;
    TimeStamp mSynStarted;
    bool mConnectedOK = false;
    bool mIsBackup;

    bool mWaitingForConnect = false;
    void SetConnecting();
    void MaybeSetConnectingDone();

    nsresult Init(DnsAndConnectSocket* dnsAndSock);
    void CancelDnsResolution();
    void Abandon();
    void CloseAll();
    nsresult SetupConn(nsAHttpTransaction* transaction, ConnectionEntry* ent,
                       nsresult status, uint32_t cap,
                       HttpConnectionBase** connection);
    [[nodiscard]] nsresult SetupStreams(DnsAndConnectSocket* dnsAndSock);
    nsresult ResolveHost(DnsAndConnectSocket* dnsAndSock);
    bool ShouldRetryDNS();
    nsresult OnLookupComplete(DnsAndConnectSocket* dnsAndSock,
                              nsIDNSRecord* rec, nsresult status);
    nsresult CheckConnectedResult(DnsAndConnectSocket* dnsAndSock);

   protected:
    explicit TransportSetup(bool isBackup);
  };

  struct PrimaryTransportSetup final : TransportSetup {
    PrimaryTransportSetup() : TransportSetup(false) {}
  };

  struct BackupTransportSetup final : TransportSetup {
    BackupTransportSetup() : TransportSetup(true) {}
  };

  nsresult SetupConn(bool isPrimary, nsresult status);
  void SetupBackupTimer();
  void CancelBackupTimer();

  bool IsPrimary(nsITransport* trans);
  bool IsPrimary(nsIAsyncOutputStream* out);
  bool IsPrimary(nsICancelable* dnsRequest);
  bool IsBackup(nsITransport* trans);
  bool IsBackup(nsIAsyncOutputStream* out);
  bool IsBackup(nsICancelable* dnsRequest);

  // To find out whether |mTransaction| is still in the connection entry's
  // pending queue. If the transaction is found and |removeWhenFound| is
  // true, the transaction will be removed from the pending queue.
  already_AddRefed<PendingTransactionInfo> FindTransactionHelper(
      bool removeWhenFound);

  void CheckProxyConfig();
  nsresult SetupDnsFlags(ConnectionEntry* ent);
  nsresult SetupEvent(SetupEvents event);

  RefPtr<nsAHttpTransaction> mTransaction;
  bool mDispatchedMTransaction = false;

  PrimaryTransportSetup mPrimaryTransport;
  uint32_t mCaps;

  // mSpeculative is set if the socket was created from
  // SpeculativeConnect(). It is cleared when a transaction would normally
  // start a new connection from scratch but instead finds this one in
  // the half open list and claims it for its own use. (which due to
  // the vagaries of scheduling from the pending queue might not actually
  // match up - but it prevents a speculative connection from opening
  // more connections that are needed.)
  bool mSpeculative;

  // If created with a non-null urgent transaction, remember it, so we can
  // mark the connection as urgent rightaway it's created.
  bool mUrgentStart;

  // mIsFromPredictor is set if the socket originated from the network
  // Predictor. It is used to gather telemetry data on used speculative
  // connections from the predictor.
  bool mIsFromPredictor;

  bool mAllow1918 = true;

  // mHasConnected tracks whether one of the sockets has completed the
  // connection process. It may have completed unsuccessfully.
  bool mHasConnected = false;

  bool mBackupConnStatsSet = false;

  // A DnsAndConnectSocket can be made for a concrete non-null transaction,
  // but the transaction can be dispatch to another connection. In that
  // case we can free this transaction to be claimed by other
  // transactions.
  bool mFreeToUse = true;

  RefPtr<nsHttpConnectionInfo> mConnInfo;
  nsCOMPtr<nsITimer> mSynTimer;
  BackupTransportSetup mBackupTransport;

  bool mIsHttp3;

  bool mSkipDnsResolution = false;
  bool mProxyNotTransparent = false;
  bool mProxyTransparentResolvesHost = false;
};

NS_DEFINE_STATIC_IID_ACCESSOR(DnsAndConnectSocket, NS_DNSANDCONNECTSOCKET_IID)

}  // namespace net
}  // namespace mozilla

#endif  // DnsAndConnectSocket_h__