Merge branch 'dev'
commit
102bf7e174
|
@ -59,7 +59,7 @@ Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
# binary files
|
# binary files
|
||||||
bin/
|
build/
|
||||||
# test files
|
# test files
|
||||||
assets/
|
assets/
|
||||||
# custom build tracking
|
# custom build tracking
|
||||||
|
|
29
SConstruct
29
SConstruct
|
@ -29,7 +29,20 @@ def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, ta
|
||||||
sources.append( self.StaticObject( target=target_name, source=path ) )
|
sources.append( self.StaticObject( target=target_name, source=path ) )
|
||||||
pass
|
pass
|
||||||
|
|
||||||
env=Environment(ENV=os.environ, CPPPATH=['#source/forstio','#source','#','#driver'],
|
def isAbsolutePath(key, dirname, env):
|
||||||
|
assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,)
|
||||||
|
|
||||||
|
env_vars = Variables(
|
||||||
|
args=ARGUMENTS
|
||||||
|
)
|
||||||
|
|
||||||
|
env_vars.Add('prefix',
|
||||||
|
help='Installation target location of build results and headers',
|
||||||
|
default='/usr/local/',
|
||||||
|
validator=isAbsolutePath
|
||||||
|
)
|
||||||
|
|
||||||
|
env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=['#source/forstio','#source','#','#driver'],
|
||||||
CXX='clang++',
|
CXX='clang++',
|
||||||
CPPDEFINES=['SAW_UNIX'],
|
CPPDEFINES=['SAW_UNIX'],
|
||||||
CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
|
CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
|
||||||
|
@ -56,11 +69,11 @@ env_library = env.Clone()
|
||||||
|
|
||||||
env.objects_shared = []
|
env.objects_shared = []
|
||||||
env_library.add_source_files(env.objects_shared, env.sources + env.driver_sources + env.tls_sources, shared=True)
|
env_library.add_source_files(env.objects_shared, env.sources + env.driver_sources + env.tls_sources, shared=True)
|
||||||
env.library_shared = env_library.SharedLibrary('#bin/forstio', [env.objects_shared])
|
env.library_shared = env_library.SharedLibrary('#build/forstio', [env.objects_shared])
|
||||||
|
|
||||||
env.objects_static = []
|
env.objects_static = []
|
||||||
env_library.add_source_files(env.objects_static, env.sources + env.driver_sources + env.tls_sources)
|
env_library.add_source_files(env.objects_static, env.sources + env.driver_sources + env.tls_sources)
|
||||||
env.library_static = env_library.StaticLibrary('#bin/forstio', [env.objects_static])
|
env.library_static = env_library.StaticLibrary('#build/forstio', [env.objects_static])
|
||||||
|
|
||||||
env.Alias('library', [env.library_shared, env.library_static])
|
env.Alias('library', [env.library_shared, env.library_static])
|
||||||
env.Alias('library_shared', env.library_shared)
|
env.Alias('library_shared', env.library_shared)
|
||||||
|
@ -87,9 +100,9 @@ env.Alias('format', env.format_actions)
|
||||||
|
|
||||||
env.Alias('all', ['format', 'library_shared', 'library_static', 'test'])
|
env.Alias('all', ['format', 'library_shared', 'library_static', 'test'])
|
||||||
|
|
||||||
env.Install('/usr/local/lib/', [env.library_shared, env.library_static])
|
env.Install('$prefix/lib/', [env.library_shared, env.library_static])
|
||||||
env.Install('/usr/local/include/forstio/', [env.headers])
|
env.Install('$prefix/include/forstio/', [env.headers])
|
||||||
env.Install('/usr/local/include/forstio/tls/', [env.tls_headers])
|
env.Install('$prefix/include/forstio/tls/', [env.tls_headers])
|
||||||
|
|
||||||
env.Install('/usr/local/include/forstio/test/', [env.test_headers])
|
env.Install('$prefix/include/forstio/test/', [env.test_headers])
|
||||||
env.Alias('install', '/usr/local/')
|
env.Alias('install', '$prefix')
|
||||||
|
|
|
@ -124,31 +124,145 @@ void UnixServer::notify(uint32_t mask) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnixDatagram::UnixDatagram(UnixEventPort &event_port, int file_descriptor,
|
||||||
|
int fd_flags)
|
||||||
|
: IFdOwner{event_port, file_descriptor, fd_flags, EPOLLIN | EPOLLOUT} {}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
ssize_t unixReadMsg(int fd, void *buffer, size_t length) {
|
||||||
|
struct ::sockaddr_storage their_addr;
|
||||||
|
socklen_t addr_len = sizeof(sockaddr_storage);
|
||||||
|
return ::recvfrom(fd, buffer, length, 0,
|
||||||
|
reinterpret_cast<struct ::sockaddr *>(&their_addr),
|
||||||
|
&addr_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t unixWriteMsg(int fd, const void *buffer, size_t length,
|
||||||
|
::sockaddr *dest_addr, socklen_t dest_addr_len) {
|
||||||
|
|
||||||
|
return ::sendto(fd, buffer, length, 0, dest_addr, dest_addr_len);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ErrorOr<size_t> UnixDatagram::read(void *buffer, size_t length) {
|
||||||
|
ssize_t read_bytes = unixReadMsg(fd(), buffer, length);
|
||||||
|
if (read_bytes > 0) {
|
||||||
|
return static_cast<size_t>(read_bytes);
|
||||||
|
}
|
||||||
|
return recoverableError("Currently busy");
|
||||||
|
}
|
||||||
|
|
||||||
|
Conveyor<void> UnixDatagram::readReady() {
|
||||||
|
auto caf = newConveyorAndFeeder<void>();
|
||||||
|
read_ready = std::move(caf.feeder);
|
||||||
|
return std::move(caf.conveyor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<size_t> UnixDatagram::write(const void *buffer, size_t length,
|
||||||
|
NetworkAddress &dest) {
|
||||||
|
UnixNetworkAddress &unix_dest = static_cast<UnixNetworkAddress &>(dest);
|
||||||
|
SocketAddress &sock_addr = unix_dest.unixAddress();
|
||||||
|
socklen_t sock_addr_length = sock_addr.getRawLength();
|
||||||
|
ssize_t write_bytes = unixWriteMsg(fd(), buffer, length, sock_addr.getRaw(),
|
||||||
|
sock_addr_length);
|
||||||
|
if (write_bytes > 0) {
|
||||||
|
return static_cast<size_t>(write_bytes);
|
||||||
|
}
|
||||||
|
return recoverableError("Currently busy");
|
||||||
|
}
|
||||||
|
|
||||||
|
Conveyor<void> UnixDatagram::writeReady() {
|
||||||
|
auto caf = newConveyorAndFeeder<void>();
|
||||||
|
write_ready = std::move(caf.feeder);
|
||||||
|
return std::move(caf.conveyor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnixDatagram::notify(uint32_t mask) {
|
||||||
|
if (mask & EPOLLOUT) {
|
||||||
|
if (write_ready) {
|
||||||
|
write_ready->feed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & EPOLLIN) {
|
||||||
|
if (read_ready) {
|
||||||
|
read_ready->feed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool beginsWith(const std::string_view &viewed,
|
bool beginsWith(const std::string_view &viewed,
|
||||||
const std::string_view &begins) {
|
const std::string_view &begins) {
|
||||||
return viewed.size() >= begins.size() &&
|
return viewed.size() >= begins.size() &&
|
||||||
viewed.compare(0, begins.size(), begins) == 0;
|
viewed.compare(0, begins.size(), begins) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::variant<UnixNetworkAddress, UnixNetworkAddress *>
|
||||||
|
translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
|
||||||
|
auto addr_variant = addr.representation();
|
||||||
|
std::variant<UnixNetworkAddress, UnixNetworkAddress *> os_addr = std::visit(
|
||||||
|
[](auto &arg)
|
||||||
|
-> std::variant<UnixNetworkAddress, UnixNetworkAddress *> {
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, OsNetworkAddress *>) {
|
||||||
|
return static_cast<UnixNetworkAddress *>(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sock_addrs = SocketAddress::parse(
|
||||||
|
std::string_view{arg->address()}, arg->port());
|
||||||
|
|
||||||
|
return UnixNetworkAddress{arg->address(), arg->port(),
|
||||||
|
std::move(sock_addrs)};
|
||||||
|
},
|
||||||
|
addr_variant);
|
||||||
|
return os_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnixNetworkAddress &translateToUnixAddressRef(
|
||||||
|
std::variant<UnixNetworkAddress, UnixNetworkAddress *> &addr_variant) {
|
||||||
|
return std::visit(
|
||||||
|
[](auto &arg) -> UnixNetworkAddress & {
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, UnixNetworkAddress>) {
|
||||||
|
return arg;
|
||||||
|
} else if constexpr (std::is_same_v<T, UnixNetworkAddress *>) {
|
||||||
|
return *arg;
|
||||||
|
} else {
|
||||||
|
static_assert(true, "Cases exhausted");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addr_variant);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Own<Server> UnixNetworkAddress::listen() {
|
Own<Server> UnixNetwork::listen(NetworkAddress &addr) {
|
||||||
assert(addresses.size() > 0);
|
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
|
||||||
if (addresses.size() == 0) {
|
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
|
||||||
|
|
||||||
|
assert(address.unixAddressSize() > 0);
|
||||||
|
if (address.unixAddressSize() == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = addresses.front().socket(SOCK_STREAM);
|
int fd = address.unixAddress(0).socket(SOCK_STREAM);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int val = 1;
|
int val = 1;
|
||||||
|
int rc = ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||||
|
if (rc < 0) {
|
||||||
|
::close(fd);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
bool failed = address.unixAddress(0).bind(fd);
|
||||||
|
|
||||||
bool failed = addresses.front().bind(fd);
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
|
::close(fd);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,13 +271,16 @@ Own<Server> UnixNetworkAddress::listen() {
|
||||||
return heap<UnixServer>(event_port, fd, 0);
|
return heap<UnixServer>(event_port, fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Conveyor<Own<IoStream>> UnixNetworkAddress::connect() {
|
Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
|
||||||
assert(addresses.size() > 0);
|
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
|
||||||
if (addresses.size() == 0) {
|
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
|
||||||
|
|
||||||
|
assert(address.unixAddressSize() > 0);
|
||||||
|
if (address.unixAddressSize() == 0) {
|
||||||
return Conveyor<Own<IoStream>>{criticalError("No address found")};
|
return Conveyor<Own<IoStream>>{criticalError("No address found")};
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = addresses.front().socket(SOCK_STREAM);
|
int fd = address.unixAddress(0).socket(SOCK_STREAM);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return Conveyor<Own<IoStream>>{criticalError("Couldn't open socket")};
|
return Conveyor<Own<IoStream>>{criticalError("Couldn't open socket")};
|
||||||
}
|
}
|
||||||
|
@ -172,8 +289,10 @@ Conveyor<Own<IoStream>> UnixNetworkAddress::connect() {
|
||||||
heap<UnixIoStream>(event_port, fd, 0, EPOLLIN | EPOLLOUT);
|
heap<UnixIoStream>(event_port, fd, 0, EPOLLIN | EPOLLOUT);
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
for (auto iter = addresses.begin(); iter != addresses.end(); ++iter) {
|
for (size_t i = 0; i < address.unixAddressSize(); ++i) {
|
||||||
int status = ::connect(fd, iter->getRaw(), iter->getRawLength());
|
SocketAddress &addr_iter = address.unixAddress(i);
|
||||||
|
int status =
|
||||||
|
::connect(fd, addr_iter.getRaw(), addr_iter.getRawLength());
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
int error = errno;
|
int error = errno;
|
||||||
/*
|
/*
|
||||||
|
@ -212,22 +331,43 @@ Conveyor<Own<IoStream>> UnixNetworkAddress::connect() {
|
||||||
return Conveyor<Own<IoStream>>{std::move(io_stream)};
|
return Conveyor<Own<IoStream>>{std::move(io_stream)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UnixNetworkAddress::toString() const {
|
Own<Datagram> UnixNetwork::datagram(NetworkAddress &addr) {
|
||||||
try {
|
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
|
||||||
std::ostringstream oss;
|
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
|
||||||
oss << "Address: " << path;
|
|
||||||
if (port_hint > 0) {
|
SAW_ASSERT(address.unixAddressSize() > 0) { return nullptr; }
|
||||||
oss << "\nPort: " << port_hint;
|
|
||||||
}
|
int fd = address.unixAddress(0).socket(SOCK_DGRAM);
|
||||||
return oss.str();
|
|
||||||
} catch (std::bad_alloc &) {
|
int optval = 1;
|
||||||
return {};
|
int rc =
|
||||||
|
::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||||
|
if (rc < 0) {
|
||||||
|
::close(fd);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool failed = address.unixAddress(0).bind(fd);
|
||||||
|
if (failed) {
|
||||||
|
::close(fd);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/// @todo
|
||||||
|
return heap<UnixDatagram>(event_port, fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &UnixNetworkAddress::address() const { return path; }
|
const std::string &UnixNetworkAddress::address() const { return path; }
|
||||||
|
|
||||||
uint16_t UnixNetworkAddress::port() const { return port_hint; }
|
uint16_t UnixNetworkAddress::port() const { return port_hint; }
|
||||||
|
|
||||||
|
SocketAddress &UnixNetworkAddress::unixAddress(size_t i) {
|
||||||
|
assert(i < addresses.size());
|
||||||
|
/// @todo change from list to vector?
|
||||||
|
return addresses.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UnixNetworkAddress::unixAddressSize() const { return addresses.size(); }
|
||||||
|
|
||||||
UnixNetwork::UnixNetwork(UnixEventPort &event) : event_port{event} {}
|
UnixNetwork::UnixNetwork(UnixEventPort &event) : event_port{event} {}
|
||||||
|
|
||||||
Conveyor<Own<NetworkAddress>> UnixNetwork::parseAddress(const std::string &path,
|
Conveyor<Own<NetworkAddress>> UnixNetwork::parseAddress(const std::string &path,
|
||||||
|
@ -240,29 +380,11 @@ Conveyor<Own<NetworkAddress>> UnixNetwork::parseAddress(const std::string &path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<SocketAddress> addresses =
|
std::vector<SocketAddress> addresses =
|
||||||
SocketAddress::parse(addr_view, port_hint);
|
SocketAddress::parse(addr_view, port_hint);
|
||||||
|
|
||||||
return Conveyor<Own<NetworkAddress>>{heap<UnixNetworkAddress>(
|
return Conveyor<Own<NetworkAddress>>{
|
||||||
event_port, path, port_hint, std::move(addresses))};
|
heap<UnixNetworkAddress>(path, port_hint, std::move(addresses))};
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<SocketPair> UnixNetwork::socketPair() {
|
|
||||||
int sv[2];
|
|
||||||
|
|
||||||
int rc = ::socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
|
||||||
0, sv);
|
|
||||||
if (rc < 0) {
|
|
||||||
return criticalError("Failed to create socket pair");
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketPair socket_pair;
|
|
||||||
socket_pair.stream[0] =
|
|
||||||
heap<UnixIoStream>(event_port, sv[0], 0, EPOLLIN | EPOLLOUT);
|
|
||||||
socket_pair.stream[1] =
|
|
||||||
heap<UnixIoStream>(event_port, sv[1], 0, EPOLLIN | EPOLLOUT);
|
|
||||||
|
|
||||||
return socket_pair;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnixIoProvider::UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port)
|
UnixIoProvider::UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port)
|
||||||
|
|
|
@ -312,6 +312,27 @@ public:
|
||||||
void notify(uint32_t mask) override;
|
void notify(uint32_t mask) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UnixDatagram final : public Datagram, public IFdOwner {
|
||||||
|
private:
|
||||||
|
Own<ConveyorFeeder<void>> read_ready = nullptr;
|
||||||
|
Own<ConveyorFeeder<void>> write_ready = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UnixDatagram(UnixEventPort &event_port, int file_descriptor, int fd_flags);
|
||||||
|
|
||||||
|
ErrorOr<size_t> read(void *buffer, size_t length) override;
|
||||||
|
Conveyor<void> readReady() override;
|
||||||
|
|
||||||
|
ErrorOr<size_t> write(const void *buffer, size_t length,
|
||||||
|
NetworkAddress &dest) override;
|
||||||
|
Conveyor<void> writeReady() override;
|
||||||
|
|
||||||
|
void notify(uint32_t mask) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class which provides potential addresses to NetworkAddress
|
||||||
|
*/
|
||||||
class SocketAddress {
|
class SocketAddress {
|
||||||
private:
|
private:
|
||||||
union {
|
union {
|
||||||
|
@ -335,8 +356,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket(int type) const {
|
int socket(int type) const {
|
||||||
bool is_stream = type & SOCK_STREAM;
|
|
||||||
|
|
||||||
type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
|
type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
|
||||||
|
|
||||||
int result = ::socket(address.generic.sa_family, type, 0);
|
int result = ::socket(address.generic.sa_family, type, 0);
|
||||||
|
@ -352,13 +371,17 @@ public:
|
||||||
return error < 0;
|
return error < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ::sockaddr *getRaw() {
|
||||||
|
return &address.generic;
|
||||||
|
}
|
||||||
|
|
||||||
const struct ::sockaddr *getRaw() const { return &address.generic; }
|
const struct ::sockaddr *getRaw() const { return &address.generic; }
|
||||||
|
|
||||||
socklen_t getRawLength() const { return address_length; }
|
socklen_t getRawLength() const { return address_length; }
|
||||||
|
|
||||||
static std::list<SocketAddress> parse(std::string_view str,
|
static std::vector<SocketAddress> parse(std::string_view str,
|
||||||
uint16_t port_hint) {
|
uint16_t port_hint) {
|
||||||
std::list<SocketAddress> results;
|
std::vector<SocketAddress> results;
|
||||||
|
|
||||||
struct ::addrinfo *head;
|
struct ::addrinfo *head;
|
||||||
struct ::addrinfo hints;
|
struct ::addrinfo hints;
|
||||||
|
@ -387,27 +410,24 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnixNetworkAddress final : public NetworkAddress {
|
class UnixNetworkAddress final : public OsNetworkAddress {
|
||||||
private:
|
private:
|
||||||
UnixEventPort &event_port;
|
|
||||||
const std::string path;
|
const std::string path;
|
||||||
uint16_t port_hint;
|
uint16_t port_hint;
|
||||||
std::list<SocketAddress> addresses;
|
std::vector<SocketAddress> addresses;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UnixNetworkAddress(UnixEventPort &event_port, const std::string &path,
|
UnixNetworkAddress(const std::string &path, uint16_t port_hint,
|
||||||
uint16_t port_hint, std::list<SocketAddress> &&addr)
|
std::vector<SocketAddress> &&addr)
|
||||||
: event_port{event_port}, path{path}, port_hint{port_hint},
|
: path{path}, port_hint{port_hint}, addresses{std::move(addr)} {}
|
||||||
addresses{std::move(addr)} {}
|
|
||||||
|
|
||||||
Own<Server> listen() override;
|
|
||||||
Conveyor<Own<IoStream>> connect() override;
|
|
||||||
|
|
||||||
std::string toString() const override;
|
|
||||||
|
|
||||||
const std::string &address() const override;
|
const std::string &address() const override;
|
||||||
|
|
||||||
uint16_t port() const override;
|
uint16_t port() const override;
|
||||||
|
|
||||||
|
// Custom address info
|
||||||
|
SocketAddress &unixAddress(size_t i = 0);
|
||||||
|
size_t unixAddressSize() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnixNetwork final : public Network {
|
class UnixNetwork final : public Network {
|
||||||
|
@ -420,7 +440,11 @@ public:
|
||||||
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &address,
|
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &address,
|
||||||
uint16_t port_hint = 0) override;
|
uint16_t port_hint = 0) override;
|
||||||
|
|
||||||
ErrorOr<SocketPair> socketPair() override;
|
Own<Server> listen(NetworkAddress &addr) override;
|
||||||
|
|
||||||
|
Conveyor<Own<IoStream>> connect(NetworkAddress &addr) override;
|
||||||
|
|
||||||
|
Own<Datagram> datagram(NetworkAddress &addr) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnixIoProvider final : public IoProvider {
|
class UnixIoProvider final : public IoProvider {
|
||||||
|
|
|
@ -91,11 +91,11 @@ public:
|
||||||
virtual ~ErrorOrValue() = default;
|
virtual ~ErrorOrValue() = default;
|
||||||
|
|
||||||
template <typename T> ErrorOr<UnfixVoid<T>> &as() {
|
template <typename T> ErrorOr<UnfixVoid<T>> &as() {
|
||||||
return dynamic_cast<ErrorOr<UnfixVoid<T>> &>(*this);
|
return static_cast<ErrorOr<UnfixVoid<T>> &>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> const ErrorOr<UnfixVoid<T>> &as() const {
|
template <typename T> const ErrorOr<UnfixVoid<T>> &as() const {
|
||||||
return dynamic_cast<const ErrorOr<UnfixVoid<T>> &>(*this);
|
return static_cast<const ErrorOr<UnfixVoid<T>> &>(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -58,4 +58,14 @@ Conveyor<size_t> AsyncIoStream::writeDone() {
|
||||||
write_stepper.write_done = std::move(caf.feeder);
|
write_stepper.write_done = std::move(caf.feeder);
|
||||||
return std::move(caf.conveyor);
|
return std::move(caf.conveyor);
|
||||||
}
|
}
|
||||||
} // namespace saw
|
|
||||||
|
StringNetworkAddress::StringNetworkAddress(const std::string &address,
|
||||||
|
uint16_t port)
|
||||||
|
: address_value{address}, port_value{port} {}
|
||||||
|
|
||||||
|
const std::string &StringNetworkAddress::address() const {
|
||||||
|
return address_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t StringNetworkAddress::port() const { return port_value; }
|
||||||
|
} // namespace saw
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "io_helpers.h"
|
#include "io_helpers.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace saw {
|
namespace saw {
|
||||||
/*
|
/*
|
||||||
|
@ -74,7 +75,7 @@ private:
|
||||||
public:
|
public:
|
||||||
AsyncIoStream(Own<IoStream> str);
|
AsyncIoStream(Own<IoStream> str);
|
||||||
|
|
||||||
void read(void *buffer, size_t min_length, size_t max_length) override;
|
void read(void *buffer, size_t length, size_t max_length) override;
|
||||||
|
|
||||||
Conveyor<size_t> readDone() override;
|
Conveyor<size_t> readDone() override;
|
||||||
|
|
||||||
|
@ -92,38 +93,85 @@ public:
|
||||||
virtual Conveyor<Own<IoStream>> accept() = 0;
|
virtual Conveyor<Own<IoStream>> accept() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SocketPair {
|
class NetworkAddress;
|
||||||
|
/**
|
||||||
|
* Datagram class. Bound to a local address it is able to receive inbound
|
||||||
|
* datagram messages and send them as well as long as an address is provided as
|
||||||
|
* well
|
||||||
|
*/
|
||||||
|
class Datagram {
|
||||||
public:
|
public:
|
||||||
std::array<Own<IoStream>, 2> stream;
|
virtual ~Datagram() = default;
|
||||||
|
|
||||||
|
virtual ErrorOr<size_t> read(void *buffer, size_t length) = 0;
|
||||||
|
virtual Conveyor<void> readReady() = 0;
|
||||||
|
|
||||||
|
virtual ErrorOr<size_t> write(const void *buffer, size_t length,
|
||||||
|
NetworkAddress &dest) = 0;
|
||||||
|
virtual Conveyor<void> writeReady() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OsNetworkAddress;
|
||||||
|
class StringNetworkAddress;
|
||||||
|
|
||||||
class NetworkAddress {
|
class NetworkAddress {
|
||||||
public:
|
public:
|
||||||
|
using ChildVariant =
|
||||||
|
std::variant<OsNetworkAddress *, StringNetworkAddress *>;
|
||||||
|
|
||||||
virtual ~NetworkAddress() = default;
|
virtual ~NetworkAddress() = default;
|
||||||
|
|
||||||
/*
|
virtual NetworkAddress::ChildVariant representation() = 0;
|
||||||
* Listen on this address
|
|
||||||
*/
|
|
||||||
virtual Own<Server> listen() = 0;
|
|
||||||
virtual Conveyor<Own<IoStream>> connect() = 0;
|
|
||||||
|
|
||||||
virtual std::string toString() const = 0;
|
|
||||||
|
|
||||||
virtual const std::string &address() const = 0;
|
virtual const std::string &address() const = 0;
|
||||||
virtual uint16_t port() const = 0;
|
virtual uint16_t port() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OsNetworkAddress : public NetworkAddress {
|
||||||
|
public:
|
||||||
|
virtual ~OsNetworkAddress() = default;
|
||||||
|
|
||||||
|
NetworkAddress::ChildVariant representation() override { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class StringNetworkAddress final : public NetworkAddress {
|
||||||
|
private:
|
||||||
|
std::string address_value;
|
||||||
|
uint16_t port_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringNetworkAddress(const std::string &address, uint16_t port);
|
||||||
|
|
||||||
|
const std::string &address() const override;
|
||||||
|
uint16_t port() const override;
|
||||||
|
|
||||||
|
NetworkAddress::ChildVariant representation() override { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
class Network {
|
class Network {
|
||||||
public:
|
public:
|
||||||
virtual ~Network() = default;
|
virtual ~Network() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the provided string and uint16 to the preferred storage method
|
||||||
|
*/
|
||||||
virtual Conveyor<Own<NetworkAddress>>
|
virtual Conveyor<Own<NetworkAddress>>
|
||||||
parseAddress(const std::string &addr, uint16_t port_hint = 0) = 0;
|
parseAddress(const std::string &addr, uint16_t port_hint = 0) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an unnamed pair of bidirectional fds
|
* Set up a listener on this address
|
||||||
*/
|
*/
|
||||||
virtual ErrorOr<SocketPair> socketPair() = 0;
|
virtual Own<Server> listen(NetworkAddress &bind_addr) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to a remote address
|
||||||
|
*/
|
||||||
|
virtual Conveyor<Own<IoStream>> connect(NetworkAddress &address) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a datagram socket at this address.
|
||||||
|
*/
|
||||||
|
virtual Own<Datagram> datagram(NetworkAddress &address) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IoProvider {
|
class IoProvider {
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "async.h"
|
#include "async.h"
|
||||||
|
#include "message.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
namespace saw {
|
namespace saw {
|
||||||
|
|
||||||
template <typename Codec, typename Incoming, typename Outgoing>
|
template <typename Codec, typename Incoming, typename Outgoing, class InContainer = MessageContainer<Incoming>, class OutContainer = MessageContainer<Outgoing>>
|
||||||
class StreamingIoPeer {
|
class StreamingIoPeer {
|
||||||
private:
|
private:
|
||||||
Codec codec;
|
Codec codec;
|
||||||
|
|
||||||
Own<AsyncIoStream> io_stream;
|
Own<AsyncIoStream> io_stream;
|
||||||
|
|
||||||
Own<ConveyorFeeder<Incoming>> incoming_feeder = nullptr;
|
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> incoming_feeder = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StreamingIoPeer(Own<AsyncIoStream> stream);
|
StreamingIoPeer(Own<AsyncIoStream> stream);
|
||||||
|
|
||||||
void send(Outgoing outgoing, Own<MessageBuilder> builder);
|
void send(HeapMessageRoot<Outgoing, OutContainer> builder);
|
||||||
|
|
||||||
Conveyor<Incoming> startReadPump();
|
Conveyor<HeapMessageRootIncoming> startReadPump();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace saw
|
|
||||||
|
|
||||||
|
} // namespace saw
|
||||||
|
|
|
@ -155,24 +155,18 @@ public:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
TlsNetworkAddress::TlsNetworkAddress(Own<NetworkAddress> net_addr, const std::string& host_name_, Tls &tls_)
|
Own<Server> TlsNetwork::listen(NetworkAddress& address) {
|
||||||
: internal{std::move(net_addr)}, host_name{host_name_}, tls{tls_} {}
|
return heap<TlsServer>(internal.listen(address));
|
||||||
|
|
||||||
Own<Server> TlsNetworkAddress::listen() {
|
|
||||||
SAW_ASSERT(internal) { return nullptr; }
|
|
||||||
return heap<TlsServer>(internal->listen());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Conveyor<Own<IoStream>> TlsNetworkAddress::connect() {
|
Conveyor<Own<IoStream>> TlsNetwork::connect(NetworkAddress& address) {
|
||||||
SAW_ASSERT(internal) { return Conveyor<Own<IoStream>>{nullptr, nullptr}; }
|
|
||||||
|
|
||||||
// Helper setups
|
// Helper setups
|
||||||
auto caf = newConveyorAndFeeder<Own<IoStream>>();
|
auto caf = newConveyorAndFeeder<Own<IoStream>>();
|
||||||
Own<TlsClientStreamHelper> helper = heap<TlsClientStreamHelper>(std::move(caf.feeder));
|
Own<TlsClientStreamHelper> helper = heap<TlsClientStreamHelper>(std::move(caf.feeder));
|
||||||
TlsClientStreamHelper* hlp_ptr = helper.get();
|
TlsClientStreamHelper* hlp_ptr = helper.get();
|
||||||
|
|
||||||
// Conveyor entangled structure
|
// Conveyor entangled structure
|
||||||
auto prim_conv = internal->connect().then([this, hlp_ptr](
|
auto prim_conv = internal.connect(address).then([this, hlp_ptr, addr = address.address()](
|
||||||
Own<IoStream> stream) -> ErrorOr<void> {
|
Own<IoStream> stream) -> ErrorOr<void> {
|
||||||
IoStream* inner_stream = stream.get();
|
IoStream* inner_stream = stream.get();
|
||||||
auto tls_stream = heap<TlsIoStream>(std::move(stream));
|
auto tls_stream = heap<TlsIoStream>(std::move(stream));
|
||||||
|
@ -181,8 +175,6 @@ Conveyor<Own<IoStream>> TlsNetworkAddress::connect() {
|
||||||
|
|
||||||
gnutls_init(&session, GNUTLS_CLIENT);
|
gnutls_init(&session, GNUTLS_CLIENT);
|
||||||
|
|
||||||
const std::string &addr = this->address();
|
|
||||||
|
|
||||||
gnutls_server_name_set(session, GNUTLS_NAME_DNS, addr.c_str(),
|
gnutls_server_name_set(session, GNUTLS_NAME_DNS, addr.c_str(),
|
||||||
addr.size());
|
addr.size());
|
||||||
|
|
||||||
|
@ -209,6 +201,11 @@ Conveyor<Own<IoStream>> TlsNetworkAddress::connect() {
|
||||||
return caf.conveyor.attach(std::move(helper));
|
return caf.conveyor.attach(std::move(helper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Own<Datagram> TlsNetwork::datagram(NetworkAddress& address){
|
||||||
|
///@unimplemented
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t forst_tls_push_func(gnutls_transport_ptr_t p, const void *data,
|
static ssize_t forst_tls_push_func(gnutls_transport_ptr_t p, const void *data,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
IoStream *stream = reinterpret_cast<IoStream *>(p);
|
IoStream *stream = reinterpret_cast<IoStream *>(p);
|
||||||
|
@ -238,30 +235,13 @@ static ssize_t forst_tls_pull_func(gnutls_transport_ptr_t p, void *data, size_t
|
||||||
return static_cast<ssize_t>(length.value());
|
return static_cast<ssize_t>(length.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &TlsNetworkAddress::address() const {
|
|
||||||
assert(internal);
|
|
||||||
return internal->address();
|
|
||||||
}
|
|
||||||
uint16_t TlsNetworkAddress::port() const {
|
|
||||||
assert(internal);
|
|
||||||
return internal->port(); }
|
|
||||||
|
|
||||||
std::string TlsNetworkAddress::toString() const { return internal->toString(); }
|
|
||||||
|
|
||||||
TlsNetwork::TlsNetwork(Network &network) : internal{network} {}
|
TlsNetwork::TlsNetwork(Network &network) : internal{network} {}
|
||||||
|
|
||||||
Conveyor<Own<NetworkAddress>> TlsNetwork::parseAddress(const std::string &addr,
|
Conveyor<Own<NetworkAddress>> TlsNetwork::parseAddress(const std::string &addr,
|
||||||
uint16_t port) {
|
uint16_t port) {
|
||||||
return internal.parseAddress(addr, port)
|
/// @todo tls server name needed. Check validity. Won't matter later on, because gnutls should fail anyway. But
|
||||||
.then(
|
/// it's better to find the error source sooner rather than later
|
||||||
[this, addr, port](Own<NetworkAddress> net) -> Own<NetworkAddress> {
|
return internal.parseAddress(addr, port);
|
||||||
assert(net);
|
|
||||||
return heap<TlsNetworkAddress>(std::move(net), addr, tls);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<SocketPair> TlsNetwork::socketPair(){
|
|
||||||
return criticalError("Unimplemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network) {
|
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network) {
|
||||||
|
|
|
@ -33,25 +33,6 @@ public:
|
||||||
Conveyor<Own<IoStream>> accept() override;
|
Conveyor<Own<IoStream>> accept() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TlsNetworkAddress final : public NetworkAddress {
|
|
||||||
private:
|
|
||||||
Own<NetworkAddress> internal;
|
|
||||||
std::string host_name;
|
|
||||||
Tls &tls;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TlsNetworkAddress(Own<NetworkAddress> net_addr, const std::string& host_name_, Tls &tls_);
|
|
||||||
|
|
||||||
Own<Server> listen() override;
|
|
||||||
|
|
||||||
Conveyor<Own<IoStream>> connect() override;
|
|
||||||
|
|
||||||
std::string toString() const override;
|
|
||||||
|
|
||||||
const std::string &address() const override;
|
|
||||||
uint16_t port() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TlsNetwork final : public Network {
|
class TlsNetwork final : public Network {
|
||||||
private:
|
private:
|
||||||
Tls tls;
|
Tls tls;
|
||||||
|
@ -60,10 +41,13 @@ private:
|
||||||
public:
|
public:
|
||||||
TlsNetwork(Network &network);
|
TlsNetwork(Network &network);
|
||||||
|
|
||||||
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &addr,
|
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &addr, uint16_t port = 0) override;
|
||||||
uint16_t port = 0) override;
|
|
||||||
|
Own<Server> listen(NetworkAddress& address) override;
|
||||||
|
|
||||||
ErrorOr<SocketPair> socketPair() override;
|
Conveyor<Own<IoStream>> connect(NetworkAddress& address) override;
|
||||||
|
|
||||||
|
Own<Datagram> datagram(NetworkAddress& address) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network);
|
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network);
|
||||||
|
|
|
@ -15,4 +15,4 @@ env.test_objects = []
|
||||||
env.test_sources.append(dir_path+'/suite/suite.cpp')
|
env.test_sources.append(dir_path+'/suite/suite.cpp')
|
||||||
env.test_headers = [dir_path + '/suite/suite.h']
|
env.test_headers = [dir_path + '/suite/suite.h']
|
||||||
|
|
||||||
env.test_program = env_test.Program('#bin/test', [env.test_sources, env.library_static])
|
env.test_program = env_test.Program('#build/test', [env.test_sources, env.library_static])
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "source/forstio/io.h"
|
#include "source/forstio/io.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
/*
|
||||||
SAW_TEST("Io Socket Pair"){
|
SAW_TEST("Io Socket Pair"){
|
||||||
using namespace saw;
|
using namespace saw;
|
||||||
|
|
||||||
|
@ -40,5 +41,5 @@ SAW_TEST("Io Socket Pair"){
|
||||||
SAW_EXPECT(buffer_out[5] == 0, "Element 6 failed");
|
SAW_EXPECT(buffer_out[5] == 0, "Element 6 failed");
|
||||||
SAW_EXPECT(buffer_out[6] == 0, "Element 7 failed");
|
SAW_EXPECT(buffer_out[6] == 0, "Element 7 failed");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue