Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  ConnectionEstablisher.cpp

  Sprache: C
 

/* 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/. */


// HttpLog.h should generally be included first
#include "HttpLog.h"

#include "ConnectionEstablisher.h"
#include "HappyEyeballsConnectionAttempt.h"
#include "mozilla/Components.h"
#include "nsSocketTransportService2.h"
#include "nsHttpConnectionMgr.h"
#include "nsHttpHandler.h"
#include "nsIDNSRecord.h"
#include "nsHttpTransaction.h"
#include "HttpConnectionUDP.h"

// Log on level :5, instead of default :4.
#undef LOG
#define LOG(args) LOG5(args)
#undef LOG_ENABLED
#define LOG_ENABLED() LOG5_ENABLED()

namespace mozilla::net {

// -------------------- SingleDNSAddrRecord --------------------

void DnsMetadata::Fill(nsIDNSAddrRecord* aRecord) {
  if (!aRecord) {
    return;
  }
  aRecord->IsTRR(&mIsTRR);
  aRecord->ResolvedInSocketProcess(&mResolvedInSocketProcess);
  aRecord->GetTrrFetchDuration(&mTrrFetchDuration);
  aRecord->GetTrrFetchDurationNetworkOnly(&mTrrFetchDurationNetworkOnly);
  aRecord->GetEffectiveTRRMode(&mEffectiveTRRMode);
  aRecord->GetTrrSkipReason(&mTrrSkipReason);
}

class SingleDNSAddrRecord final : public nsIDNSAddrRecord {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIDNSRECORD
  NS_DECL_NSIDNSADDRRECORD

  SingleDNSAddrRecord(NetAddr aAddr, const DnsMetadata& aMetadata)
      : mAddress(aAddr),
        mIsTRR(aMetadata.mIsTRR),
        mResolvedInSocketProcess(aMetadata.mResolvedInSocketProcess),
        mTrrFetchDuration(aMetadata.mTrrFetchDuration),
        mTrrFetchDurationNetworkOnly(aMetadata.mTrrFetchDurationNetworkOnly),
        mEffectiveTRRMode(aMetadata.mEffectiveTRRMode),
        mTrrSkipReason(aMetadata.mTrrSkipReason) {
    LOG(("SingleDNSAddrRecord ctor:%p mIsTRR=%d mEffectiveTRRMode=%d", this,
         mIsTRR, static_cast<uint32_t>(mEffectiveTRRMode)));
  }

 private:
  ~SingleDNSAddrRecord() { LOG(("SingleDNSAddrRecord dtor:%p", this)); }

  nsCString mCanonicalName;
  NetAddr mAddress;

  bool mIsTRR = false;
  bool mResolvedInSocketProcess = false;
  double mTrrFetchDuration = 0.0;
  double mTrrFetchDurationNetworkOnly = 0.0;
  nsIRequest::TRRMode mEffectiveTRRMode = nsIRequest::TRR_DEFAULT_MODE;
  nsITRRSkipReason::value mTrrSkipReason = nsITRRSkipReason::TRR_UNSET;
  uint32_t mTTL = 60;
  mozilla::TimeStamp mLastUpdate = TimeStamp::Now();
  bool mDone = false;
};

NS_IMPL_ISUPPORTS(SingleDNSAddrRecord, nsIDNSRecord, nsIDNSAddrRecord)

NS_IMETHODIMP
SingleDNSAddrRecord::GetCanonicalName(nsACString& aResult) {
  aResult.Assign(mCanonicalName);
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::IsTRR(bool* aRetval) {
  *aRetval = mIsTRR;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::ResolvedInSocketProcess(bool* aRetval) {
  *aRetval = mResolvedInSocketProcess;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetTrrFetchDuration(double* aTime) {
  *aTime = mTrrFetchDuration;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetTrrFetchDurationNetworkOnly(double* aTime) {
  *aTime = mTrrFetchDurationNetworkOnly;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetScriptableNextAddr(uint16_t aPort,
                                           nsINetAddr** aResult) {
  return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetNextAddrAsString(nsACString& aResult) {
  return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
SingleDNSAddrRecord::HasMore(bool* aResult) { return NS_ERROR_NOT_IMPLEMENTED; }

NS_IMETHODIMP
SingleDNSAddrRecord::Rewind() { return NS_ERROR_NOT_IMPLEMENTED; }

NS_IMETHODIMP
SingleDNSAddrRecord::ReportUnusable(uint16_t aPort) {
  // TODO: should we block this address?
  return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetEffectiveTRRMode(nsIRequest::TRRMode* aMode) {
  *aMode = mEffectiveTRRMode;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetTrrSkipReason(nsITRRSkipReason::value* aReason) {
  *aReason = mTrrSkipReason;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetTtl(uint32_t* aTtl) {
  *aTtl = mTTL;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetLastUpdate(mozilla::TimeStamp* aLastUpdate) {
  *aLastUpdate = mLastUpdate;
  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetNextAddr(uint16_t aPort, NetAddr* aAddr) {
  if (mDone) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  *aAddr = mAddress;
  mDone = true;

  uint16_t port = htons(aPort);
  if (aAddr->raw.family == AF_INET) {
    aAddr->inet.port = port;
  } else if (aAddr->raw.family == AF_INET6) {
    aAddr->inet6.port = port;
  }

  return NS_OK;
}

NS_IMETHODIMP
SingleDNSAddrRecord::GetAddresses(nsTArray<NetAddr>& aAddressArray) {
  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
  return NS_ERROR_NOT_IMPLEMENTED;
}

// -------------------- ConnectionEstablisher --------------------

NS_IMPL_ISUPPORTS(ConnectionEstablisher, nsITransportEventSink,
                  nsIInterfaceRequestor)

ConnectionEstablisher::ConnectionEstablisher(nsHttpConnectionInfo* aConnInfo,
                                             const NetAddr& aAddr,
                                             uint32_t aCaps)
    : mConnInfo(aConnInfo), mAddr(aAddr), mCaps(aCaps) {
  LOG(("ConnectionEstablisher ctor:%p", this));
}

ConnectionEstablisher::~ConnectionEstablisher() {
  LOG(("ConnectionEstablisher dtor:%p", this));
  MaybeSetConnectingDone();

  if (!OnSocketThread() && gSocketTransportService) {
    gSocketTransportService->Dispatch(
        NS_NewRunnableFunction(
            "~ConnectionEstablisher",
            [transaction = std::move(mTransaction), handle = std::move(mHandle),
             resultConn = std::move(mResultConn),
             transportStatusCallback = std::move(mTransportStatusCallback),
             lnaCheckCallback = std::move(mLnaCheckCallback),
             callback = std::move(mCallback)]() {}),
        NS_DISPATCH_NORMAL);
  }
}

void ConnectionEstablisher::SetConnecting() {
  MOZ_ASSERT(!mWaitingForConnect);
  mWaitingForConnect = true;
  gHttpHandler->ConnMgr()->StartedConnect();
}

void ConnectionEstablisher::MaybeSetConnectingDone() {
  if (mWaitingForConnect) {
    mWaitingForConnect = false;
    gHttpHandler->ConnMgr()->RecvdConnect();
  }
}

void ConnectionEstablisher::ClearResultConnection() { mResultConn = nullptr; }

nsresult ConnectionEstablisher::ActivateConnectionWithTransaction(
    RefPtr<HttpConnectionBase> aConn,
    std::function<void(nsresult)> aOnActivated) {
  LOG(
      ("ConnectionEstablisher::ActivateConnectionWithTransaction %p conn=%p "
       "trans=%p",
       this, aConn.get(), mTransaction.get()));

  aConn->SetIsRacing(true);

  mHasConnected = true;
  mResultConn = aConn;
  mHandle = new ConnectionHandle(aConn);

  MOZ_ASSERT(mTransaction,
             "HappyEyeballsConnectionAttempt must hand us a transaction "
             "before we can activate a connection.");

  mTransaction->SetConnectedCallback(
      [self = RefPtr{this},
       onActivated = std::move(aOnActivated)](nsresult aResult) {
        NS_DispatchToCurrentThread(NS_NewRunnableFunction(
            "ConnectionEstablisher::ActivateCallback",
            [self, aResult, onActivated = std::move(onActivated)]() {
              if (NS_FAILED(aResult)) {
                self->Finish(aResult);
                return;
              }

              onActivated(NS_OK);
            }));
      });

  mTransaction->SetConnection(mHandle);
  nsresult rv = aConn->Activate(mTransaction, mCaps, 0);
  if (NS_FAILED(rv)) {
    Finish(rv);
    return rv;
  }

  return NS_OK;
}

void ConnectionEstablisher::FinishInternal(nsresult aResult) {
  LOG(("ConnectionEstablisher::FinishInternal %p result=%x", this,
       static_cast<uint32_t>(aResult)));

  if (mFinished) {
    return;
  }
  mFinished = true;

  MaybeSetConnectingDone();
  mTransportStatusCallback = nullptr;
  mLnaCheckCallback = nullptr;
  mAddrRecord = nullptr;

  if (mTransaction) {
    // Detach the connected-callback so later Close/cleanup on the
    // transaction can't call us back. Keep the ref itself: the winning
    // HandleTCPConnectionResult / HandleUDPConnectionResult still needs
    // to query establisher->Transaction() afterwards to grab the
    // handshake timings.
    mTransaction->SetConnectedCallback(nullptr);
  }

  if (mCallback) {
    auto cb = std::move(mCallback);
    mCallback = nullptr;
    // HappyEyeballsTransaction is speculative — the real transaction is
    // never driving I/O on this conn — so the H1 fallback path always
    // applies: reset the handle so the conn doesn't cling to it after
    // we're done (H2/H3 manage reuse via their sessions).
    if (mHandle && mHandle->Conn() && !mHandle->Conn()->UsingSpdy() &&
        !mHandle->Conn()->UsingHttp3()) {
      mHandle->Reset();
    }

    // Clear mHandle to break the ref cycle: the establisher holds mHandle
    // (which refs the connection), while the connection holds mCallbacks
    // (which refs the establisher).
    mHandle = nullptr;

    // For H3, check CanReuse() to guard against mHttp3Session being
    // destroyed between the async handshake callback and this point.
    // For H1/H2, skip: H1 needs the connection even if the socket is dead
    // (e.g. cert error) to propagate the proper error code; H2 sessions
    // may be incorrectly marked DontReuse by the proxy transaction's caps.
    bool connUsable =
        mResultConn && (!mResultConn->UsingHttp3() || mResultConn->CanReuse());
    if (NS_SUCCEEDED(aResult) && connUsable) {
      if (!mConnectStart.IsNull()) {
        mResultConn->SetConnectBootstrapTimings(mConnectStart, mTcpConnectEnd);
      }
      cb(std::move(mResultConn));
    } else {
      LOG(
          ("ConnectionEstablisher::FinishInternal %p conn rejected "
           "aResult=%x connUsable=%d UsingHttp3=%d",
           this, static_cast<uint32_t>(aResult), connUsable,
           mResultConn ? mResultConn->UsingHttp3() : 0));
      cb(Err(NS_FAILED(aResult) ? aResult : NS_ERROR_ABORT));
    }
  }
}

NS_IMETHODIMP
ConnectionEstablisher::GetInterface(const nsIID& iid, void** result) {
  if (mSecurityCallbacks) {
    return mSecurityCallbacks->GetInterface(iid, result);
  }
  return NS_ERROR_NO_INTERFACE;
}

NS_IMETHODIMP
ConnectionEstablisher::OnTransportStatus(nsITransport* trans, nsresult status,
                                         int64_t progress,
                                         int64_t progressMax) {
  if (status == NS_NET_STATUS_CONNECTING_TO) {
    mConnectStart = TimeStamp::Now();
  } else if (status == NS_NET_STATUS_CONNECTED_TO) {
    mConnectedOK = true;
    mTcpConnectEnd = TimeStamp::Now();
  }

  if (mTransportStatusCallback) {
    mTransportStatusCallback(trans, status, progress);
  }

  return NS_OK;
}

NS_IMPL_ISUPPORTS_INHERITED(TCPConnectionEstablisher, ConnectionEstablisher,
                            nsIOutputStreamCallback)

TCPConnectionEstablisher::TCPConnectionEstablisher(
    nsHttpConnectionInfo* aConnInfo, NetAddr aAddr, uint32_t aCaps,
    bool aSpeculative, bool aAllow1918)
    : ConnectionEstablisher(aConnInfo, aAddr, aCaps),
      mSpeculative(aSpeculative),
      mAllow1918(aAllow1918) {}

TCPConnectionEstablisher::~TCPConnectionEstablisher() {
  // mSocketTransport / mStreamOut / mStreamIn must be released on the
  // socket thread.
  if (!OnSocketThread() && gSocketTransportService) {
    gSocketTransportService->Dispatch(
        NS_NewRunnableFunction("~TCPConnectionEstablisher",
                               [socketTransport = std::move(mSocketTransport),
                                streamOut = std::move(mStreamOut),
                                streamIn = std::move(mStreamIn)]() {}),
        NS_DISPATCH_NORMAL);
  }
}

bool TCPConnectionEstablisher::Start(DoneCallback&& aCallback) {
  mCallback = std::move(aCallback);
  mAddrRecord = new SingleDNSAddrRecord(mAddr, mDnsMetadata);

  nsresult rv = CreateAndConfigureSocketTransport();
  if (NS_FAILED(rv)) {
    return false;
  }

  return true;
}

void TCPConnectionEstablisher::ResetSpeculativeFlags() {
  uint32_t flags = 0;
  if (!mSocketTransport ||
      NS_FAILED(mSocketTransport->GetConnectionFlags(&flags))) {
    return;
  }

  flags &= ~nsISocketTransport::DISABLE_RFC1918;
  flags &= ~nsISocketTransport::IS_SPECULATIVE_CONNECTION;
  mSocketTransport->SetConnectionFlags(flags);
}

void TCPConnectionEstablisher::Close(nsresult aReason) {
  LOG(("TCPConnectionEstablisher::Close %p aReason=%x", this,
       static_cast<uint32_t>(aReason)));

  mHandle = nullptr;
  if (mResultConn) {
    // Every connection touched by HE is marked non-reusable: adopted conns
    // finish serving the in-flight real txn then close; losing conns are
    // torn down immediately below.  Either way the CM must never hand a new
    // transaction to a connection that participated in an HE race.
    bool adopted = mTransaction && mTransaction->IsAdopted();
    mResultConn->DontReuse();
    if (adopted) {
      LOG(("TCPConnectionEstablisher::Close %p adopted conn %p DontReuse", this,
           mResultConn.get()));
    } else {
      LOG(("TCPConnectionEstablisher::Close closing connection %p",
           mResultConn.get()));
      // Use CloseTransaction rather than Close to properly clean up the
      // SPDY session: if we only called Close, an Http2Session in
      // mSpdySession/mTransaction would never be released and the conn
      // would stay alive indefinitely without a pending socket read to
      // trigger CloseTransaction naturally.
      mResultConn->CloseTransaction(mResultConn->Transaction(), aReason);
    }
    mResultConn = nullptr;
  }

  if (mSocketTransport) {
    mSocketTransport->SetEventSink(nullptr, nullptr);
    mSocketTransport->SetSecurityCallbacks(nullptr);
    mSocketTransport = nullptr;
  }

  // Tell output stream (and backup) to forget the half open socket.
  if (mStreamOut) {
    mStreamOut->AsyncWait(nullptr, 00, nullptr);
    mStreamOut = nullptr;
  }

  // Lose references to input stream (and backup).
  if (mStreamIn) {
    mStreamIn->AsyncWait(nullptr, 00, nullptr);
    mStreamIn = nullptr;
  }

  // Release the DNS address record to avoid leaking SingleDNSAddrRecord
  mAddrRecord = nullptr;

  mConnectedOK = false;
  Finish(aReason);
}

nsresult TCPConnectionEstablisher::CreateAndConfigureSocketTransport() {
  nsresult rv = NS_OK;
  nsTArray<nsCString> socketTypes;
  if (mConnInfo->FirstHopSSL()) {
    socketTypes.AppendElement("ssl"_ns);
  } else {
    const nsCString& defaultType = gHttpHandler->DefaultSocketType();
    if (!defaultType.IsVoid()) {
      socketTypes.AppendElement(defaultType);
    }
  }

  nsCOMPtr<nsISocketTransport> socketTransport;
  nsCOMPtr<nsISocketTransportService> sts =
      components::SocketTransport::Service();
  if (!sts) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  LOG(
      ("TCPConnectionEstablisher::CreateAndConfigureSocketTransport [this=%p "
       "info=%s] "
       "setup routed transport to origin %s:%d via %s:%d\n",
       this, mConnInfo->HashKey().get(), mConnInfo->Origin(),
       mConnInfo->OriginPort(), mConnInfo->RoutedHost(),
       mConnInfo->RoutedPort()));

  nsCOMPtr<nsIRoutedSocketTransportService> routedSTS(do_QueryInterface(sts));
  if (routedSTS) {
    rv = routedSTS->CreateRoutedTransport(
        socketTypes, mConnInfo->GetOrigin(), mConnInfo->OriginPort(),
        mConnInfo->GetRoutedHost(), mConnInfo->RoutedPort(),
        mConnInfo->ProxyInfo(), mAddrRecord, getter_AddRefs(socketTransport));
  } else {
    if (!mConnInfo->GetRoutedHost().IsEmpty()) {
      // There is a route requested, but the legacy nsISocketTransportService
      // can't handle it.
      // Origin should be reachable on origin host name, so this should
      // not be a problem - but log it.
      LOG(
          ("%p using legacy nsISocketTransportService "
           "means explicit route %s:%d will be ignored.\n",
           this, mConnInfo->RoutedHost(), mConnInfo->RoutedPort()));
    }

    rv = sts->CreateTransport(socketTypes, mConnInfo->GetOrigin(),
                              mConnInfo->OriginPort(), mConnInfo->ProxyInfo(),
                              mAddrRecord, getter_AddRefs(socketTransport));
  }

  if (NS_FAILED(rv)) {
    return rv;
  }

  uint32_t tmpFlags = 0;
  if (mCaps & NS_HTTP_REFRESH_DNS) {
    tmpFlags = nsISocketTransport::BYPASS_CACHE;
  }

  tmpFlags |= nsISocketTransport::GetFlagsFromTRRMode(
      NS_HTTP_TRR_MODE_FROM_FLAGS(mCaps));

  if (mCaps & NS_HTTP_LOAD_ANONYMOUS) {
    tmpFlags |= nsISocketTransport::ANONYMOUS_CONNECT;
  }

  // When we are making a speculative connection we do not propagate all flags
  // in mCaps, so we need to query nsHttpConnectionInfo directly as well.
  if ((mCaps & NS_HTTP_LOAD_ANONYMOUS_CONNECT_ALLOW_CLIENT_CERT) ||
      mConnInfo->GetAnonymousAllowClientCert()) {
    tmpFlags |= nsISocketTransport::ANONYMOUS_CONNECT_ALLOW_CLIENT_CERT;
  }

  if (mConnInfo->GetPrivate()) {
    tmpFlags |= nsISocketTransport::NO_PERMANENT_STORAGE;
  }

  if (mCaps & NS_HTTP_DISALLOW_ECH) {
    tmpFlags |= nsISocketTransport::DONT_TRY_ECH;
  }

  if (mCaps & NS_HTTP_IS_RETRY) {
    tmpFlags |= nsISocketTransport::IS_RETRY;
  }

  if (((mCaps & NS_HTTP_BE_CONSERVATIVE) || mConnInfo->GetBeConservative()) &&
      gHttpHandler->ConnMgr()->BeConservativeIfProxied(
          mConnInfo->ProxyInfo())) {
    LOG(("Setting Socket to BE_CONSERVATIVE"));
    tmpFlags |= nsISocketTransport::BE_CONSERVATIVE;
  }

  // IP hint addresses from HTTPS records are handled by the Happy Eyeballs
  // state machine.

  if (!mAllow1918) {
    tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
  }

  if (mSpeculative) {
    tmpFlags |= nsISocketTransport::IS_SPECULATIVE_CONNECTION;
  }

  socketTransport->SetConnectionFlags(tmpFlags);
  socketTransport->SetTlsFlags(mConnInfo->GetTlsFlags());
  socketTransport->SetOriginAttributes(mConnInfo->GetOriginAttributes());

  socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());

  rv = socketTransport->SetEventSink(this, nullptr);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = socketTransport->SetSecurityCallbacks(this);
  NS_ENSURE_SUCCESS(rv, rv);

  if (nsHttpHandler::EchConfigEnabled() &&
      !mConnInfo->GetEchConfig().IsEmpty()) {
    LOG(("Setting ECH"));
    rv = socketTransport->SetEchConfig(mConnInfo->GetEchConfig());
    NS_ENSURE_SUCCESS(rv, rv);
  }

  mSynStarted = TimeStamp::Now();

  nsCOMPtr<nsIOutputStream> sout;
  rv = socketTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 00,
                                         getter_AddRefs(sout));
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIInputStream> sin;
  rv = socketTransport->OpenInputStream(nsITransport::OPEN_UNBUFFERED, 00,
                                        getter_AddRefs(sin));
  NS_ENSURE_SUCCESS(rv, rv);

  mSocketTransport = socketTransport.forget();
  mStreamIn = do_QueryInterface(sin);
  mStreamOut = do_QueryInterface(sout);

  rv = mStreamOut->AsyncWait(this, 00, nullptr);
  if (NS_SUCCEEDED(rv)) {
    SetConnecting();
  }
  return rv;
}

void TCPConnectionEstablisher::Finish(nsresult aResult) {
  // Release TCP-specific resources first
  mStreamOut = nullptr;
  mStreamIn = nullptr;
  mSocketTransport = nullptr;

  FinishInternal(aResult);
}

NS_IMETHODIMP
TCPConnectionEstablisher::OnOutputStreamReady(nsIAsyncOutputStream* aOut) {
  MOZ_DIAGNOSTIC_ASSERT(mStreamOut == aOut, "stream mismatch");
  LOG(("TCPConnectionEstablisher::OnOutputStreamReady %p mFinished=%d", this,
       mFinished));

  if (mFinished) {
    return NS_OK;
  }

  // Early LNA check: reject the connection before TLS handshake can send SNI.
  if (mLnaCheckCallback && mSocketTransport) {
    nsresult rv = mLnaCheckCallback(mSocketTransport);
    if (NS_FAILED(rv)) {
      mSocketTransport->Close(rv);
      Finish(rv);
      return NS_OK;
    }
  }

  // Create nsHttpConnection when the output stream is ready.
  RefPtr<nsHttpConnection> conn = new nsHttpConnection();
  conn->SetTransactionCaps(mCaps);
  // TODO:
  // 1. BootstrapTimings
  // 2. SetTransactionCaps
  // 3. SetSecurityCallbacks
  // 4. RecordIPFamilyPreference

  nsresult rv = conn->Init(
      mConnInfo, gHttpHandler->ConnMgr()->mMaxRequestDelay, mSocketTransport,
      mStreamIn, mStreamOut, mConnectedOK, NS_OK, this,
      PR_MillisecondsToInterval(static_cast<uint32_t>(
          (TimeStamp::Now() - mSynStarted).ToMilliseconds())),
      mCaps & NS_HTTP_ALLOW_SPDY_WITHOUT_KEEPALIVE);

  if (NS_FAILED(rv)) {
    Finish(rv);
    return NS_OK;
  }

  // Clear TCP-specific resources before activation
  mSocketTransport = nullptr;
  mStreamOut = nullptr;
  mStreamIn = nullptr;

  rv = ActivateConnectionWithTransaction(
      conn, [self = RefPtr{this}](nsresult aResult) { self->Finish(aResult); });

  return rv;
}

// -------------------- UDPConnectionEstablisher --------------------

UDPConnectionEstablisher::UDPConnectionEstablisher(
    nsHttpConnectionInfo* aConnInfo, NetAddr aAddr, uint32_t aCaps)
    : ConnectionEstablisher(aConnInfo, aAddr, aCaps) {
  LOG(("UDPConnectionEstablisher ctor:%p", this));
}

UDPConnectionEstablisher::~UDPConnectionEstablisher() {
  LOG(("UDPConnectionEstablisher dtor:%p", this));
}

bool UDPConnectionEstablisher::Start(DoneCallback&& aCallback) {
  LOG(("UDPConnectionEstablisher::Start %p", this));
  mCallback = std::move(aCallback);
  mAddrRecord = new SingleDNSAddrRecord(mAddr, mDnsMetadata);

  nsresult rv = CreateAndConfigureUDPConn();
  if (NS_FAILED(rv)) {
    return false;
  }

  return true;
}

void UDPConnectionEstablisher::Close(nsresult aReason) {
  LOG(("UDPConnectionEstablisher::Close %p aReason=%x", this,
       static_cast<uint32_t>(aReason)));

  mHandle = nullptr;
  if (mResultConn) {
    // If the HT on this conn has been adopted, the conn is already
    // driving the real nsHttpTransaction — tearing it down here would
    // close the real txn. Just mark the conn non-reusable and let it
    // finish serving the in-flight request naturally.
    bool adopted = mTransaction && mTransaction->IsAdopted();
    if (adopted) {
      LOG(("UDPConnectionEstablisher::Close %p adopted conn %p DontReuse", this,
           mResultConn.get()));
      mResultConn->DontReuse();
    } else {
      LOG(("UDPConnectionEstablisher::Close closing connection %p",
           mResultConn.get()));
      // TODO: for some cases we might want to exclude HTTP/3.
      mResultConn->SetDontExclude();
      mResultConn->Close(aReason);
    }
    mResultConn = nullptr;
  }

  // Release the DNS address record to avoid leaking SingleDNSAddrRecord
  mAddrRecord = nullptr;

  Finish(aReason);
}

nsresult UDPConnectionEstablisher::CreateAndConfigureUDPConn() {
  LOG(
      ("UDPConnectionEstablisher::CreateAndConfigureUDPConn [this=%p "
       "info=%s]",
       this, mConnInfo->HashKey().get()));

  RefPtr<HttpConnectionUDP> connUDP = new HttpConnectionUDP();
  connUDP->SetTransactionCaps(mCaps);

  nsresult rv = connUDP->Init(mConnInfo, mAddrRecord, NS_OK, this, mCaps);
  if (NS_FAILED(rv)) {
    return rv;
  }

  SetConnecting();

  rv = ActivateConnectionWithTransaction(
      connUDP,
      [self = RefPtr{this}](nsresult aResult) { self->Finish(aResult); });

  return rv;
}

void UDPConnectionEstablisher::Finish(nsresult aResult) {
  LOG(("UDPConnectionEstablisher::Finish %p result=%x", this,
       static_cast<uint32_t>(aResult)));

  FinishInternal(aResult);
}

}  // namespace mozilla::net

Messung V0.5 in Prozent
C=91 H=94 G=92

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002