Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ option(LAPS_INSTALL "Install the laps Components" ON)

option(LAPS_BUILD_TESTS "Build Tests laps" OFF)

option(LAPS_USE_BROTLI "Enable picotls Brotli TLS certificate compression (libbrotlidec)" OFF)
set(QUICR_USE_BROTLI "${LAPS_USE_BROTLI}" CACHE BOOL "Enable picotls Brotli TLS certificate compression" FORCE)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
Expand All @@ -15,7 +18,7 @@ set (CMAKE_POLICY_VERSION_MINIMUM 3.5)
### Define the project name and version
### Version will be added to version output of apps and library
project(laps
VERSION 0.18.16
VERSION 0.18.23
DESCRIPTION "Latency Aware Publish/Subscribe"
LANGUAGES CXX)

Expand Down
2 changes: 1 addition & 1 deletion dependencies/libquicr
Submodule libquicr updated 74 files
+19 −0 .github/workflows/format.yml
+85 −0 .github/workflows/macos.yml
+47 −0 .github/workflows/mbedtls.yml
+1 −0 .github/workflows/sanitizers.yml
+15 −36 .github/workflows/ubuntu.yml
+144 −0 .github/workflows/windows.yml
+0 −9 .gitmodules
+1 −1 .pre-commit-config.yaml
+5 −22 CMakeLists.txt
+4 −5 Makefile
+48 −1 README.md
+1 −1 REUSE.toml
+4 −0 benchmark/CMakeLists.txt
+1 −0 benchmark/data_storage.cpp
+1 −1 benchmark/extensions.cpp
+9 −9 benchmark/safe_time_queue.cpp
+5 −1 c-bridge/CMakeLists.txt
+20 −50 c-bridge/examples/chat.c
+36 −0 c-bridge/examples/example_sleep.h
+3 −3 c-bridge/examples/fetch.c
+16 −10 c-bridge/examples/file_transfer.c
+16 −16 c-bridge/examples/simple_publisher.c
+3 −3 c-bridge/examples/simple_subscriber.c
+0 −20 cmake/FindMbedTLS.cmake
+10 −1 cmake/Lint.cmake
+138 −0 cmake/QuicrDependencies.cmake
+0 −140 dependencies/CMakeLists.txt
+0 −1 dependencies/mbedtls
+0 −1 dependencies/picoquic
+0 −1 dependencies/timeq
+5 −1 examples/qclient/CMakeLists.txt
+6 −0 examples/qclient/helper_functions.h
+11 −1 examples/qclient/signal_handler.h
+1 −1 fuzz/ctrl_messages_fuzzer.cpp
+4 −0 include/quicr/config.h
+5 −1 include/quicr/containers/cache.h
+1 −1 include/quicr/containers/priority_queue.h
+4 −0 include/quicr/containers/stream_buffer.h
+1 −1 include/quicr/handlers/fetch_track_handler.h
+1 −1 include/quicr/handlers/joining_fetch_handler.h
+1 −1 include/quicr/handlers/publish_fetch_handler.h
+1 −1 include/quicr/handlers/publish_track_handler.h
+6 −0 include/quicr/handlers/subscribe_namespace_handler.h
+1 −1 include/quicr/handlers/subscribe_track_handler.h
+1 −1 include/quicr/handlers/track_handler.h
+0 −7 include/quicr/messages/ctrl_message_types.h
+0 −0 include/quicr/messages/message_serialisation.h
+3 −1 include/quicr/session.h
+20 −12 include/quicr/track_name.h
+13 −1 include/quicr/transport.h
+2 −2 include/quicr/utilities/bytes.h
+9 −1 include/quicr/utilities/defer.h
+11 −1 src/CMakeLists.txt
+4 −0 src/ctrl_message_types.cpp
+3 −3 src/message_serialisation.cpp
+4 −3 src/picoquic_connection.cpp
+21 −6 src/picoquic_connection.h
+9 −6 src/publish_track_handler.cpp
+38 −12 src/session.cpp
+14 −1 src/subscribe_namespace_handler.cpp
+1 −1 src/subscribe_track_handler.cpp
+178 −103 src/transport_picoquic.cpp
+34 −10 src/transport_picoquic.h
+4 −0 test/CMakeLists.txt
+17 −5 test/integration_test/CMakeLists.txt
+10 −0 test/integration_test/ctest_integration_test_properties.cmake
+111 −9 test/integration_test/integration_test.cpp
+9 −6 test/integration_test/test_server.cpp
+1 −2 test/moq_ctrl_messages.cpp
+1 −2 test/moq_data_messages.cpp
+19 −5 test/picoquic_connection.cpp
+1 −1 test/track_handlers.cpp
+10 −0 test/track_namespace.cpp
+9 −0 vcpkg.json
31 changes: 26 additions & 5 deletions src/client_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ namespace laps {
}

quicr::Reply<void, quicr::ErrorCode> ClientManager::NewGroupRequested(const quicr::FullTrackName& track_full_name,
std::uint64_t group_id)
std::uint64_t group_id)
{
auto th = quicr::TrackHash(track_full_name);
SPDLOG_INFO("New group requested received track_alais: {} group_id: {} ", th.track_fullname_hash, group_id);
Expand Down Expand Up @@ -921,8 +921,9 @@ namespace laps {
return {};
}

quicr::Reply<void, quicr::ErrorCode> ClientManager::PublishDoneReceived(const std::shared_ptr<quicr::Session>& session,
uint64_t request_id)
quicr::Reply<void, quicr::ErrorCode> ClientManager::PublishDoneReceived(
const std::shared_ptr<quicr::Session>& session,
uint64_t request_id)
{
const auto connection_handle = ConnectionHandle(session);
SPDLOG_LOGGER_INFO(
Expand Down Expand Up @@ -1001,6 +1002,25 @@ namespace laps {
}
}

const auto& pub_ns = s_it->second->GetFullTrackName().name_space;
const auto& pub_ta = s_it->second->GetTrackAlias().value_or(0);

// UnPublishTrack within publish namespace handler if matched
for (auto& [tn, conns] : state_.subscribes_namespaces) {
const auto prefix_match = tn.IsPrefixOf(pub_ns);

if (prefix_match == std::partial_ordering::less || prefix_match == std::partial_ordering::equivalent) {
for (auto& [_, pub_ns_h] : conns) {
if (!config_.allow_self && pub_ns_h->GetConnectionId() == connection_handle) {
// Initially do not mirror
continue;
}

pub_ns_h->UnpublishTrack(pub_ta);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep shared tracks until the last publisher finishes

When two connections publish the same full track name, they share pub_ta, and the code immediately above explicitly detects that another publisher remains via have_publishers. This unconditional erase nevertheless removes the shared track from every matching namespace handler when either publisher sends PUBLISH_DONE; later ranking updates report the alias as missing and cannot select or resume the remaining live publication. Only unpublish when have_publishers is false, or rebind the namespace entry to a remaining publisher.

Useful? React with 👍 / 👎.

}
}
}

state_.pub_subscribes_by_req_id.erase(s_it);
lock.unlock();

Expand All @@ -1011,8 +1031,9 @@ namespace laps {
return {};
}

quicr::Reply<void, quicr::ErrorCode> ClientManager::UnsubscribeReceived(const std::shared_ptr<quicr::Session>& session,
uint64_t request_id)
quicr::Reply<void, quicr::ErrorCode> ClientManager::UnsubscribeReceived(
const std::shared_ptr<quicr::Session>& session,
uint64_t request_id)
{
const auto connection_handle = ConnectionHandle(session);
SPDLOG_LOGGER_INFO(LOGGER, "Unsubscribe connection handle: {0} request_id: {1}", connection_handle, request_id);
Expand Down
11 changes: 4 additions & 7 deletions src/client_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ namespace laps {
quicr::Bytes data;

// libc++ now compares set keys with std::less<void>, which requires operator<.
bool operator<(const CacheObject& other) const noexcept
{
return headers.object_id < other.headers.object_id;
}
bool operator<(const CacheObject& other) const noexcept { return headers.object_id < other.headers.object_id; }
};
}

Expand Down Expand Up @@ -196,7 +193,7 @@ namespace laps {
std::weak_ptr<quicr::SubscribeNamespaceHandler> sub_ns_handler) override;

quicr::Reply<void, quicr::ErrorCode> PublishDoneReceived(const std::shared_ptr<quicr::Session>& session,
std::uint64_t request_id) override;
std::uint64_t request_id) override;

quicr::Reply<quicr::RequestResponse, quicr::RequestErrorCode> SubscribeReceived(
const std::shared_ptr<quicr::Session>& session,
Expand All @@ -205,10 +202,10 @@ namespace laps {
const quicr::SubscribeAttributes& subscribe_attributes) override;

quicr::Reply<void, quicr::ErrorCode> UnsubscribeReceived(const std::shared_ptr<quicr::Session>& session,
std::uint64_t request_id) override;
std::uint64_t request_id) override;

quicr::Reply<void, quicr::ErrorCode> NewGroupRequested(const quicr::FullTrackName& track_full_name,
std::uint64_t group_id) override;
std::uint64_t group_id) override;

quicr::Reply<quicr::RequestResponse, quicr::RequestErrorCode> TrackStatusReceived(
const std::shared_ptr<quicr::Session>& session,
Expand Down
2 changes: 1 addition & 1 deletion src/peering/info_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "peering/messages/subscribe_info.h"

#include <map>
#include <quicr/messages/messages.h>
#include <quicr/messages/message_serialisation.h>
#include <set>

namespace laps::peering {
Expand Down
2 changes: 1 addition & 1 deletion src/peering/messages/data_header.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "peering/common.h"
#include "subscribe_info.h"

#include <quicr/messages/messages.h>
#include <quicr/messages/message_serialisation.h>
#include <quicr/messages/uintvar.h>

namespace laps::peering {
Expand Down
3 changes: 1 addition & 2 deletions src/peering/peer_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1364,8 +1364,7 @@ namespace laps::peering {
if (const auto stream_it = entry.streams.find(stream_id); stream_it != entry.streams.end()) {
out_peer_sess->CloseStream(stream_it->second, flag);
entry.streams.erase(stream_it);
client_manager_->PeerStreamClosed(
key.first, stream_id, flag == quicr::StreamClosedFlag::kReset);
client_manager_->PeerStreamClosed(key.first, stream_id, flag == quicr::StreamClosedFlag::kReset);
}
}
}
Expand Down
25 changes: 11 additions & 14 deletions src/publish_namespace_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ namespace laps {
}
}

void
laps::PublishNamespaceHandler::UnpublishTrack(std::uint64_t track_alias)
{
published_tracks_.erase(track_alias);
}

void
laps::PublishNamespaceHandler::PublishTrack(std::shared_ptr<quicr::PublishTrackHandler> handler)
{
Expand Down Expand Up @@ -152,8 +158,6 @@ laps::PublishNamespaceHandler::UpdateTrackRanking(

if (published_tracks_.size() > active_tracks.size()) {

std::vector<std::uint64_t> remove_publish_tracks;

// Unpublish tracks that are too old
for (auto& [ta, track] : published_tracks_) {
if (active_tracks.contains(ta)) {
Expand Down Expand Up @@ -182,21 +186,14 @@ laps::PublishNamespaceHandler::UpdateTrackRanking(
}

if (cur_tick - track.last_updated_tick > delay_publish_done_ms_) {
SPDLOG_INFO("Unpublish track, not in top-n track alias: {} conn_id: {} ticks: {} < {}",
ta,
GetConnectionId(),
track.last_updated_tick,
cur_tick);
remove_publish_tracks.push_back(ta);
SPDLOG_TRACE("Unpublish track, not in top-n track alias: {} conn_id: {} ticks: {} < {}",
ta,
GetConnectionId(),
track.last_updated_tick,
cur_tick);
Comment on lines 188 to +193

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve cleanup for teardown paths without PUBLISH_DONE

This branch now only logs once a paused track exceeds the cleanup delay, while the sole new UnpublishTrack call is in PublishDoneReceived. If a publisher disconnects abruptly or ends a publish namespace, the existing teardown paths remove it from client state without invoking that callback, leaving its alias in published_tracks_; a later publisher of the same alias cannot replace the stale entry because PublishTrack uses emplace, so ranking can continue using an obsolete or expired handler. Wire those teardown paths to UnpublishTrack or retain the delayed erase as a fallback.

Useful? React with 👍 / 👎.

}
}
}

if (!remove_publish_tracks.empty()) {
for (const auto& ta: remove_publish_tracks) {
published_tracks_.erase(ta);
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/publish_namespace_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace laps {
std::shared_ptr<const std::vector<uint8_t>> data) override;

void PublishTrack(std::shared_ptr<quicr::PublishTrackHandler> handler) override;
void UnpublishTrack(std::uint64_t track_alias);

static auto Create(const quicr::TrackNamespace& prefix, std::weak_ptr<timeq::tick_service> tick_service)
{
Expand Down
3 changes: 3 additions & 0 deletions src/subscribe_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ namespace laps {
}

if (value.latest_value != recv_value || cur_tick - value.latest_tick_ms > kRefreshRankingIntervalMs) {
SPDLOG_TRACE(
"value changed: from {} to {} ta: {} conn: {}", value.latest_value, recv_value, ta, conn_id);

value.latest_value = recv_value;
value.latest_tick_ms = cur_tick;

Expand Down
2 changes: 1 addition & 1 deletion src/subscribe_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace laps {
class SubscribeTrackHandler : public quicr::SubscribeTrackHandler
{
public:
static constexpr uint64_t kRefreshRankingIntervalMs = 120;
static constexpr uint64_t kRefreshRankingIntervalMs = 500;

SubscribeTrackHandler(const quicr::FullTrackName& full_track_name,
std::uint8_t priority,
Expand Down
4 changes: 2 additions & 2 deletions src/track_ranking.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ namespace laps {
flat_track_list_.insert(flat_track_list_.end(), sort_tracks.begin(), sort_tracks.end());
}

NotifyNamespaceHandlers();

} else {
// Update latest_tick in flat_track_list_ in-place
for (auto& [alias, insert_seq_num, latest_tick, conn_id] : flat_track_list_) {
Expand All @@ -142,8 +144,6 @@ namespace laps {
}
}
}

NotifyNamespaceHandlers();
}

void RemoveTrack(const TrackAlias track_alias)
Expand Down
Loading