Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  connection_unittest.cc

  Sprache: C
 

/*
 *  Copyright 2025 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


#include "p2p/base/connection.h"

#include <cmath>
#include <cstdint>
#include <limits>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "api/environment/environment.h"
#include "api/environment/environment_factory.h"
#include "api/rtc_error.h"
#include "api/test/rtc_error_matchers.h"
#include "api/transport/stun.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "p2p/base/basic_packet_socket_factory.h"
#include "p2p/base/port.h"
#include "p2p/base/port_interface.h"
#include "p2p/base/transport_description.h"
#include "p2p/client/relay_port_factory_interface.h"
#include "p2p/test/test_port.h"
#include "rtc_base/buffer.h"
#include "rtc_base/network.h"
#include "rtc_base/network/received_packet.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/virtual_socket_server.h"
#include "test/create_test_environment.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/time_controller/simulated_time_controller.h"
#include "test/wait_until.h"

namespace webrtc {
namespace {

using ::testing::IsTrue;

constexpr int kDefaultTimeout = 3000;
const SocketAddress kLocalAddr1("192.168.1.2"0);
const SocketAddress kLocalAddr2("192.168.1.3"0);

constexpr int kTiebreaker1 = 11111;
constexpr int kTiebreaker2 = 22222;

class ConnectionTest : public ::testing::Test {
 public:
  ConnectionTest()
      : ss_(new VirtualSocketServer()),
        socket_factory_(ss_.get()) {
    lport_ = CreateTestPort(kLocalAddr1, "lfrag""lpass");
    rport_ = CreateTestPort(kLocalAddr2, "rfrag""rpass");
    lport_->SetIceRole(ICEROLE_CONTROLLING);
    lport_->SetIceTiebreaker(kTiebreaker1);
    rport_->SetIceRole(ICEROLE_CONTROLLED);
    rport_->SetIceTiebreaker(kTiebreaker2);

    lport_->PrepareAddress();
    rport_->PrepareAddress();
  }

  Connection* CreateConnection(IceRole role) {
    Connection* conn;
    if (role == ICEROLE_CONTROLLING) {
      conn = lport_->CreateConnection(rport_->Candidates()[0],
                                      Port::ORIGIN_MESSAGE);
    } else {
      conn = rport_->CreateConnection(lport_->Candidates()[0],
                                      Port::ORIGIN_MESSAGE);
    }
    conn->SubscribeStateChange(this, [this](Connection* connection) {
      OnConnectionStateChange(connection);
    });
    return conn;
  }

  void SendPingAndCaptureReply(Connection* lconn,
                               Connection* rconn,
                               int64_t ms,
                               BufferT<uint8_t>* reply) {
    TestPort* lport =
        lconn->PortForTest() == lport_.get() ? lport_.get() : rport_.get();
    TestPort* rport =
        rconn->PortForTest() == rport_.get() ? rport_.get() : lport_.get();
    lconn->Ping();
    ASSERT_TRUE(WaitUntil([&] { return lport->last_stun_msg(); },
                          {.timeout = TimeDelta::Millis(kDefaultTimeout),
                           .clock = &time_controller_}));
    ASSERT_GT(lport->last_stun_buf().size(), 0u);
    rconn->OnReadPacket(ReceivedIpPacket(lport->last_stun_buf(),
                                         SocketAddress(), std::nullopt));

    time_controller_.AdvanceTime(TimeDelta::Millis(ms));
    ASSERT_TRUE(WaitUntil([&] { return rport->last_stun_msg(); },
                          {.timeout = TimeDelta::Millis(kDefaultTimeout),
                           .clock = &time_controller_}));
    ASSERT_GT(rport->last_stun_buf().size(), 0u);
    reply->SetData(rport->last_stun_buf());
  }

  void SendPingAndReceiveResponse(Connection* lconn,
                                  Connection* rconn,
                                  int64_t ms) {
    BufferT<uint8_t> reply;
    SendPingAndCaptureReply(lconn, rconn, ms, &reply);

    lconn->OnReadPacket(ReceivedIpPacket(reply, SocketAddress(), std::nullopt));
  }

  void OnConnectionStateChange(Connection* connection) { num_state_changes_++; }

  Network* MakeNetwork(const SocketAddress& addr) {
    networks_.emplace_back("unittest""unittest", addr.ipaddr(), 32);
    networks_.back().AddIP(addr.ipaddr());
    return &networks_.back();
  }

  std::unique_ptr<TestPort> CreateTestPort(
      const SocketAddress& addr,
      absl::string_view username,
      absl::string_view password,
      const FieldTrialsView* field_trials = nullptr) {
    Port::PortParametersRef args = {
        .env = CreateEnvironment(field_trials),
        .network_thread = time_controller_.GetMainThread(),
        .socket_factory = &socket_factory_,
        .network = MakeNetwork(addr),
        .ice_username_fragment = username,
        .ice_password = password};
    auto port = std::make_unique<TestPort>(args, 00);
    port->SubscribeRoleConflict([this]() { OnRoleConflict(); });
    return port;
  }

  void OnRoleConflict() { role_conflict_ = true; }
  const Environment& env() const { return env_; }

  GlobalSimulatedTimeController time_controller_{Timestamp::Zero()};
  const Environment env_ = CreateTestEnvironment();
  int num_state_changes_ = 0;
  std::unique_ptr<VirtualSocketServer> ss_;
  BasicPacketSocketFactory socket_factory_;
  std::list<Network> networks_;
  bool role_conflict_ = false;

  std::unique_ptr<TestPort> lport_;
  std::unique_ptr<TestPort> rport_;
};

TEST_F(ConnectionTest, ConnectionForgetLearnedState) {
  Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
  Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);

  EXPECT_FALSE(lconn->writable());
  EXPECT_FALSE(lconn->receiving());
  EXPECT_TRUE(std::isnan(lconn->GetRttEstimate().GetAverage()));
  EXPECT_EQ(lconn->GetRttEstimate().GetVariance(),
            std::numeric_limits<double>::infinity());

  SendPingAndReceiveResponse(lconn, rconn, 10);

  EXPECT_TRUE(lconn->writable());
  EXPECT_TRUE(lconn->receiving());
  EXPECT_EQ(lconn->GetRttEstimate().GetAverage(), 10);
  EXPECT_EQ(lconn->GetRttEstimate().GetVariance(),
            std::numeric_limits<double>::infinity());

  SendPingAndReceiveResponse(lconn, rconn, 11);

  EXPECT_TRUE(lconn->writable());
  EXPECT_TRUE(lconn->receiving());
  EXPECT_NEAR(lconn->GetRttEstimate().GetAverage(), 100.5);
  EXPECT_LT(lconn->GetRttEstimate().GetVariance(),
            std::numeric_limits<double>::infinity());

  lconn->ForgetLearnedState();

  EXPECT_FALSE(lconn->writable());
  EXPECT_FALSE(lconn->receiving());
  EXPECT_TRUE(std::isnan(lconn->GetRttEstimate().GetAverage()));
  EXPECT_EQ(lconn->GetRttEstimate().GetVariance(),
            std::numeric_limits<double>::infinity());
}

TEST_F(ConnectionTest, ConnectionForgetLearnedStateDiscardsPendingPings) {
  Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
  Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);

  SendPingAndReceiveResponse(lconn, rconn, 10);

  EXPECT_TRUE(lconn->writable());
  EXPECT_TRUE(lconn->receiving());

  BufferT<uint8_t> reply;
  SendPingAndCaptureReply(lconn, rconn, 10, &reply);

  lconn->ForgetLearnedState();

  EXPECT_FALSE(lconn->writable());
  EXPECT_FALSE(lconn->receiving());

  lconn->OnReadPacket(ReceivedIpPacket(reply, SocketAddress(), std::nullopt));

  // That reply was discarded due to the ForgetLearnedState() while it was
  // outstanding.
  EXPECT_FALSE(lconn->writable());
  EXPECT_FALSE(lconn->receiving());

  // But sending a new ping and getting a reply works.
  SendPingAndReceiveResponse(lconn, rconn, 11);
  EXPECT_TRUE(lconn->writable());
  EXPECT_TRUE(lconn->receiving());
}

TEST_F(ConnectionTest, ConnectionForgetLearnedStateDoesNotTriggerStateChange) {
  Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
  Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);

  EXPECT_EQ(num_state_changes_, 0);
  SendPingAndReceiveResponse(lconn, rconn, 10);

  EXPECT_TRUE(lconn->writable());
  EXPECT_TRUE(lconn->receiving());
  EXPECT_EQ(num_state_changes_, 2);

  lconn->ForgetLearnedState();

  EXPECT_FALSE(lconn->writable());
  EXPECT_FALSE(lconn->receiving());
  EXPECT_EQ(num_state_changes_, 2);
}

// Test normal happy case.
// Sending a delta and getting a delta ack in response.
TEST_F(ConnectionTest, SendReceiveGoogDelta) {
  constexpr int64_t ms = 10;
  Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
  Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);

  std::unique_ptr<StunByteStringAttribute> delta =
      absl::WrapUnique(new StunByteStringAttribute(STUN_ATTR_GOOG_DELTA));
  delta->CopyBytes("DELTA");

  std::unique_ptr<StunAttribute> delta_ack =
      absl::WrapUnique(new StunUInt64Attribute(STUN_ATTR_GOOG_DELTA_ACK, 133));

  bool received_goog_delta = false;
  bool received_goog_delta_ack = false;
  lconn->SetStunDictConsumer(
      // DeltaReceived
      [](const StunByteStringAttribute* delta)
          -> std::unique_ptr<StunAttribute> { return nullptr; },
      // DeltaAckReceived
      [&](RTCErrorOr<const StunUInt64Attribute*> error_or_ack) {
        received_goog_delta_ack = true;
        EXPECT_TRUE(error_or_ack.ok());
        EXPECT_EQ(error_or_ack.value()->value(), 133ull);
      });

  rconn->SetStunDictConsumer(
      // DeltaReceived
      [&](const StunByteStringAttribute* delta)
          -> std::unique_ptr<StunAttribute> {
        received_goog_delta = true;
        EXPECT_EQ(delta->string_view(), "DELTA");
        return std::move(delta_ack);
      },
      // DeltaAckReceived
      [](RTCErrorOr<const StunUInt64Attribute*> error_or__ack) {});

  lconn->Ping(env().clock().CurrentTime(), std::move(delta));
  ASSERT_THAT(WaitUntil([&] { return lport_->last_stun_msg(); }, IsTrue(),
                        {.timeout = TimeDelta::Millis(kDefaultTimeout),
                         .clock = &time_controller_}),
              IsRtcOk());
  ASSERT_GT(lport_->last_stun_buf().size(), 0u);
  rconn->OnReadPacket(
      ReceivedIpPacket(lport_->last_stun_buf(), SocketAddress(), std::nullopt));
  EXPECT_TRUE(received_goog_delta);

  time_controller_.SkipForwardBy(TimeDelta::Millis(ms));
  ASSERT_TRUE(WaitUntil([&] { return rport_->last_stun_msg(); },
                        {.timeout = TimeDelta::Millis(kDefaultTimeout),
                         .clock = &time_controller_}));
  ASSERT_GT(rport_->last_stun_buf().size(), 0u);
  lconn->OnReadPacket(
      ReceivedIpPacket(rport_->last_stun_buf(), SocketAddress(), std::nullopt));
  EXPECT_TRUE(received_goog_delta_ack);
}

// Test that sending a goog delta and not getting
// a delta ack in reply gives an error callback.
TEST_F(ConnectionTest, SendGoogDeltaNoReply) {
  constexpr int64_t ms = 10;
  Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
  Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);

  std::unique_ptr<StunByteStringAttribute> delta =
      absl::WrapUnique(new StunByteStringAttribute(STUN_ATTR_GOOG_DELTA));
  delta->CopyBytes("DELTA");

  bool received_goog_delta_ack_error = false;
  lconn->SetStunDictConsumer(
      // DeltaReceived
      [](const StunByteStringAttribute* delta)
          -> std::unique_ptr<StunAttribute> { return nullptr; },
      // DeltaAckReceived
      [&](RTCErrorOr<const StunUInt64Attribute*> error_or_ack) {
        received_goog_delta_ack_error = true;
        EXPECT_FALSE(error_or_ack.ok());
      });

  lconn->Ping(env().clock().CurrentTime(), std::move(delta));
  ASSERT_THAT(WaitUntil([&] { return lport_->last_stun_msg(); }, IsTrue(),
                        {.timeout = TimeDelta::Millis(kDefaultTimeout),
                         .clock = &time_controller_}),
              IsRtcOk());
  ASSERT_GT(lport_->last_stun_buf().size(), 0u);
  rconn->OnReadPacket(
      ReceivedIpPacket(lport_->last_stun_buf(), SocketAddress(), std::nullopt));

  time_controller_.SkipForwardBy(TimeDelta::Millis(ms));
  ASSERT_THAT(WaitUntil([&] { return rport_->last_stun_msg(); }, IsTrue(),
                        {.timeout = TimeDelta::Millis(kDefaultTimeout),
                         .clock = &time_controller_}),
              IsRtcOk());
  ASSERT_GT(rport_->last_stun_buf().size(), 0u);
  lconn->OnReadPacket(
      ReceivedIpPacket(rport_->last_stun_buf(), SocketAddress(), std::nullopt));
  EXPECT_TRUE(received_goog_delta_ack_error);
}

// Test that if StunBinding is sufficiently full, aka DELTA is too big, it is
// not sent.
TEST_F(ConnectionTest, TooBigDeltaIsNotSent) {
  constexpr int64_t ms = 10;
  Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
  Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);

  std::string a_long_string(1200'a');
  std::unique_ptr<StunByteStringAttribute> delta =
      absl::WrapUnique(new StunByteStringAttribute(STUN_ATTR_GOOG_DELTA));
  delta->CopyBytes(a_long_string);

  std::unique_ptr<StunAttribute> delta_ack =
      absl::WrapUnique(new StunUInt64Attribute(STUN_ATTR_GOOG_DELTA_ACK, 133));

  bool received_goog_delta = false;
  bool received_goog_delta_ack = false;
  lconn->SetStunDictConsumer(
      // DeltaReceived
      [](const StunByteStringAttribute* delta)
          -> std::unique_ptr<StunAttribute> { return nullptr; },
      // DeltaAckReceived
      [&](RTCErrorOr<const StunUInt64Attribute*> error_or_ack) {
        received_goog_delta_ack = true;
        EXPECT_TRUE(error_or_ack.ok());
        EXPECT_EQ(error_or_ack.value()->value(), 133ull);
      });

  rconn->SetStunDictConsumer(
      // DeltaReceived
      [&](const StunByteStringAttribute* delta)
          -> std::unique_ptr<StunAttribute> {
        received_goog_delta = true;
        EXPECT_EQ(delta->string_view(), "DELTA");
        return std::move(delta_ack);
      },
      // DeltaAckReceived
      [](RTCErrorOr<const StunUInt64Attribute*> error_or__ack) {});

  lconn->Ping(env().clock().CurrentTime(), std::move(delta));
  ASSERT_THAT(WaitUntil([&] { return lport_->last_stun_msg(); }, IsTrue(),
                        {.timeout = TimeDelta::Millis(kDefaultTimeout),
                         .clock = &time_controller_}),
              IsRtcOk());
  ASSERT_GT(lport_->last_stun_buf().size(), 0u);
  rconn->OnReadPacket(
      ReceivedIpPacket(lport_->last_stun_buf(), SocketAddress(), std::nullopt));
  EXPECT_FALSE(received_goog_delta);

  time_controller_.SkipForwardBy(TimeDelta::Millis(ms));
  ASSERT_TRUE(WaitUntil([&] { return rport_->last_stun_msg(); },
                        {.timeout = TimeDelta::Millis(kDefaultTimeout),
                         .clock = &time_controller_}));
  ASSERT_GT(rport_->last_stun_buf().size(), 0u);
  lconn->OnReadPacket(
      ReceivedIpPacket(rport_->last_stun_buf(), SocketAddress(), std::nullopt));

  EXPECT_FALSE(received_goog_delta_ack);
}

}  // namespace
}  // namespace webrtc

Messung V0.5 in Prozent
C=87 H=100 G=93

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© 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=141584
#Domains=752002