272 lines
9.2 KiB
C++
272 lines
9.2 KiB
C++
/* 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_INLINE_DECL_STATIC_IID(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);
|
|
// Toggles the IP family flags (RESOLVE_DISABLE_IPV6 and
|
|
// RESOLVE_DISABLE_IPV4) in mDnsFlags if retrying with a different IP family
|
|
// is enabled.
|
|
bool ToggleIpFamilyFlagsIfRetryEnabled();
|
|
|
|
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;
|
|
};
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|
|
#endif // DnsAndConnectSocket_h__
|