Skip to content

Commit

Permalink
Max payload size should be limited by receive window
Browse files Browse the repository at this point in the history
  • Loading branch information
Gallardo994 committed Jan 16, 2024
1 parent 10cf3b9 commit 775ed56
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 7 deletions.
9 changes: 3 additions & 6 deletions imkcpp/include/imkcpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,9 @@ namespace imkcpp {

/// Calculates the maximum payload size that can be sent in a single send() call.
[[nodiscard]] auto estimate_max_payload_size() const noexcept -> size_t {
const size_t max_segments_count = std::min(
static_cast<size_t>(this->congestion_controller.get_send_window()),
static_cast<size_t>(std::numeric_limits<u8>::max())
);

return MAX_SEGMENT_SIZE * max_segments_count;
return MAX_SEGMENT_SIZE * std::min(
static_cast<size_t>(this->congestion_controller.get_receive_window()),
static_cast<size_t>(std::numeric_limits<u8>::max()));
}
};
}
4 changes: 3 additions & 1 deletion imkcpp/include/sender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ namespace imkcpp {
return tl::unexpected(error::too_many_fragments);
}

if (count > this->congestion_controller.get_send_window()) {
// We should limit sending by receive window because we can send more than send_wnd segments,
// but cannot receive more than rcv_wnd segments.
if (count > this->congestion_controller.get_receive_window()) {
return tl::unexpected(error::exceeds_window_size);
}

Expand Down
59 changes: 59 additions & 0 deletions tests/Send_Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,65 @@ TEST(Send_Tests, Send_LossyScenario) {
std::cout << "Send_LossyScenario finished in simulated " << update_idx << " calls" << std::endl;
}

TEST(Send_Tests, Send_SendWindowSmallerThanReceive) {
using namespace imkcpp;

constexpr size_t max_segment_size = MTU_TO_MSS<constants::IKCP_MTU_DEF>();
constexpr size_t size = max_segment_size * 250;

ImKcpp<constants::IKCP_MTU_DEF> kcp_output(0);
kcp_output.set_send_window(128);
kcp_output.set_receive_window(256);
kcp_output.set_interval(10);
kcp_output.update(0, [](std::span<const std::byte>) { });

ImKcpp<constants::IKCP_MTU_DEF> kcp_input(0);
kcp_input.set_send_window(128);
kcp_input.set_receive_window(256);
kcp_input.set_interval(10);
kcp_input.update(0, [](std::span<const std::byte>) { });

std::vector<std::byte> send_buffer(size);
for (u32 j = 0; j < size; ++j) {
send_buffer[j] = static_cast<std::byte>(j);
}

auto send_result = kcp_output.send(send_buffer);
ASSERT_TRUE(send_result.has_value()) << err_to_str(send_result.error());
ASSERT_EQ(send_result.value(), size);

auto output_to_input = [&](const std::span<const std::byte> data) {
kcp_input.input(data);
};

auto input_to_output = [&](const std::span<const std::byte> data) {
kcp_output.input(data);
};

size_t update_idx = 0;

while (kcp_output.get_state() == State::Alive && kcp_input.peek_size() != size) {
const auto now = static_cast<u32>(update_idx * 10);

kcp_output.update(now, output_to_input);
kcp_input.update(now, input_to_output);

++update_idx;
}

ASSERT_EQ(kcp_output.get_state(), State::Alive);

std::vector<std::byte> recv_buffer(size);
auto recv_result = kcp_input.recv(recv_buffer);
ASSERT_TRUE(recv_result.has_value()) << err_to_str(recv_result.error());

for (size_t j = 0; j < size; ++j) {
EXPECT_EQ(send_buffer.at(j), recv_buffer.at(j));
}

std::cout << "Send_LossyScenario finished in simulated " << update_idx << " calls" << std::endl;
}

TEST(Send_Tests, Send_FragmentedValidValues) {
using namespace imkcpp;

Expand Down

0 comments on commit 775ed56

Please sign in to comment.