tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ConnectionEntry.cpp (37800B)


      1 /* vim:set ts=4 sw=2 sts=2 et cin: */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 // HttpLog.h should generally be included first
      7 #include "HttpLog.h"
      8 
      9 // Log on level :5, instead of default :4.
     10 #undef LOG
     11 #define LOG(args) LOG5(args)
     12 #undef LOG_ENABLED
     13 #define LOG_ENABLED() LOG5_ENABLED()
     14 
     15 #include "ConnectionEntry.h"
     16 #include "HttpConnectionUDP.h"
     17 #include "nsQueryObject.h"
     18 #include "mozilla/StaticPrefs_network.h"
     19 #include "nsHttpHandler.h"
     20 #include "mozilla/net/neqo_glue_ffi_generated.h"
     21 
     22 namespace mozilla {
     23 namespace net {
     24 
     25 // ConnectionEntry
     26 ConnectionEntry::~ConnectionEntry() {
     27  LOG(("ConnectionEntry::~ConnectionEntry this=%p", this));
     28 
     29  MOZ_ASSERT(!mIdleConns.Length());
     30  MOZ_ASSERT(!mActiveConns.Length());
     31  MOZ_DIAGNOSTIC_ASSERT(!mDnsAndConnectSockets.Length());
     32  MOZ_ASSERT(!PendingQueueLength());
     33  MOZ_ASSERT(!UrgentStartQueueLength());
     34  MOZ_ASSERT(!mDoNotDestroy);
     35 }
     36 
     37 ConnectionEntry::ConnectionEntry(nsHttpConnectionInfo* ci)
     38    : mConnInfo(ci),
     39      mUsingSpdy(false),
     40      mCanUseSpdy(true),
     41      mPreferIPv4(false),
     42      mPreferIPv6(false),
     43      mUsedForConnection(false),
     44      mDoNotDestroy(false) {
     45  LOG(("ConnectionEntry::ConnectionEntry this=%p key=%s", this,
     46       ci->HashKey().get()));
     47 }
     48 
     49 bool ConnectionEntry::AvailableForDispatchNow() {
     50  if (mIdleConns.Length() && mIdleConns[0]->CanReuse()) {
     51    return true;
     52  }
     53 
     54  return gHttpHandler->ConnMgr()->GetH2orH3ActiveConn(this, false, false) !=
     55         nullptr;
     56 }
     57 
     58 uint32_t ConnectionEntry::UnconnectedDnsAndConnectSockets() const {
     59  uint32_t unconnectedDnsAndConnectSockets = 0;
     60  for (uint32_t i = 0; i < mDnsAndConnectSockets.Length(); ++i) {
     61    if (!mDnsAndConnectSockets[i]->HasConnected()) {
     62      ++unconnectedDnsAndConnectSockets;
     63    }
     64  }
     65  return unconnectedDnsAndConnectSockets;
     66 }
     67 
     68 void ConnectionEntry::InsertIntoDnsAndConnectSockets(
     69    DnsAndConnectSocket* sock) {
     70  mDnsAndConnectSockets.AppendElement(sock);
     71  gHttpHandler->ConnMgr()->IncreaseNumDnsAndConnectSockets();
     72 }
     73 
     74 void ConnectionEntry::RemoveDnsAndConnectSocket(DnsAndConnectSocket* dnsAndSock,
     75                                                bool abandon) {
     76  if (abandon) {
     77    dnsAndSock->Abandon();
     78  }
     79  if (mDnsAndConnectSockets.RemoveElement(dnsAndSock)) {
     80    gHttpHandler->ConnMgr()->DecreaseNumDnsAndConnectSockets();
     81  }
     82 
     83  if (!UnconnectedDnsAndConnectSockets()) {
     84    // perhaps this reverted RestrictConnections()
     85    // use the PostEvent version of processpendingq to avoid
     86    // altering the pending q vector from an arbitrary stack
     87    nsresult rv = gHttpHandler->ConnMgr()->ProcessPendingQ(mConnInfo);
     88    if (NS_FAILED(rv)) {
     89      LOG(
     90          ("ConnectionEntry::RemoveDnsAndConnectSocket\n"
     91           "    failed to process pending queue\n"));
     92    }
     93  }
     94 }
     95 
     96 void ConnectionEntry::CloseAllDnsAndConnectSockets() {
     97  for (const auto& dnsAndSock : mDnsAndConnectSockets) {
     98    dnsAndSock->Abandon();
     99    gHttpHandler->ConnMgr()->DecreaseNumDnsAndConnectSockets();
    100  }
    101  mDnsAndConnectSockets.Clear();
    102  nsresult rv = gHttpHandler->ConnMgr()->ProcessPendingQ(mConnInfo);
    103  if (NS_FAILED(rv)) {
    104    LOG(
    105        ("ConnectionEntry::CloseAllDnsAndConnectSockets\n"
    106         "    failed to process pending queue\n"));
    107  }
    108 }
    109 
    110 void ConnectionEntry::DisallowHttp2() {
    111  mCanUseSpdy = false;
    112 
    113  // If we have any spdy connections, we want to go ahead and close them when
    114  // they're done so we can free up some connections.
    115  for (uint32_t i = 0; i < mActiveConns.Length(); ++i) {
    116    if (mActiveConns[i]->UsingSpdy()) {
    117      mActiveConns[i]->DontReuse();
    118    }
    119  }
    120  for (uint32_t i = 0; i < mIdleConns.Length(); ++i) {
    121    if (mIdleConns[i]->UsingSpdy()) {
    122      mIdleConns[i]->DontReuse();
    123    }
    124  }
    125 
    126  // Can't coalesce if we're not using spdy
    127  mCoalescingKeys.Clear();
    128  mAddresses.Clear();
    129 }
    130 
    131 void ConnectionEntry::DontReuseHttp3Conn() {
    132  MOZ_ASSERT(mConnInfo->IsHttp3());
    133 
    134  // If we have any spdy connections, we want to go ahead and close them when
    135  // they're done so we can free up some connections.
    136  for (uint32_t i = 0; i < mActiveConns.Length(); ++i) {
    137    mActiveConns[i]->DontReuse();
    138  }
    139 
    140  // Can't coalesce if we're not using http3
    141  mCoalescingKeys.Clear();
    142  mAddresses.Clear();
    143 }
    144 
    145 void ConnectionEntry::RecordIPFamilyPreference(uint16_t family) {
    146  LOG(("ConnectionEntry::RecordIPFamilyPreference %p, af=%u", this, family));
    147 
    148  if (family == PR_AF_INET && !mPreferIPv6) {
    149    mPreferIPv4 = true;
    150  }
    151 
    152  if (family == PR_AF_INET6 && !mPreferIPv4) {
    153    mPreferIPv6 = true;
    154  }
    155 
    156  LOG(("  %p prefer ipv4=%d, ipv6=%d", this, (bool)mPreferIPv4,
    157       (bool)mPreferIPv6));
    158 }
    159 
    160 void ConnectionEntry::ResetIPFamilyPreference() {
    161  LOG(("ConnectionEntry::ResetIPFamilyPreference %p", this));
    162 
    163  mPreferIPv4 = false;
    164  mPreferIPv6 = false;
    165 }
    166 
    167 bool net::ConnectionEntry::PreferenceKnown() const {
    168  return (bool)mPreferIPv4 || (bool)mPreferIPv6;
    169 }
    170 
    171 size_t ConnectionEntry::PendingQueueLength() const {
    172  return mPendingQ.PendingQueueLength();
    173 }
    174 
    175 size_t ConnectionEntry::PendingQueueLengthForWindow(uint64_t windowId) const {
    176  return mPendingQ.PendingQueueLengthForWindow(windowId);
    177 }
    178 
    179 void ConnectionEntry::AppendPendingUrgentStartQ(
    180    nsTArray<RefPtr<PendingTransactionInfo>>& result) {
    181  mPendingQ.AppendPendingUrgentStartQ(result);
    182 }
    183 
    184 void ConnectionEntry::AppendPendingQForFocusedWindow(
    185    uint64_t windowId, nsTArray<RefPtr<PendingTransactionInfo>>& result,
    186    uint32_t maxCount) {
    187  mPendingQ.AppendPendingQForFocusedWindow(windowId, result, maxCount);
    188  LOG(
    189      ("ConnectionEntry::AppendPendingQForFocusedWindow [ci=%s], "
    190       "pendingQ count=%zu for focused window (id=%" PRIu64 ")\n",
    191       mConnInfo->HashKey().get(), result.Length(), windowId));
    192 }
    193 
    194 void ConnectionEntry::AppendPendingQForNonFocusedWindows(
    195    uint64_t windowId, nsTArray<RefPtr<PendingTransactionInfo>>& result,
    196    uint32_t maxCount) {
    197  mPendingQ.AppendPendingQForNonFocusedWindows(windowId, result, maxCount);
    198  LOG(
    199      ("ConnectionEntry::AppendPendingQForNonFocusedWindows [ci=%s], "
    200       "pendingQ count=%zu for non focused window\n",
    201       mConnInfo->HashKey().get(), result.Length()));
    202 }
    203 
    204 void ConnectionEntry::RemoveEmptyPendingQ() { mPendingQ.RemoveEmptyPendingQ(); }
    205 
    206 void ConnectionEntry::InsertTransactionSorted(
    207    nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ,
    208    PendingTransactionInfo* pendingTransInfo,
    209    bool aInsertAsFirstForTheSamePriority /*= false*/) {
    210  mPendingQ.InsertTransactionSorted(pendingQ, pendingTransInfo,
    211                                    aInsertAsFirstForTheSamePriority);
    212 }
    213 
    214 void ConnectionEntry::ReschedTransaction(nsHttpTransaction* aTrans) {
    215  mPendingQ.ReschedTransaction(aTrans);
    216 }
    217 
    218 void ConnectionEntry::InsertTransaction(
    219    PendingTransactionInfo* pendingTransInfo,
    220    bool aInsertAsFirstForTheSamePriority /* = false */) {
    221  mPendingQ.InsertTransaction(pendingTransInfo,
    222                              aInsertAsFirstForTheSamePriority);
    223  pendingTransInfo->Transaction()->OnPendingQueueInserted(mConnInfo->HashKey());
    224 }
    225 
    226 nsTArray<RefPtr<PendingTransactionInfo>>*
    227 ConnectionEntry::GetTransactionPendingQHelper(nsAHttpTransaction* trans) {
    228  return mPendingQ.GetTransactionPendingQHelper(trans);
    229 }
    230 
    231 bool ConnectionEntry::RestrictConnections() {
    232  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    233 
    234  if (AvailableForDispatchNow()) {
    235    // this might be a h2/spdy connection in this connection entry that
    236    // is able to be immediately muxxed, or it might be one that
    237    // was found in the same state through a coalescing hash
    238    LOG(
    239        ("ConnectionEntry::RestrictConnections %p %s restricted due to "
    240         "active >=h2\n",
    241         this, mConnInfo->HashKey().get()));
    242    return true;
    243  }
    244 
    245  // If this host is trying to negotiate a SPDY session right now,
    246  // don't create any new ssl connections until the result of the
    247  // negotiation is known.
    248 
    249  bool doRestrict = mConnInfo->FirstHopSSL() &&
    250                    StaticPrefs::network_http_http2_enabled() && mUsingSpdy &&
    251                    (mDnsAndConnectSockets.Length() || mActiveConns.Length());
    252 
    253  // If there are no restrictions, we are done
    254  if (!doRestrict) {
    255    return false;
    256  }
    257 
    258  // If the restriction is based on a tcp handshake in progress
    259  // let that connect and then see if it was SPDY or not
    260  if (UnconnectedDnsAndConnectSockets()) {
    261    return true;
    262  }
    263 
    264  // There is a concern that a host is using a mix of HTTP/1 and SPDY.
    265  // In that case we don't want to restrict connections just because
    266  // there is a single active HTTP/1 session in use.
    267  // When a tunnel is used, we should avoid bypassing connection restrictions.
    268  // Otherwise, we might create too many unused tunnels.
    269  if (mUsingSpdy && mActiveConns.Length() &&
    270      !(mConnInfo->UsingHttpsProxy() && mConnInfo->UsingConnect())) {
    271    bool confirmedRestrict = false;
    272    for (uint32_t index = 0; index < mActiveConns.Length(); ++index) {
    273      HttpConnectionBase* conn = mActiveConns[index];
    274      RefPtr<nsHttpConnection> connTCP = do_QueryObject(conn);
    275      if ((connTCP && !connTCP->ReportedNPN()) || conn->CanDirectlyActivate()) {
    276        confirmedRestrict = true;
    277        break;
    278      }
    279    }
    280    doRestrict = confirmedRestrict;
    281    if (!confirmedRestrict) {
    282      LOG(
    283          ("nsHttpConnectionMgr spdy connection restriction to "
    284           "%s bypassed.\n",
    285           mConnInfo->Origin()));
    286    }
    287  }
    288  return doRestrict;
    289 }
    290 
    291 uint32_t ConnectionEntry::TotalActiveConnections() const {
    292  // Add in the in-progress tcp connections, we will assume they are
    293  // keepalive enabled.
    294  // Exclude DnsAndConnectSocket's that has already created a usable connection.
    295  // This prevents the limit being stuck on ipv6 connections that
    296  // eventually time out after typical 21 seconds of no ACK+SYN reply.
    297  return mActiveConns.Length() + UnconnectedDnsAndConnectSockets();
    298 }
    299 
    300 size_t ConnectionEntry::UrgentStartQueueLength() {
    301  return mPendingQ.UrgentStartQueueLength();
    302 }
    303 
    304 void ConnectionEntry::PrintPendingQ() { mPendingQ.PrintPendingQ(); }
    305 
    306 void ConnectionEntry::Compact() {
    307  mIdleConns.Compact();
    308  mActiveConns.Compact();
    309  mPendingQ.Compact();
    310 }
    311 
    312 void ConnectionEntry::RemoveFromIdleConnectionsIndex(size_t inx) {
    313  mIdleConns.RemoveElementAt(inx);
    314  gHttpHandler->ConnMgr()->DecrementNumIdleConns();
    315 }
    316 
    317 bool ConnectionEntry::RemoveFromIdleConnections(nsHttpConnection* conn) {
    318  if (!mIdleConns.RemoveElement(conn)) {
    319    return false;
    320  }
    321 
    322  gHttpHandler->ConnMgr()->DecrementNumIdleConns();
    323  return true;
    324 }
    325 
    326 void ConnectionEntry::CancelAllTransactions(nsresult reason) {
    327  mPendingQ.CancelAllTransactions(reason);
    328 }
    329 
    330 nsresult ConnectionEntry::CloseIdleConnection(nsHttpConnection* conn) {
    331  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    332 
    333  RefPtr<nsHttpConnection> deleteProtector(conn);
    334  if (!RemoveFromIdleConnections(conn)) {
    335    return NS_ERROR_UNEXPECTED;
    336  }
    337 
    338  // The connection is closed immediately no need to call EndIdleMonitoring.
    339  conn->Close(NS_ERROR_ABORT);
    340  return NS_OK;
    341 }
    342 
    343 void ConnectionEntry::CloseIdleConnections() {
    344  while (mIdleConns.Length()) {
    345    RefPtr<nsHttpConnection> conn(mIdleConns[0]);
    346    RemoveFromIdleConnectionsIndex(0);
    347    // The connection is closed immediately no need to call EndIdleMonitoring.
    348    conn->Close(NS_ERROR_ABORT);
    349  }
    350 }
    351 
    352 void ConnectionEntry::CloseIdleConnections(uint32_t maxToClose) {
    353  uint32_t closed = 0;
    354  while (mIdleConns.Length() && (closed < maxToClose)) {
    355    RefPtr<nsHttpConnection> conn(mIdleConns[0]);
    356    RemoveFromIdleConnectionsIndex(0);
    357    // The connection is closed immediately no need to call EndIdleMonitoring.
    358    conn->Close(NS_ERROR_ABORT);
    359    closed++;
    360  }
    361 }
    362 
    363 void ConnectionEntry::CloseExtendedCONNECTConnections() {
    364  while (mExtendedCONNECTConns.Length()) {
    365    RefPtr<HttpConnectionBase> conn(mExtendedCONNECTConns[0]);
    366    mExtendedCONNECTConns.RemoveElementAt(0);
    367 
    368    // safe to close connection since we are on the socket thread
    369    // closing via transaction to break connection/transaction bond
    370    conn->CloseTransaction(conn->Transaction(), NS_ERROR_ABORT, true);
    371  }
    372 }
    373 
    374 nsresult ConnectionEntry::RemoveIdleConnection(nsHttpConnection* conn) {
    375  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    376 
    377  if (!RemoveFromIdleConnections(conn)) {
    378    return NS_ERROR_UNEXPECTED;
    379  }
    380 
    381  conn->EndIdleMonitoring();
    382  return NS_OK;
    383 }
    384 
    385 bool ConnectionEntry::IsInIdleConnections(HttpConnectionBase* conn) {
    386  RefPtr<nsHttpConnection> connTCP = do_QueryObject(conn);
    387  return connTCP && mIdleConns.Contains(connTCP);
    388 }
    389 
    390 already_AddRefed<nsHttpConnection> ConnectionEntry::GetIdleConnection(
    391    bool respectUrgency, bool urgentTrans, bool* onlyUrgent) {
    392  RefPtr<nsHttpConnection> conn;
    393  size_t index = 0;
    394  while (!conn && (mIdleConns.Length() > index)) {
    395    conn = mIdleConns[index];
    396 
    397    if (!conn->CanReuse()) {
    398      RemoveFromIdleConnectionsIndex(index);
    399      LOG(("   dropping stale connection: [conn=%p]\n", conn.get()));
    400      conn->Close(NS_ERROR_ABORT);
    401      conn = nullptr;
    402      continue;
    403    }
    404 
    405    // non-urgent transactions can only be dispatched on non-urgent
    406    // started or used connections.
    407    if (respectUrgency && conn->IsUrgentStartPreferred() && !urgentTrans) {
    408      LOG(("  skipping urgent: [conn=%p]", conn.get()));
    409      conn = nullptr;
    410      ++index;
    411      continue;
    412    }
    413 
    414    *onlyUrgent = false;
    415 
    416    RemoveFromIdleConnectionsIndex(index);
    417    conn->EndIdleMonitoring();
    418    LOG(("   reusing connection: [conn=%p]\n", conn.get()));
    419  }
    420 
    421  return conn.forget();
    422 }
    423 
    424 nsresult ConnectionEntry::RemoveActiveConnection(HttpConnectionBase* conn) {
    425  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    426 
    427  if (!mActiveConns.RemoveElement(conn)) {
    428    return NS_ERROR_UNEXPECTED;
    429  }
    430  conn->SetOwner(nullptr);
    431  gHttpHandler->ConnMgr()->DecrementActiveConnCount(conn);
    432 
    433  return NS_OK;
    434 }
    435 
    436 nsresult ConnectionEntry::RemovePendingConnection(HttpConnectionBase* conn) {
    437  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    438 
    439  if (!mPendingConns.RemoveElement(conn)) {
    440    return NS_ERROR_UNEXPECTED;
    441  }
    442 
    443  return NS_OK;
    444 }
    445 
    446 void ConnectionEntry::ClosePersistentConnections() {
    447  LOG(("ConnectionEntry::ClosePersistentConnections [ci=%s]\n",
    448       mConnInfo->HashKey().get()));
    449  CloseIdleConnections();
    450 
    451  int32_t activeCount = mActiveConns.Length();
    452  for (int32_t i = 0; i < activeCount; i++) {
    453    mActiveConns[i]->DontReuse();
    454  }
    455 
    456  mCoalescingKeys.Clear();
    457  mAddresses.Clear();
    458 }
    459 
    460 uint32_t ConnectionEntry::PruneDeadConnections() {
    461  uint32_t timeToNextExpire = UINT32_MAX;
    462 
    463  for (int32_t len = mIdleConns.Length(); len > 0; --len) {
    464    int32_t idx = len - 1;
    465    RefPtr<nsHttpConnection> conn(mIdleConns[idx]);
    466    if (!conn->CanReuse()) {
    467      RemoveFromIdleConnectionsIndex(idx);
    468      // The connection is closed immediately no need to call
    469      // EndIdleMonitoring.
    470      conn->Close(NS_ERROR_ABORT);
    471    } else {
    472      timeToNextExpire = std::min(timeToNextExpire, conn->TimeToLive());
    473    }
    474  }
    475 
    476  if (mUsingSpdy) {
    477    for (uint32_t i = 0; i < mActiveConns.Length(); ++i) {
    478      RefPtr<nsHttpConnection> connTCP = do_QueryObject(mActiveConns[i]);
    479      // Http3 has its own timers, it is not using this one.
    480      if (connTCP && connTCP->UsingSpdy()) {
    481        if (!connTCP->CanReuse()) {
    482          // Marking it don't-reuse will create an active
    483          // tear down if the spdy session is idle.
    484          connTCP->DontReuse();
    485        } else {
    486          timeToNextExpire = std::min(timeToNextExpire, connTCP->TimeToLive());
    487        }
    488      }
    489    }
    490  }
    491 
    492  return timeToNextExpire;
    493 }
    494 
    495 void ConnectionEntry::MakeConnectionPendingAndDontReuse(
    496    HttpConnectionBase* conn) {
    497  gHttpHandler->ConnMgr()->DecrementActiveConnCount(conn);
    498  mPendingConns.AppendElement(conn);
    499  // After DontReuse(), the connection will be closed after the last
    500  // transition is done.
    501  conn->DontReuse();
    502  LOG(("Move active connection to pending list [conn=%p]\n", conn));
    503 }
    504 
    505 template <typename ConnType>
    506 static void CheckForTrafficForConns(nsTArray<RefPtr<ConnType>>& aConns,
    507                                    bool aCheck) {
    508  for (uint32_t index = 0; index < aConns.Length(); ++index) {
    509    RefPtr<nsHttpConnection> conn = do_QueryObject(aConns[index]);
    510    if (conn) {
    511      conn->CheckForTraffic(aCheck);
    512    }
    513  }
    514 }
    515 
    516 void ConnectionEntry::VerifyTraffic() {
    517  if (!mConnInfo->IsHttp3()) {
    518    CheckForTrafficForConns(mPendingConns, true);
    519    // Iterate the idle connections and unmark them for traffic checks.
    520    CheckForTrafficForConns(mIdleConns, false);
    521  }
    522 
    523  uint32_t numConns = mActiveConns.Length();
    524  if (numConns) {
    525    // Walk the list backwards to allow us to remove entries easily.
    526    for (int index = numConns - 1; index >= 0; index--) {
    527      RefPtr<nsHttpConnection> conn = do_QueryObject(mActiveConns[index]);
    528      RefPtr<HttpConnectionUDP> connUDP = do_QueryObject(mActiveConns[index]);
    529      if (conn) {
    530        conn->CheckForTraffic(true);
    531        if (conn->EverUsedSpdy() &&
    532            StaticPrefs::
    533                network_http_move_to_pending_list_after_network_change()) {
    534          mActiveConns.RemoveElementAt(index);
    535          conn->SetOwner(nullptr);
    536          MakeConnectionPendingAndDontReuse(conn);
    537        }
    538      } else if (connUDP &&
    539                 StaticPrefs::
    540                     network_http_move_to_pending_list_after_network_change()) {
    541        mActiveConns.RemoveElementAt(index);
    542        connUDP->SetOwner(nullptr);
    543        MakeConnectionPendingAndDontReuse(connUDP);
    544      }
    545    }
    546  }
    547 }
    548 
    549 void ConnectionEntry::InsertIntoIdleConnections_internal(
    550    nsHttpConnection* conn) {
    551  uint32_t idx;
    552  for (idx = 0; idx < mIdleConns.Length(); idx++) {
    553    nsHttpConnection* idleConn = mIdleConns[idx];
    554    if (idleConn->MaxBytesRead() < conn->MaxBytesRead()) {
    555      break;
    556    }
    557  }
    558 
    559  mIdleConns.InsertElementAt(idx, conn);
    560 }
    561 
    562 void ConnectionEntry::InsertIntoIdleConnections(nsHttpConnection* conn) {
    563  InsertIntoIdleConnections_internal(conn);
    564  gHttpHandler->ConnMgr()->NewIdleConnectionAdded(conn->TimeToLive());
    565  conn->BeginIdleMonitoring();
    566 }
    567 
    568 bool ConnectionEntry::IsInActiveConns(HttpConnectionBase* conn) {
    569  return mActiveConns.Contains(conn);
    570 }
    571 
    572 void ConnectionEntry::InsertIntoActiveConns(HttpConnectionBase* conn) {
    573  mActiveConns.AppendElement(conn);
    574  conn->SetOwner(this);
    575  gHttpHandler->ConnMgr()->IncrementActiveConnCount();
    576 }
    577 
    578 bool ConnectionEntry::IsInExtendedCONNECTConns(HttpConnectionBase* conn) {
    579  return mExtendedCONNECTConns.Contains(conn);
    580 }
    581 
    582 void ConnectionEntry::InsertIntoExtendedCONNECTConns(HttpConnectionBase* conn) {
    583  // no incrementing of connection count since it is a tunneled connection
    584  mExtendedCONNECTConns.AppendElement(conn);
    585 }
    586 
    587 void ConnectionEntry::RemoveExtendedCONNECTConns(HttpConnectionBase* conn) {
    588  mExtendedCONNECTConns.RemoveElement(conn);
    589 }
    590 
    591 void ConnectionEntry::MakeAllDontReuseExcept(HttpConnectionBase* conn) {
    592  for (uint32_t index = 0; index < mActiveConns.Length(); ++index) {
    593    HttpConnectionBase* otherConn = mActiveConns[index];
    594    if (otherConn != conn) {
    595      LOG(
    596          ("ConnectionEntry::MakeAllDontReuseExcept shutting down old "
    597           "connection (%p) "
    598           "because new "
    599           "spdy connection (%p) takes precedence\n",
    600           otherConn, conn));
    601      otherConn->SetCloseReason(
    602          ConnectionCloseReason::CLOSE_EXISTING_CONN_FOR_COALESCING);
    603      otherConn->DontReuse();
    604    }
    605  }
    606 
    607  // Cancel any other pending connections - their associated transactions
    608  // are in the pending queue and will be dispatched onto this new connection
    609  CloseAllDnsAndConnectSockets();
    610 }
    611 
    612 bool ConnectionEntry::FindConnToClaim(
    613    PendingTransactionInfo* pendingTransInfo) {
    614  nsHttpTransaction* trans = pendingTransInfo->Transaction();
    615 
    616  for (const auto& dnsAndSock : mDnsAndConnectSockets) {
    617    if (dnsAndSock->AcceptsTransaction(trans) && dnsAndSock->Claim()) {
    618      pendingTransInfo->RememberDnsAndConnectSocket(dnsAndSock);
    619      // We've found a speculative connection or a connection that
    620      // is free to be used in the DnsAndConnectSockets list.
    621      // A free to be used connection is a connection that was
    622      // open for a concrete transaction, but that trunsaction
    623      // ended up using another connection.
    624      LOG(
    625          ("ConnectionEntry::FindConnToClaim [ci = %s]\n"
    626           "Found a speculative or a free-to-use DnsAndConnectSocket\n",
    627           mConnInfo->HashKey().get()));
    628 
    629      // return OK because we have essentially opened a new connection
    630      // by converting a speculative DnsAndConnectSockets to general use
    631      return true;
    632    }
    633  }
    634 
    635  // consider null transactions that are being used to drive the ssl handshake
    636  // if the transaction creating this connection can re-use persistent
    637  // connections
    638  if (trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) {
    639    uint32_t activeLength = mActiveConns.Length();
    640    for (uint32_t i = 0; i < activeLength; i++) {
    641      if (pendingTransInfo->TryClaimingActiveConn(mActiveConns[i])) {
    642        LOG(
    643            ("ConnectionEntry::FindConnectingSocket [ci = %s] "
    644             "Claiming a null transaction for later use\n",
    645             mConnInfo->HashKey().get()));
    646        return true;
    647      }
    648    }
    649  }
    650  return false;
    651 }
    652 
    653 bool ConnectionEntry::MakeFirstActiveSpdyConnDontReuse() {
    654  if (!mUsingSpdy) {
    655    return false;
    656  }
    657 
    658  for (uint32_t index = 0; index < mActiveConns.Length(); ++index) {
    659    HttpConnectionBase* conn = mActiveConns[index];
    660    if (conn->UsingSpdy() && conn->CanReuse()) {
    661      conn->DontReuse();
    662      return true;
    663    }
    664  }
    665  return false;
    666 }
    667 
    668 // Return an active h2 or h3 connection
    669 // that can be directly activated or null.
    670 HttpConnectionBase* ConnectionEntry::GetH2orH3ActiveConn() {
    671  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    672 
    673  HttpConnectionBase* experienced = nullptr;
    674  HttpConnectionBase* noExperience = nullptr;
    675  uint32_t activeLen = mActiveConns.Length();
    676 
    677  // activeLen should generally be 1.. this is a setup race being resolved
    678  // take a conn who can activate and is experienced
    679  for (uint32_t index = 0; index < activeLen; ++index) {
    680    HttpConnectionBase* tmp = mActiveConns[index];
    681    if (tmp->CanDirectlyActivate()) {
    682      if (tmp->IsExperienced()) {
    683        experienced = tmp;
    684        break;
    685      }
    686      noExperience = tmp;  // keep looking for a better option
    687    }
    688  }
    689 
    690  // if that worked, cleanup anything else and exit
    691  if (experienced) {
    692    for (uint32_t index = 0; index < activeLen; ++index) {
    693      HttpConnectionBase* tmp = mActiveConns[index];
    694      // in the case where there is a functional h2 session, drop the others
    695      if (tmp != experienced) {
    696        tmp->DontReuse();
    697      }
    698    }
    699 
    700    LOG(
    701        ("GetH2orH3ActiveConn() request for ent %p %s "
    702         "found an active experienced connection %p in native connection "
    703         "entry\n",
    704         this, mConnInfo->HashKey().get(), experienced));
    705    return experienced;
    706  }
    707 
    708  if (noExperience) {
    709    LOG(
    710        ("GetH2orH3ActiveConn() request for ent %p %s "
    711         "found an active but inexperienced connection %p in native connection "
    712         "entry\n",
    713         this, mConnInfo->HashKey().get(), noExperience));
    714    return noExperience;
    715  }
    716 
    717  return nullptr;
    718 }
    719 
    720 already_AddRefed<nsHttpConnection> ConnectionEntry::GetH2TunnelActiveConn() {
    721  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    722 
    723  for (const auto& conn : mActiveConns) {
    724    RefPtr<nsHttpConnection> connTCP = do_QueryObject(conn);
    725    if (connTCP && connTCP->UsingSpdy() && connTCP->CanDirectlyActivate()) {
    726      LOG(
    727          ("GetH2TunnelActiveConn() request for ent %p %s "
    728           "found an H2 tunnel connection %p\n",
    729           this, mConnInfo->HashKey().get(), connTCP.get()));
    730      return connTCP.forget();
    731    }
    732  }
    733 
    734  return nullptr;
    735 }
    736 
    737 void ConnectionEntry::CloseActiveConnections() {
    738  while (mActiveConns.Length()) {
    739    RefPtr<HttpConnectionBase> conn(mActiveConns[0]);
    740    mActiveConns.RemoveElementAt(0);
    741    conn->SetOwner(nullptr);
    742    gHttpHandler->ConnMgr()->DecrementActiveConnCount(conn);
    743 
    744    // Since HttpConnectionBase::Close doesn't break the bond with
    745    // the connection's transaction, we must explicitely tell it
    746    // to close its transaction and not just self.
    747    conn->CloseTransaction(conn->Transaction(), NS_ERROR_ABORT, true);
    748  }
    749 }
    750 
    751 void ConnectionEntry::CloseAllActiveConnsWithNullTransactcion(
    752    nsresult aCloseCode) {
    753  for (uint32_t index = 0; index < mActiveConns.Length(); ++index) {
    754    RefPtr<HttpConnectionBase> activeConn = mActiveConns[index];
    755    nsAHttpTransaction* liveTransaction = activeConn->Transaction();
    756    if (liveTransaction && liveTransaction->IsNullTransaction()) {
    757      LOG(
    758          ("ConnectionEntry::CloseAllActiveConnsWithNullTransactcion "
    759           "also canceling Null Transaction %p on conn %p\n",
    760           liveTransaction, activeConn.get()));
    761      activeConn->CloseTransaction(liveTransaction, aCloseCode);
    762    }
    763  }
    764 }
    765 
    766 void ConnectionEntry::ClosePendingConnections() {
    767  while (mPendingConns.Length()) {
    768    RefPtr<HttpConnectionBase> conn(mPendingConns[0]);
    769    mPendingConns.RemoveElementAt(0);
    770 
    771    // Since HttpConnectionBase::Close doesn't break the bond with
    772    // the connection's transaction, we must explicitely tell it
    773    // to close its transaction and not just self.
    774    conn->CloseTransaction(conn->Transaction(), NS_ERROR_ABORT, true);
    775  }
    776 }
    777 
    778 void ConnectionEntry::PruneNoTraffic() {
    779  LOG(("  pruning no traffic [ci=%s]\n", mConnInfo->HashKey().get()));
    780  if (mConnInfo->IsHttp3()) {
    781    return;
    782  }
    783 
    784  uint32_t numConns = mActiveConns.Length();
    785  if (numConns) {
    786    // Walk the list backwards to allow us to remove entries easily.
    787    for (int index = numConns - 1; index >= 0; index--) {
    788      RefPtr<nsHttpConnection> conn = do_QueryObject(mActiveConns[index]);
    789      if (conn && conn->NoTraffic()) {
    790        mActiveConns.RemoveElementAt(index);
    791        conn->SetOwner(nullptr);
    792        gHttpHandler->ConnMgr()->DecrementActiveConnCount(conn);
    793        conn->Close(NS_ERROR_ABORT);
    794        LOG(
    795            ("  closed active connection due to no traffic "
    796             "[conn=%p]\n",
    797             conn.get()));
    798      }
    799    }
    800  }
    801 }
    802 
    803 uint32_t ConnectionEntry::TimeoutTick() {
    804  uint32_t timeoutTickNext = 3600;  // 1hr
    805 
    806  if (mConnInfo->IsHttp3()) {
    807    return timeoutTickNext;
    808  }
    809 
    810  LOG(
    811      ("ConnectionEntry::TimeoutTick() this=%p host=%s "
    812       "idle=%zu active=%zu"
    813       " dnsAndSock-len=%zu pending=%zu"
    814       " urgentStart pending=%zu\n",
    815       this, mConnInfo->Origin(), IdleConnectionsLength(), ActiveConnsLength(),
    816       mDnsAndConnectSockets.Length(), PendingQueueLength(),
    817       UrgentStartQueueLength()));
    818 
    819  // First call the tick handler for each active connection.
    820  PRIntervalTime tickTime = PR_IntervalNow();
    821  for (uint32_t index = 0; index < mActiveConns.Length(); ++index) {
    822    RefPtr<nsHttpConnection> conn = do_QueryObject(mActiveConns[index]);
    823    if (conn) {
    824      uint32_t connNextTimeout = conn->ReadTimeoutTick(tickTime);
    825      timeoutTickNext = std::min(timeoutTickNext, connNextTimeout);
    826    }
    827  }
    828 
    829  // Now check for any stalled DnsAndConnectSockets.
    830  if (mDnsAndConnectSockets.Length()) {
    831    TimeStamp currentTime = TimeStamp::Now();
    832    double maxConnectTime_ms = gHttpHandler->ConnectTimeout();
    833 
    834    for (const auto& dnsAndSock : Reversed(mDnsAndConnectSockets)) {
    835      double delta = dnsAndSock->Duration(currentTime);
    836      // If the socket has timed out, close it so the waiting
    837      // transaction will get the proper signal.
    838      if (delta > maxConnectTime_ms) {
    839        LOG(("Force timeout of DnsAndConnectSocket to %s after %.2fms.\n",
    840             mConnInfo->HashKey().get(), delta));
    841        dnsAndSock->CloseTransports(NS_ERROR_NET_TIMEOUT);
    842      }
    843 
    844      // If this DnsAndConnectSocket hangs around for 5 seconds after we've
    845      // closed() it then just abandon the socket.
    846      if (delta > maxConnectTime_ms + 5000) {
    847        LOG(("Abandon DnsAndConnectSocket to %s after %.2fms.\n",
    848             mConnInfo->HashKey().get(), delta));
    849        RemoveDnsAndConnectSocket(dnsAndSock, true);
    850      }
    851    }
    852  }
    853  if (mDnsAndConnectSockets.Length()) {
    854    timeoutTickNext = 1;
    855  }
    856 
    857  return timeoutTickNext;
    858 }
    859 
    860 void ConnectionEntry::MoveConnection(HttpConnectionBase* proxyConn,
    861                                     ConnectionEntry* otherEnt) {
    862  // To avoid changing mNumActiveConns/mNumIdleConns counter use internal
    863  // functions.
    864  RefPtr<HttpConnectionBase> deleteProtector(proxyConn);
    865  if (mActiveConns.RemoveElement(proxyConn)) {
    866    otherEnt->mActiveConns.AppendElement(proxyConn);
    867    proxyConn->SetOwner(otherEnt);
    868    return;
    869  }
    870 
    871  RefPtr<nsHttpConnection> proxyConnTCP = do_QueryObject(proxyConn);
    872  if (proxyConnTCP) {
    873    if (mIdleConns.RemoveElement(proxyConnTCP)) {
    874      otherEnt->InsertIntoIdleConnections_internal(proxyConnTCP);
    875      return;
    876    }
    877  }
    878 }
    879 
    880 HttpRetParams ConnectionEntry::GetConnectionData() {
    881  HttpRetParams data;
    882  data.host = mConnInfo->Origin();
    883  data.port = mConnInfo->OriginPort();
    884  for (uint32_t i = 0; i < mActiveConns.Length(); i++) {
    885    HttpConnInfo info;
    886    RefPtr<nsHttpConnection> connTCP = do_QueryObject(mActiveConns[i]);
    887    if (connTCP) {
    888      info.ttl = connTCP->TimeToLive();
    889    } else {
    890      info.ttl = 0;
    891    }
    892    info.rtt = mActiveConns[i]->Rtt();
    893    info.SetHTTPProtocolVersion(mActiveConns[i]->Version());
    894    data.active.AppendElement(info);
    895  }
    896  for (uint32_t i = 0; i < mIdleConns.Length(); i++) {
    897    HttpConnInfo info;
    898    info.ttl = mIdleConns[i]->TimeToLive();
    899    info.rtt = mIdleConns[i]->Rtt();
    900    info.SetHTTPProtocolVersion(mIdleConns[i]->Version());
    901    data.idle.AppendElement(info);
    902  }
    903  for (uint32_t i = 0; i < mDnsAndConnectSockets.Length(); i++) {
    904    DnsAndConnectSockets dnsAndSock{};
    905    dnsAndSock.speculative = mDnsAndConnectSockets[i]->IsSpeculative();
    906    data.dnsAndSocks.AppendElement(dnsAndSock);
    907  }
    908  if (mConnInfo->IsHttp3()) {
    909    data.httpVersion = "HTTP/3"_ns;
    910  } else if (mUsingSpdy) {
    911    data.httpVersion = "HTTP/2"_ns;
    912  } else {
    913    data.httpVersion = "HTTP <= 1.1"_ns;
    914  }
    915  data.ssl = mConnInfo->EndToEndSSL();
    916  return data;
    917 }
    918 
    919 Http3ConnectionStatsParams ConnectionEntry::GetHttp3ConnectionStatsData() {
    920  Http3ConnectionStatsParams data;
    921  if (!mConnInfo->IsHttp3()) {
    922    return data;
    923  }
    924  data.host = mConnInfo->Origin();
    925  data.port = mConnInfo->OriginPort();
    926 
    927  for (uint32_t i = 0; i < mActiveConns.Length(); i++) {
    928    RefPtr<HttpConnectionUDP> connUDP = do_QueryObject(mActiveConns[i]);
    929    if (!connUDP) {
    930      continue;
    931    }
    932 
    933    Http3Stats stats = connUDP->GetStats();
    934    Http3ConnStats res;
    935    res.packetsRx = stats.packets_rx;
    936    res.dupsRx = stats.dups_rx;
    937    res.droppedRx = stats.dropped_rx;
    938    res.savedDatagrams = stats.saved_datagrams;
    939    res.packetsTx = stats.packets_tx;
    940    res.lost = stats.lost;
    941    res.lateAck = stats.late_ack;
    942    res.ptoAck = stats.pto_ack;
    943    res.wouldBlockRx = stats.would_block_rx;
    944    res.wouldBlockTx = stats.would_block_tx;
    945    res.ptoCounts.AppendElements(&stats.pto_counts[0], 16);
    946 
    947    data.stats.AppendElement(std::move(res));
    948  }
    949  return data;
    950 }
    951 
    952 void ConnectionEntry::LogConnections() {
    953  LOG(("active conns ["));
    954  for (HttpConnectionBase* conn : mActiveConns) {
    955    LOG(("  %p", conn));
    956  }
    957 
    958  LOG(("] idle conns ["));
    959  for (nsHttpConnection* conn : mIdleConns) {
    960    LOG(("  %p", conn));
    961  }
    962  LOG(("]"));
    963 }
    964 
    965 bool ConnectionEntry::RemoveTransFromPendingQ(nsHttpTransaction* aTrans) {
    966  // We will abandon all DnsAndConnectSockets belonging to the given
    967  // transaction.
    968  nsTArray<RefPtr<PendingTransactionInfo>>* infoArray =
    969      GetTransactionPendingQHelper(aTrans);
    970 
    971  RefPtr<PendingTransactionInfo> pendingTransInfo;
    972  int32_t transIndex =
    973      infoArray ? infoArray->IndexOf(aTrans, 0, PendingComparator()) : -1;
    974  if (transIndex >= 0) {
    975    pendingTransInfo = (*infoArray)[transIndex];
    976    infoArray->RemoveElementAt(transIndex);
    977  }
    978 
    979  if (!pendingTransInfo) {
    980    return false;
    981  }
    982 
    983  // Abandon all DnsAndConnectSockets belonging to the given transaction.
    984  nsWeakPtr tmp = pendingTransInfo->ForgetDnsAndConnectSocketAndActiveConn();
    985  RefPtr<DnsAndConnectSocket> dnsAndSock = do_QueryReferent(tmp);
    986  if (dnsAndSock) {
    987    RemoveDnsAndConnectSocket(dnsAndSock, true);
    988  }
    989  return true;
    990 }
    991 
    992 void ConnectionEntry::MaybeUpdateEchConfig(nsHttpConnectionInfo* aConnInfo) {
    993  if (!mConnInfo->HashKey().Equals(aConnInfo->HashKey())) {
    994    return;
    995  }
    996 
    997  const nsCString& echConfig = aConnInfo->GetEchConfig();
    998  if (mConnInfo->GetEchConfig().Equals(echConfig)) {
    999    return;
   1000  }
   1001 
   1002  LOG(("ConnectionEntry::MaybeUpdateEchConfig [ci=%s]\n",
   1003       mConnInfo->HashKey().get()));
   1004 
   1005  mConnInfo->SetEchConfig(echConfig);
   1006 
   1007  // If echConfig is changed, we should close all DnsAndConnectSockets and idle
   1008  // connections. This is to make sure the new echConfig will be used for the
   1009  // next connection.
   1010  CloseAllDnsAndConnectSockets();
   1011  CloseIdleConnections();
   1012 }
   1013 
   1014 bool ConnectionEntry::MaybeProcessCoalescingKeys(nsIDNSAddrRecord* dnsRecord,
   1015                                                 bool aIsHttp3) {
   1016  if (!mConnInfo || !mConnInfo->EndToEndSSL() || (!aIsHttp3 && !AllowHttp2()) ||
   1017      mConnInfo->UsingProxy() || !mCoalescingKeys.IsEmpty() || !dnsRecord) {
   1018    return false;
   1019  }
   1020 
   1021  nsresult rv = dnsRecord->GetAddresses(mAddresses);
   1022  if (NS_FAILED(rv) || mAddresses.IsEmpty()) {
   1023    return false;
   1024  }
   1025 
   1026  for (uint32_t i = 0; i < mAddresses.Length(); ++i) {
   1027    if ((mAddresses[i].raw.family == AF_INET && mAddresses[i].inet.ip == 0) ||
   1028        (mAddresses[i].raw.family == AF_INET6 &&
   1029         mAddresses[i].inet6.ip.u64[0] == 0 &&
   1030         mAddresses[i].inet6.ip.u64[1] == 0)) {
   1031      // Bug 1680249 - Don't create the coalescing key if the ip address is
   1032      // `0.0.0.0` or `::`.
   1033      LOG(
   1034          ("ConnectionEntry::MaybeProcessCoalescingKeys skip creating "
   1035           "Coalescing Key for host [%s]",
   1036           mConnInfo->Origin()));
   1037      continue;
   1038    }
   1039    nsCString* newKey = mCoalescingKeys.AppendElement(nsCString());
   1040    newKey->SetLength(kIPv6CStrBufSize + 26);
   1041    mAddresses[i].ToStringBuffer(newKey->BeginWriting(), kIPv6CStrBufSize);
   1042    newKey->SetLength(strlen(newKey->BeginReading()));
   1043    if (mConnInfo->GetAnonymous()) {
   1044      newKey->AppendLiteral("~A:");
   1045    } else {
   1046      newKey->AppendLiteral("~.:");
   1047    }
   1048    if (mConnInfo->GetFallbackConnection()) {
   1049      newKey->AppendLiteral("~F:");
   1050    } else {
   1051      newKey->AppendLiteral("~.:");
   1052    }
   1053    newKey->AppendInt(mConnInfo->OriginPort());
   1054    newKey->AppendLiteral("/[");
   1055    nsAutoCString suffix;
   1056    mConnInfo->GetOriginAttributes().CreateSuffix(suffix);
   1057    newKey->Append(suffix);
   1058    newKey->AppendLiteral("]viaDNS");
   1059    LOG(
   1060        ("ConnectionEntry::MaybeProcessCoalescingKeys "
   1061         "Established New Coalescing Key # %d for host "
   1062         "%s [%s]",
   1063         i, mConnInfo->Origin(), newKey->get()));
   1064  }
   1065  return true;
   1066 }
   1067 
   1068 nsresult ConnectionEntry::CreateDnsAndConnectSocket(
   1069    nsAHttpTransaction* trans, uint32_t caps, bool speculative,
   1070    bool urgentStart, bool allow1918,
   1071    PendingTransactionInfo* pendingTransInfo) {
   1072  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1073  MOZ_ASSERT((speculative && !pendingTransInfo) ||
   1074             (!speculative && pendingTransInfo));
   1075 
   1076  RefPtr<DnsAndConnectSocket> sock =
   1077      new DnsAndConnectSocket(mConnInfo, trans, caps, speculative, urgentStart);
   1078 
   1079  if (speculative) {
   1080    sock->SetAllow1918(allow1918);
   1081  }
   1082 
   1083  nsresult rv = sock->Init(this);
   1084  if (NS_FAILED(rv)) {
   1085    sock->Abandon();
   1086    return rv;
   1087  }
   1088 
   1089  InsertIntoDnsAndConnectSockets(sock);
   1090 
   1091  if (pendingTransInfo && sock->Claim()) {
   1092    pendingTransInfo->RememberDnsAndConnectSocket(sock);
   1093  }
   1094 
   1095  return NS_OK;
   1096 }
   1097 
   1098 bool ConnectionEntry::AllowToRetryDifferentIPFamilyForHttp3(nsresult aError) {
   1099  LOG(
   1100      ("ConnectionEntry::AllowToRetryDifferentIPFamilyForHttp3 %p "
   1101       "error=%" PRIx32,
   1102       this, static_cast<uint32_t>(aError)));
   1103  if (!mConnInfo->IsHttp3() && !mConnInfo->IsHttp3ProxyConnection()) {
   1104    MOZ_ASSERT(false, "Should not be called for non Http/3 connection");
   1105    return false;
   1106  }
   1107 
   1108  if (!StaticPrefs::network_http_http3_retry_different_ip_family()) {
   1109    return false;
   1110  }
   1111 
   1112  // Only allow to retry with these two errors.
   1113  if (aError != NS_ERROR_CONNECTION_REFUSED &&
   1114      aError != NS_ERROR_PROXY_CONNECTION_REFUSED) {
   1115    return false;
   1116  }
   1117 
   1118  // Already retried once.
   1119  if (mRetriedDifferentIPFamilyForHttp3) {
   1120    return false;
   1121  }
   1122 
   1123  return true;
   1124 }
   1125 
   1126 void ConnectionEntry::SetRetryDifferentIPFamilyForHttp3(uint16_t aIPFamily) {
   1127  LOG(("ConnectionEntry::SetRetryDifferentIPFamilyForHttp3 %p, af=%u", this,
   1128       aIPFamily));
   1129 
   1130  mPreferIPv4 = false;
   1131  mPreferIPv6 = false;
   1132 
   1133  if (aIPFamily == AF_INET) {
   1134    mPreferIPv6 = true;
   1135  }
   1136 
   1137  if (aIPFamily == AF_INET6) {
   1138    mPreferIPv4 = true;
   1139  }
   1140 
   1141  mRetriedDifferentIPFamilyForHttp3 = true;
   1142 
   1143  LOG(("  %p prefer ipv4=%d, ipv6=%d", this, (bool)mPreferIPv4,
   1144       (bool)mPreferIPv6));
   1145  MOZ_DIAGNOSTIC_ASSERT(mPreferIPv4 ^ mPreferIPv6);
   1146 }
   1147 
   1148 void ConnectionEntry::SetServerCertHashes(
   1149    nsTArray<RefPtr<nsIWebTransportHash>>&& aHashes) {
   1150  mServerCertHashes = std::move(aHashes);
   1151 }
   1152 
   1153 const nsTArray<RefPtr<nsIWebTransportHash>>&
   1154 ConnectionEntry::GetServerCertHashes() {
   1155  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1156  return mServerCertHashes;
   1157 }
   1158 
   1159 const nsCString& ConnectionEntry::OriginFrameHashKey() {
   1160  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1161  if (mOriginFrameHashKey.IsEmpty()) {
   1162    nsHttpConnectionInfo::BuildOriginFrameHashKey(
   1163        mOriginFrameHashKey, mConnInfo, mConnInfo->GetOrigin(),
   1164        mConnInfo->OriginPort());
   1165  }
   1166  return mOriginFrameHashKey;
   1167 }
   1168 
   1169 }  // namespace net
   1170 }  // namespace mozilla