[MG_Remote, MG_Test] (P7): the server binds its deferred stream link through the Transport factory

This commit is contained in:
2026-09-23 13:23:09 -04:00
parent 14e1c8b9b1
commit eaef83b32a
5 changed files with 82 additions and 20 deletions
+5 -14
View File
@@ -9,7 +9,6 @@
// P5 package s1: the server half of a session.
#include "../Transport/SocketTransport.h"
#include "../Transport/StreamLink.h"
#include "ServerSession.h"
#include <MG_Remote/FatalFunnel.h>
@@ -564,7 +563,7 @@ namespace MobileGL::MG_Remote::Server {
// its descriptor: Welcome has to announce the sizes of memory the connection it names
// will fill.
Uint8 dataNonce[Transport::kDataNonceBytes] = {};
Transport::StreamLink* pendingStream = nullptr;
Transport::ILink* pendingStream = nullptr;
if (stream) {
auto* socket = dynamic_cast<Transport::SocketTransport*>(&transport);
if (socket == nullptr || !socket->IsTcp() || !m_dataSource)
@@ -581,8 +580,8 @@ namespace MobileGL::MG_Remote::Server {
"stream data plane unavailable: the server could not mint a data nonce");
return created;
}
auto link = std::make_unique<Transport::StreamLink>();
created = link->AttachOwnedDeferred(m_sizes, Transport::TransportRoleTag::ServerConsumer);
std::unique_ptr<Transport::ILink> link;
created = Transport::CreateDeferredStreamLink(m_sizes, Transport::TransportRoleTag::ServerConsumer, link);
if (created == MOBILEGL_OK) {
pendingStream = link.get();
AttachDataLink(std::move(link));
@@ -801,7 +800,7 @@ namespace MobileGL::MG_Remote::Server {
// control peer going away; the deadline is refused on the control connection, where the
// client is listening.
MobileGLResult ServerSession::BindDataConnection(Transport::ITransport& control,
Transport::StreamLink& link, const Uint8* nonce) {
Transport::ILink& link, const Uint8* nonce) {
const auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(kHandshakeTimeoutMs);
Uint32 refused = 0;
for (;;) {
@@ -823,7 +822,7 @@ namespace MobileGL::MG_Remote::Server {
return offered;
}
if (Transport::ConstantTimeNonceMatch(nonce, presented)) {
const MobileGLResult bound = link.BindDataFd(fd);
const MobileGLResult bound = Transport::BindStreamLinkDataFd(link, fd);
#if !defined(_WIN32)
if (bound != MOBILEGL_OK) ::close(fd);
#endif
@@ -837,14 +836,6 @@ namespace MobileGL::MG_Remote::Server {
}
}
MobileGLResult ServerSession::AttachStreamLink(int fd, const Transport::SessionSegmentSizes& sizes) {
std::unique_ptr<Transport::ILink> link;
const auto attached = Transport::CreateStreamLink(fd, sizes, Transport::TransportRoleTag::ServerConsumer, link);
if (attached != MOBILEGL_OK) return attached;
AttachDataLink(std::move(link));
return MOBILEGL_OK;
}
void ServerSession::AttachDataLink(std::unique_ptr<Transport::ILink> link) {
m_link = std::move(link);
m_commands = &m_link->CommandsIn(); m_events = &m_link->EventsOut();
+1 -6
View File
@@ -58,10 +58,6 @@
#include "../Wire/PipeWireCodec.h"
#include "PipeApplier.h"
namespace MobileGL::MG_Remote::Transport {
class StreamLink;
}
namespace MobileGL::MG_Remote::Server {
class ServerSession {
@@ -70,7 +66,6 @@ namespace MobileGL::MG_Remote::Server {
ServerSession();
~ServerSession();
MobileGLResult AttachStreamLink(int dataFd, const Transport::SessionSegmentSizes& sizes);
void AttachDataLink(std::unique_ptr<Transport::ILink> link);
Transport::ILink* DataLink() const { return m_link.get(); }
void FlushDataProgress();
@@ -227,7 +222,7 @@ namespace MobileGL::MG_Remote::Server {
void LogMemory(const char* phase) const;
private:
MobileGLResult BindDataConnection(Transport::ITransport& control, Transport::StreamLink& link,
MobileGLResult BindDataConnection(Transport::ITransport& control, Transport::ILink& link,
const Uint8* nonce);
DataConnectionSource m_dataSource;
+10
View File
@@ -343,5 +343,15 @@ namespace MobileGL::MG_Remote::Transport {
std::unique_ptr<ILink> CreateSharedLink(TransportRoleTag role);
MobileGLResult CreateStreamLink(int fd, const SessionSegmentSizes& sizes,
TransportRoleTag role, std::unique_ptr<ILink>& out);
// PH-7 (4), ID-P7-3. The server's nonce-bound stream link, in the two steps
// StreamLink::AttachOwnedDeferred / BindDataFd describe: created with its owned memory and
// no descriptor (Welcome announces those sizes before the data connection exists), then
// bound to the one data connection that presented the session's nonce. Both halves live
// here so session code never names the concrete link (scripts/ci/link_seam_purity.py).
// Binding answers INVALID_ARGUMENT for a link these factories did not make as a stream,
// and leaves `fd` to the caller whenever it does not answer OK.
MobileGLResult CreateDeferredStreamLink(const SessionSegmentSizes& sizes, TransportRoleTag role,
std::unique_ptr<ILink>& out);
MobileGLResult BindStreamLinkDataFd(ILink& link, int fd);
} // namespace MobileGL::MG_Remote::Transport
@@ -399,6 +399,18 @@ namespace MobileGL::MG_Remote::Transport {
#endif
return result;
}
MobileGLResult CreateDeferredStreamLink(const SessionSegmentSizes& sizes, TransportRoleTag role,
std::unique_ptr<ILink>& out) {
auto link = std::make_unique<StreamLink>();
const auto result = link->AttachOwnedDeferred(sizes, role);
if (result == MOBILEGL_OK) out = std::move(link);
return result;
}
MobileGLResult BindStreamLinkDataFd(ILink& link, int fd) {
auto* stream = dynamic_cast<StreamLink*>(&link);
if (stream == nullptr) return MOBILEGL_ERR_INVALID_ARGUMENT;
return stream->BindDataFd(fd);
}
void StreamLink::InitializeEndpoints() {
m_impl->owned->SetRole(m_impl->role);
m_impl->owned->InitializeEndpoints();
+54
View File
@@ -268,6 +268,60 @@ namespace {
static_cast<unsigned long long>(sizes.StageBytes), elapsed, mibPerSecond);
}
// PH-7 (4), ID-P7-3, through the Transport factory pair ServerSession::Accept uses so that
// session code never names the concrete link (scripts/ci/link_seam_purity.py). In the
// production order: created without a descriptor, endpoints initialised, then bound once.
// A second bind, and a bind onto a link the factory did not make as a stream, are refused
// and leave the descriptor with the caller; the bound link then carries a record.
TEST(StreamLinkFactory, DeferredServerLinkBindsOnceAndThenCarriesARecord) {
SessionSegmentSizes sizes;
sizes.CmdRingBytes = 1024;
sizes.EventRingBytes = 1024;
sizes.StageBytes = 4096;
sizes.ReplyBytes = 4096;
std::unique_ptr<ILink> server;
ASSERT_EQ(CreateDeferredStreamLink(sizes, TransportRoleTag::ServerConsumer, server), MOBILEGL_OK);
ASSERT_NE(server, nullptr);
EXPECT_FALSE(server->Capabilities().PublishIsDelivery);
server->InitializeEndpoints();
int sockets[2];
ASSERT_EQ(::socketpair(AF_UNIX, SOCK_STREAM, 0, sockets), 0);
std::unique_ptr<ILink> client;
ASSERT_EQ(CreateStreamLink(sockets[0], sizes, TransportRoleTag::ClientProducer, client), MOBILEGL_OK);
client->InitializeEndpoints();
ASSERT_EQ(BindStreamLinkDataFd(*server, sockets[1]), MOBILEGL_OK);
int spare[2];
ASSERT_EQ(::socketpair(AF_UNIX, SOCK_STREAM, 0, spare), 0);
EXPECT_EQ(BindStreamLinkDataFd(*server, spare[0]), MOBILEGL_ERR_INVALID_ARGUMENT);
auto shared = CreateSharedLink(TransportRoleTag::ServerConsumer);
ASSERT_NE(shared, nullptr);
EXPECT_EQ(BindStreamLinkDataFd(*shared, spare[1]), MOBILEGL_ERR_INVALID_ARGUMENT);
EXPECT_EQ(::close(spare[0]), 0);
EXPECT_EQ(::close(spare[1]), 0);
SessionProducer producer;
producer.Attach(*client, 0);
SessionConsumer consumer;
consumer.Attach(*server, 0);
const std::uint64_t value = 0x5a5a5a5aull;
auto* record = client->CommandsOut().Reserve(1, 0, sizeof value);
ASSERT_NE(record, nullptr);
std::memcpy(record, &value, sizeof value);
producer.PublishAndNotify(1);
ASSERT_EQ(client->Flush(), MOBILEGL_OK);
ASSERT_EQ(consumer.WaitForWork(2000), SessionWait::Reached);
ASSERT_TRUE(consumer.ApplyOne([&](const RingRecordView& v) {
std::uint64_t seen = 0;
std::memcpy(&seen, v.payload, sizeof seen);
EXPECT_EQ(seen, value);
}));
consumer.RetireThrough(1);
ASSERT_EQ(server->FlushProgress(), MOBILEGL_OK);
EXPECT_EQ(producer.WaitForApplied(1, 2000), SessionWait::Reached);
}
void WriteFrame(int fd, unsigned kind, std::uint64_t a, const void* payload, std::uint32_t size) {
unsigned char h[28]{};
auto put = [&](unsigned at, std::uint64_t value, unsigned width) {