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
10 changes: 9 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@
"isDefault": true
},
"problemMatcher": ["$gcc"],
"detail": "Generated task by Debugger."
"detail": "Generated task by Debugger.",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": true
}
}
],
"version": "2.0.0"
Expand Down
8 changes: 4 additions & 4 deletions cpp/modules/l4/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ add_library(module_l4 STATIC)

target_sources(module_l4
PRIVATE
src/Channel.cpp
src/impl/ChannelUnixTcp.cpp
src/impl/ClientsRepoImpl.cpp
PUBLIC
include/Channel.h
include/ChannelUnixTcp.h
include/data.h
src/impl/ChannelUnixPipeImpl.cpp
src/impl/ChannelUnixFile.cpp
)

target_include_directories(module_l4 PUBLIC
Expand All @@ -19,6 +18,7 @@ target_include_directories(module_l4 PUBLIC

add_executable(module_l4_tests
test/test_ChannelUnixTcp.cpp
test/test_ChannelUnixPipeImpl.cpp
)
target_include_directories(module_l4_tests PRIVATE ./include/)
target_link_libraries(module_l4_tests PUBLIC Catch2::Catch2WithMain module_l4)
Expand Down
40 changes: 32 additions & 8 deletions cpp/modules/l4/include/Channel.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,48 @@
#pragma once
#include <memory>
#include <expected>

#include "data.h"
#include "SerializerL4.h"

namespace styxlib
{
enum class PacketHeaderSize : uint8_t
{
Size1Byte = 1,
Size2Bytes = 2,
Size4Bytes = 4
};

inline uint8_t to_uint8_t(const PacketHeaderSize &headerSize)
{
return static_cast<uint8_t>(headerSize);
}

/**
* Sets the packet size in the provided buffer according to the specified header size.
* @param headerSize The size of the packet header (1, 2, or 4 bytes).
* @param buffer The buffer where the packet size will be set.
* @param bufferSize The size of the buffer.
* @param packetSize The size of the packet to set.
* @return The number of bytes used for the header, or an ErrorCode if an error occurs.
*/
std::expected<uint8_t, ErrorCode> setPacketSize(
const PacketHeaderSize &headerSize,
uint8_t *buffer,
Size bufferSize,
Size packetSize);

class ChannelRx
{
protected:
DeserializerL4Ptr deserializer;

public:
ChannelRx(DeserializerL4Ptr deserializer) : deserializer(deserializer) {
if (deserializer == nullptr) {
ChannelRx(DeserializerL4Ptr deserializer) : deserializer(deserializer)
{
if (deserializer == nullptr)
{
throw std::invalid_argument("Deserializer cannot be null");
}
}
Expand All @@ -23,12 +53,6 @@ namespace styxlib
{
public:
virtual ~ChannelTx() = default;
virtual SizeResult sendBuffer(const StyxBuffer buffer, Size size) = 0;
};

class ChannelTxOneToMany {
public:
virtual ~ChannelTxOneToMany() = default;
virtual SizeResult sendBuffer(ClientId clientId, const StyxBuffer buffer, Size size) = 0;
};
}
5 changes: 4 additions & 1 deletion cpp/modules/l4/include/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace styxlib
CantCreateSocketPoll,
PacketTooLarge,
UnknownClient,
BufferTooSmall,
};

using StyxString = std::string;
Expand All @@ -26,7 +27,9 @@ namespace styxlib
using Fid = uint32_t;
using Tag = uint16_t;
using Type = uint16_t;
using ClientId = int;
using ClientId = uint16_t;
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

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

Changing ClientId from int to uint16_t is a breaking API change that limits the maximum number of clients from ~2 billion to 65,535. Consider whether this limitation is acceptable for your use case, and ensure this change is properly documented in release notes. If backward compatibility is needed, consider versioning the API.

Suggested change
using ClientId = uint16_t;
using ClientId = uint32_t;

Copilot uses AI. Check for mistakes.

constexpr ClientId InvalidClientId = 0;

class SerializerL4;
class DeserializerL4;
Expand Down
61 changes: 61 additions & 0 deletions cpp/modules/l4/include/impl/ChannelUnixFile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#pragma once

#include <vector>
#include <cstdint>

#include "data.h"
#include "Channel.h"

namespace styxlib
{
using FileDescriptor = int;
constexpr FileDescriptor InvalidFileDescriptor = -1;

struct ReadBuffer
{
std::vector<uint8_t> buffer;
Size currentSize{0};
bool isDirty{false};
};

class ChannelUnixFile : public ChannelTx, public ChannelRx
{
public:
struct Configuration
{
PacketHeaderSize packetSizeHeader{PacketHeaderSize::Size2Bytes};
uint16_t iounit{8192};
DeserializerL4Ptr deserializer{nullptr};
Configuration(
PacketHeaderSize packetSizeHeader,
uint16_t iounit,
DeserializerL4Ptr deserializer)
: packetSizeHeader(packetSizeHeader),
iounit(iounit),
deserializer(deserializer) {}
};
class FileDescriptorPair
{
public:
FileDescriptor readFd;
FileDescriptor writeFd;
FileDescriptorPair(FileDescriptor readFd, FileDescriptor writeFd)
: readFd(readFd), writeFd(writeFd) {}
};

protected:
FileDescriptorPair fds;
Configuration config;
ReadBuffer readBufferData;

virtual void closeDescriptors();
public:
ChannelUnixFile(const Configuration &config);
~ChannelUnixFile() override;
SizeResult sendBuffer(
ClientId clientId,
const StyxBuffer buffer,
Size size) override;
void readBufferBlocking();
};
} // namespace styxlib
38 changes: 38 additions & 0 deletions cpp/modules/l4/include/impl/ChannelUnixPipeImpl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <expected>
#include <future>
#include <atomic>
#include <memory>
#include <thread>

#include "ChannelUnixFile.h"

namespace styxlib
{
class ChannelUnixPipeImpl : public ChannelUnixFile
{
public:
using StartResult = std::expected<ChannelUnixFile::FileDescriptorPair, ErrorCode>;
private:
std::thread serverThread;
std::atomic<bool> running{false};
std::atomic<bool> stopRequested{false};
std::unique_ptr<std::promise<StartResult>> startPromise;
FileDescriptorPair rxFds;
FileDescriptorPair txFds;
bool isDescriptorOwned{false};
private:
void workThreadFunction();
protected:
void closeDescriptors() override;
public:
ChannelUnixPipeImpl(const ChannelUnixFile::Configuration &config);
std::future<StartResult> start();
std::future<ErrorCode> connect(const FileDescriptorPair& fds);
bool isStarted() const;
bool isConnected() const;
std::future<void> stop();
FileDescriptorPair getClientFileDescriptors() const;
};
} // namespace styxlib
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,11 @@
#include "Channel.h"
#include "ClientsRepo.h"
#include "impl/ProgressObservableMutexImpl.h"
#include "impl/ChannelUnixFile.h"

namespace styxlib
{
using Socket = int;

enum class PacketHeaderSize : uint8_t {
Size1Byte = 1,
Size2Bytes = 2,
Size4Bytes = 4
};

inline uint8_t to_uint8_t(const PacketHeaderSize &headerSize) {
return static_cast<uint8_t>(headerSize);
}

struct ReadBuffer {
std::vector<uint8_t> buffer;
Size currentSize{0};
bool isDirty{false};
};
using Socket = FileDescriptor;

class ChannelUnixTcpTx : public ChannelTx {
protected:
Expand All @@ -43,7 +28,7 @@ namespace styxlib
ChannelUnixTcpTx &operator=(ChannelUnixTcpTx &&) = delete;
ChannelUnixTcpTx &operator=(const ChannelUnixTcpTx &) = delete;
virtual ~ChannelUnixTcpTx() = default;
SizeResult sendBuffer(const StyxBuffer buffer, Size size) override;
SizeResult sendBuffer(ClientId clientId, const StyxBuffer buffer, Size size) override;
};

class ChannelUnixTcpClient : public ChannelUnixTcpTx, public ChannelRx
Expand Down Expand Up @@ -81,7 +66,7 @@ namespace styxlib
bool isConnected() const;
};

class ChannelUnixTcpServer : public ChannelRx, public ChannelTxOneToMany
class ChannelUnixTcpServer : public ChannelRx, public ChannelTx
{
public:
class Configuration
Expand Down
2 changes: 1 addition & 1 deletion cpp/modules/l4/include/impl/ClientsRepoImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace styxlib
class ClientsRepoImpl : public styxlib::ClientsRepo
{
private:
std::atomic_int nextId{0};
std::atomic<ClientId> nextId{InvalidClientId + 1};

public:
styxlib::ClientId getNextClientId() override;
Expand Down
39 changes: 39 additions & 0 deletions cpp/modules/l4/src/Channel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "Channel.h"

namespace styxlib
{
std::expected<uint8_t, ErrorCode> setPacketSize(const PacketHeaderSize &headerSize,
uint8_t* buffer,
Size bufferSize,
Size packetSize) {
if (bufferSize < 4) {
return std::unexpected(ErrorCode::BufferTooSmall);
}
switch (headerSize)
{
case PacketHeaderSize::Size1Byte:
if (packetSize > 0xFF) {
return std::unexpected(ErrorCode::PacketTooLarge);
}
buffer[0] = static_cast<uint8_t>(packetSize);
break;
case PacketHeaderSize::Size2Bytes:
if (packetSize > 0xFFFF) {
return std::unexpected(ErrorCode::PacketTooLarge);
}
buffer[1] = packetSize & 0xFF;
buffer[0] = (packetSize >> 8) & 0xFF;
break;
case PacketHeaderSize::Size4Bytes:
if (packetSize > 0xFFFFFFFF) {
return std::unexpected(ErrorCode::PacketTooLarge);
}
Comment on lines +28 to +30
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

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

The condition packetSize > 0xFFFFFFFF will always be false if Size is defined as a 32-bit unsigned integer (uint32_t), since a 32-bit value cannot exceed 0xFFFFFFFF. Either remove this check or change it to be meaningful (e.g., if Size can be 64-bit). If Size is larger than 32-bit, this check makes sense; otherwise, it's dead code.

Suggested change
if (packetSize > 0xFFFFFFFF) {
return std::unexpected(ErrorCode::PacketTooLarge);
}

Copilot uses AI. Check for mistakes.
buffer[3] = packetSize & 0xFF;
buffer[2] = (packetSize >> 8) & 0xFF;
buffer[1] = (packetSize >> 16) & 0xFF;
buffer[0] = (packetSize >> 24) & 0xFF;
break;
}
return static_cast<uint8_t>(headerSize);
}
} // namespace styxlib
Loading
Loading