Skip to content

Commit 05a2955

Browse files
committed
Add ChannelUnixUdpClient
1 parent ef1c9e6 commit 05a2955

7 files changed

Lines changed: 163 additions & 58 deletions

File tree

cpp/modules/l4/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ target_sources(module_l4
77
src/Channel.cpp
88
src/impl/ChannelUnixSocket.cpp
99
src/impl/ChannelUnixTcp.cpp
10+
src/impl/ChannelUnixUdp.cpp
1011
src/impl/ClientsRepoImpl.cpp
1112
src/impl/ChannelUnixPipeImpl.cpp
1213
src/impl/ChannelUnixFile.cpp

cpp/modules/l4/include/impl/ChannelUnixSocket.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22

33
#include <optional>
4+
#include <future>
5+
#include <string>
46

57
#include "Channel.h"
68
#include "impl/ChannelUnixFile.h"
@@ -43,4 +45,47 @@ namespace styxlib
4345
const StyxBuffer buffer,
4446
Size size) override;
4547
};
48+
49+
/**
50+
* Common base for socket-based client channels (TCP, UDP).
51+
* Handles the shared Configuration, disconnect(), isConnected(),
52+
* and the destructor. Subclasses only need to implement connect(),
53+
* which creates the protocol-specific socket and calls ::connect().
54+
*/
55+
class ChannelUnixSocketClient : public ChannelUnixSocketTx, public ChannelRx
56+
{
57+
public:
58+
struct Configuration
59+
{
60+
std::string address;
61+
uint16_t port;
62+
PacketHeaderSize packetSizeHeader{PacketHeaderSize::Size2Bytes};
63+
uint16_t iounit{8192};
64+
DeserializerL4Ptr deserializer{nullptr};
65+
Configuration(
66+
const std::string &address,
67+
uint16_t port,
68+
PacketHeaderSize packetSizeHeader,
69+
uint16_t iounit,
70+
DeserializerL4Ptr deserializer)
71+
: address(address),
72+
port(port),
73+
packetSizeHeader(packetSizeHeader),
74+
iounit(iounit),
75+
deserializer(deserializer) {}
76+
};
77+
78+
protected:
79+
const Configuration configuration;
80+
81+
public:
82+
explicit ChannelUnixSocketClient(const Configuration &config);
83+
ChannelUnixSocketClient(ChannelUnixSocketClient &&) = delete;
84+
ChannelUnixSocketClient &operator=(ChannelUnixSocketClient &&) = delete;
85+
~ChannelUnixSocketClient() override;
86+
87+
virtual std::future<ErrorCode> connect() = 0;
88+
std::future<void> disconnect();
89+
bool isConnected() const;
90+
};
4691
} // namespace styxlib

cpp/modules/l4/include/impl/ChannelUnixTcp.h

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,39 +31,17 @@ namespace styxlib
3131
virtual ~ChannelUnixTcpTx() = default;
3232
};
3333

34-
class ChannelUnixTcpClient : public ChannelUnixTcpTx, public ChannelRx
34+
class ChannelUnixTcpClient : public ChannelUnixSocketClient
3535
{
3636
public:
37-
struct Configuration
38-
{
39-
std::string address;
40-
uint16_t port;
41-
PacketHeaderSize packetSizeHeader{PacketHeaderSize::Size2Bytes};
42-
uint16_t iounit{8192};
43-
DeserializerL4Ptr deserializer{nullptr};
44-
Configuration(
45-
const std::string &address,
46-
uint16_t port,
47-
PacketHeaderSize packetSizeHeader,
48-
uint16_t iounit,
49-
DeserializerL4Ptr deserializer)
50-
: address(address),
51-
port(port),
52-
packetSizeHeader(packetSizeHeader),
53-
iounit(iounit),
54-
deserializer(deserializer) {}
55-
};
37+
// Re-export the base Configuration so existing call sites remain unchanged.
38+
using Configuration = ChannelUnixSocketClient::Configuration;
5639

57-
private:
58-
const Configuration configuration;
59-
public:
60-
ChannelUnixTcpClient(const Configuration &config);
40+
explicit ChannelUnixTcpClient(const Configuration &config);
6141
ChannelUnixTcpClient(ChannelUnixTcpClient &&) = delete;
6242
ChannelUnixTcpClient &operator=(ChannelUnixTcpClient &&) = delete;
63-
~ChannelUnixTcpClient() override;
64-
std::future<ErrorCode> connect();
65-
std::future<void> disconnect();
66-
bool isConnected() const;
43+
~ChannelUnixTcpClient() override = default;
44+
std::future<ErrorCode> connect() override;
6745
};
6846

6947
class ChannelUnixTcpServer : public ChannelRx, public ChannelTx

cpp/modules/l4/include/impl/ChannelUnixUdp.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <optional>
4+
#include <future>
45

56
#include "impl/ChannelUnixSocket.h"
67

@@ -25,4 +26,23 @@ namespace styxlib
2526
ChannelUnixUdpTx &operator=(const ChannelUnixUdpTx &) = delete;
2627
virtual ~ChannelUnixUdpTx() = default;
2728
};
29+
30+
/**
31+
* UDP client channel (Tx + Rx).
32+
*
33+
* connect() creates a SOCK_DGRAM socket and calls ::connect() to fix the
34+
* remote address, enabling plain ::send() / ::recv() calls without
35+
* specifying the peer on every call.
36+
*/
37+
class ChannelUnixUdpClient : public ChannelUnixSocketClient
38+
{
39+
public:
40+
using Configuration = ChannelUnixSocketClient::Configuration;
41+
42+
explicit ChannelUnixUdpClient(const Configuration &config);
43+
ChannelUnixUdpClient(ChannelUnixUdpClient &&) = delete;
44+
ChannelUnixUdpClient &operator=(ChannelUnixUdpClient &&) = delete;
45+
~ChannelUnixUdpClient() override = default;
46+
std::future<ErrorCode> connect() override;
47+
};
2848
} // namespace styxlib

cpp/modules/l4/src/impl/ChannelUnixSocket.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include "impl/ChannelUnixSocket.h"
22

33
#include <sys/socket.h>
4+
#include <unistd.h>
45
#include <cstring>
56
#include <vector>
7+
#include <future>
68

79
namespace styxlib
810
{
@@ -45,4 +47,38 @@ namespace styxlib
4547
Size bytesSent = static_cast<Size>(::send(socket.value(), combined.data(), combined.size(), 0));
4648
return bytesSent - headerSize.value();
4749
}
50+
51+
ChannelUnixSocketClient::ChannelUnixSocketClient(const Configuration &config)
52+
: ChannelUnixSocketTx(config.packetSizeHeader, std::nullopt),
53+
ChannelRx(),
54+
configuration(config)
55+
{
56+
if (setDeserializer(config.deserializer) != ErrorCode::Success) {
57+
throw std::invalid_argument("Deserializer cannot be null");
58+
}
59+
}
60+
61+
ChannelUnixSocketClient::~ChannelUnixSocketClient()
62+
{
63+
disconnect().get();
64+
}
65+
66+
std::future<void> ChannelUnixSocketClient::disconnect()
67+
{
68+
return std::async(
69+
std::launch::async,
70+
[this]()
71+
{
72+
if (socket.has_value())
73+
{
74+
::close(socket.value());
75+
socket = std::nullopt;
76+
}
77+
});
78+
}
79+
80+
bool ChannelUnixSocketClient::isConnected() const
81+
{
82+
return socket.has_value();
83+
}
4884
} // namespace styxlib

cpp/modules/l4/src/impl/ChannelUnixTcp.cpp

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,8 @@
1111
namespace styxlib
1212
{
1313
ChannelUnixTcpClient::ChannelUnixTcpClient(const Configuration &config)
14-
: ChannelRx(),
15-
ChannelUnixTcpTx(config.packetSizeHeader, std::nullopt),
16-
configuration(config)
14+
: ChannelUnixSocketClient(config)
1715
{
18-
if (setDeserializer(config.deserializer) != ErrorCode::Success) {
19-
throw std::invalid_argument("Deserializer cannot be null");
20-
}
21-
}
22-
23-
ChannelUnixTcpClient::~ChannelUnixTcpClient()
24-
{
25-
disconnect().get();
2616
}
2717

2818
std::future<ErrorCode> ChannelUnixTcpClient::connect()
@@ -61,25 +51,6 @@ namespace styxlib
6151
});
6252
}
6353

64-
std::future<void> ChannelUnixTcpClient::disconnect()
65-
{
66-
return std::async(
67-
std::launch::async,
68-
[this]()
69-
{
70-
if (socket.has_value())
71-
{
72-
::close(socket.value());
73-
socket = std::nullopt;
74-
}
75-
});
76-
}
77-
78-
bool ChannelUnixTcpClient::isConnected() const
79-
{
80-
return socket.has_value();
81-
}
82-
8354
ChannelUnixTcpServer::ChannelUnixTcpServer(const Configuration &config)
8455
: ChannelRx(), configuration(config)
8556
{
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "impl/ChannelUnixUdp.h"
2+
3+
#include <arpa/inet.h>
4+
#include <unistd.h>
5+
#include <future>
6+
7+
namespace styxlib
8+
{
9+
ChannelUnixUdpClient::ChannelUnixUdpClient(const Configuration &config)
10+
: ChannelUnixSocketClient(config)
11+
{
12+
}
13+
14+
std::future<ErrorCode> ChannelUnixUdpClient::connect()
15+
{
16+
return std::async(
17+
std::launch::async,
18+
[this]
19+
{
20+
if (isConnected())
21+
{
22+
return ErrorCode::AlreadyStarted;
23+
}
24+
25+
// Create a UDP socket.
26+
int sock = ::socket(AF_INET, SOCK_DGRAM, 0);
27+
if (sock < 0)
28+
{
29+
return ErrorCode::CantCreateSocket;
30+
}
31+
32+
// "Connect" the UDP socket to fix the remote address so that
33+
// subsequent ::send() calls work without specifying the peer.
34+
sockaddr_in serverAddress{};
35+
serverAddress.sin_family = AF_INET;
36+
serverAddress.sin_port = htons(configuration.port);
37+
inet_pton(AF_INET, configuration.address.c_str(), &serverAddress.sin_addr);
38+
39+
int result = ::connect(sock,
40+
reinterpret_cast<sockaddr *>(&serverAddress),
41+
sizeof(serverAddress));
42+
if (result == 0)
43+
{
44+
this->socket = sock;
45+
return ErrorCode::Success;
46+
}
47+
else
48+
{
49+
::close(sock);
50+
return ErrorCode::NotConnected;
51+
}
52+
});
53+
}
54+
} // namespace styxlib

0 commit comments

Comments
 (0)