Port to linux (not tested because linux compilers sucks)

This commit is contained in:
Andrew Golovashevich 2025-11-08 16:15:41 +03:00
parent e1e10a92f6
commit ca1cedae85
9 changed files with 431 additions and 3 deletions

View File

@ -5,12 +5,15 @@ if (${CMAKE_VERSION} STREQUAL "4.1.1")
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
elseif (${CMAKE_VERSION} STREQUAL "4.0.2")
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457")
elseif (${CMAKE_VERSION} STREQUAL "4.2.0-rc2")
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
else ()
message(FATAL_ERROR "Can't enable CMAKE_EXPERIMENTAL_CXX_IMPORT_STD for this version of cmake, please edit top-lvl CMakeLists.txt")
endif()
project(networks_1 LANGUAGES CXX)
set(CMP0155 NEW)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
@ -26,4 +29,6 @@ add_subdirectory(modules/asyncio)
add_subdirectory(programs/lab4)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE exceptions threads sockets streams)
target_link_libraries(main PRIVATE exceptions threads sockets streams)
add_executable(test-gcc gcc2.cpp)

13
linux-gcc.dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM alpine:latest
RUN apk update \
&& apk upgrade \
&& apk add gcompat ninja-build linux-headers \
&& apk --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main add gcc g++ gdb \
&& rm -rf /var/cache/apk/*
RUN cd /root/ \
&& wget https://github.com/Kitware/CMake/releases/download/v4.2.0-rc2/cmake-4.2.0-rc2-linux-x86_64.sh \
&& sh cmake-4.2.0-rc2-linux-x86_64.sh --prefix=/opt/cmake --skip-license --include-subdir \
&& rm cmake-4.2.0-rc2-linux-x86_64.sh \
&& ln -s /opt/cmake/cmake-4.2.0-rc2-linux-x86_64/bin/cmake /usr/bin/cmake

View File

@ -7,4 +7,5 @@ target_sources(
FILE_SET cxx_modules TYPE CXX_MODULES FILES
./src/exception.cppm
./src/windows.cppm
./src/posix.cppm
)

View File

@ -0,0 +1,61 @@
module;
#ifdef __linux__
#include <cstring>
#include <cerrno>
#endif
export module ru.landgrafhomyak.BGTU.networks_1.exceptions.posix;
#ifdef __linux__
// import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
namespace LdH {
export
[[noreturn]]
void throwFromLinuxErrCode(int code);
export
[[noreturn]]
void throwFromLastLinuxErr();
export void throwFromLastLinuxErrOrTimeout();
}
module : private;
[[noreturn]]
void LdH::throwFromLinuxErrCode(int code) {
char msg[1024];
// todo err check
strerror_r(code, msg, 1024);
size_t trim_size = std::strlen(msg);
while (trim_size > 0) {
switch (msg[--trim_size]) {
case '\n':
case '\r':
msg[trim_size] = '\0';
continue;
default:
break;
}
break;
}
}
[[noreturn]]
void LdH::throwFromLastLinuxErr() {
LdH::throwFromLinuxErrCode(errno);
}
void LdH::throwFromLastLinuxErrOrTimeout() {
int err = errno;
if (err == ETIMEDOUT)
return;
LdH::throwFromLinuxErrCode(err);
}
#endif

View File

@ -1,7 +1,6 @@
module;
#if defined(_WIN32)
# include "platform/windows.hpp"
@ -10,6 +9,14 @@ export module ru.landgrafhomyak.BGTU.networks_1.sockets;
# include "platform/windows.cpp.inc"
#elif defined(__linux__)
# include "platform/linux.hpp"
export module ru.landgrafhomyak.BGTU.networks_1.sockets;
# include "platform/linux.cpp.inc"
#endif
module:private;
module:private;

View File

@ -0,0 +1,221 @@
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.exceptions.posix;
import ru.landgrafhomyak.BGTU.networks_1.streams;
import :berkeley;
namespace LdH::Sockets {
export
void init_sockets() {
}
export
void deinit_sockets() {
}
struct _PosixSockContext {
class address_t {
public:
sockaddr_storage _value;
private:
address_t(sockaddr_storage value) : _value{value} {
}
public:
address_t() = default;
address_t(address_t const &) = default;
address_t(address_t &&) = default;
address_t &operator=(address_t const &) = default;
address_t &operator=(address_t &&) = default;
static address_t parse(char const *addr, char const *service) {
addrinfo *p;
int ret = getaddrinfo(addr, service, nullptr, &p);
if (0 != ret) {
LdH::throwFromLinuxErrCode(ret);
}
sockaddr_storage out;
memset(&out, 0, sizeof(sockaddr_storage));
memcpy(&out, p->ai_addr, p->ai_addrlen);
freeaddrinfo(p);
return address_t{out};
}
std::string to_string() {
char buffer[1024];
if (nullptr != inet_ntop(this->_value.ss_family, &(this->_value), buffer, sizeof(sockaddr_storage))) {
LdH::throwFromLastLinuxErr();
}
return std::string{buffer};
}
};
using sock_type_t = int;
using proto_t = int;
struct af {
public:
static int inet() { return AF_INET; }
static int inet6() { return AF_INET6; }
static int ipx() { return AF_IPX; }
};
struct sock_type {
public:
static int stream() { return SOCK_STREAM; }
static int dgram() { return SOCK_DGRAM; }
};
struct proto {
public:
static int tcp() { return IPPROTO_TCP; }
static int udp() { return IPPROTO_UDP; }
static int icmp() { return IPPROTO_ICMP; }
};
class socket_t {
private:
int _value;
explicit socket_t(int value) : _value{value} {
}
public:
socket_t() : _value{-1} {
}
socket_t(socket_t &&other) noexcept : _value{other._value} {
other._value = -1;
}
socket_t &operator=(socket_t &&other) noexcept {
this->_value = other._value;
other._value = -1;
return *this;
}
~socket_t() = default;
static socket_t create(address_t const &addr, int type, int proto) {
int sock = ::socket(addr._value.ss_family, type, proto);
if (sock == -1) {
LdH::throwFromLastLinuxErr();
}
return socket_t{sock};
}
void close() {
if (0 != ::close(this->_value)) {
LdH::throwFromLastLinuxErr();
}
this->_value = -1;
}
void connect(address_t addr) {
if (0 != ::connect(this->_value, reinterpret_cast<sockaddr *>(&(addr._value)), sizeof(sockaddr)))
LdH::throwFromLastLinuxErr();
}
void bind(address_t addr) {
if (0 != ::bind(this->_value, reinterpret_cast<sockaddr *>(&(addr._value)), sizeof(sockaddr)))
LdH::throwFromLastLinuxErr();
}
socket_t accept(address_t *addr) {
int sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), nullptr);
if (sock == -1) {
LdH::throwFromLastLinuxErr();
}
return socket_t{sock};
}
void listen(std::size_t queue_size) {
if (0 != ::listen(this->_value, queue_size)) {
LdH::throwFromLastLinuxErr();
}
}
void send_stream(std::size_t size, char const *data) {
while (true) {
std::size_t sent_count = ::send(this->_value, data, size, 0);
if (sent_count == -1) {
LdH::throwFromLastLinuxErr();
}
data += sent_count;
size -= sent_count;
if (size <= 0) return;
}
}
void recv_stream(std::size_t size, char *data) {
while (true) {
std::size_t sent_count = ::recv(this->_value, data, size, 0);
if (sent_count == -1) {
LdH::throwFromLastLinuxErr();
}
data += sent_count;
size -= sent_count;
if (size <= 0) return;
}
}
void send_datagram(address_t dest, std::size_t size, char const *data) {
int sent_count = ::sendto(this->_value, data, size, 0, reinterpret_cast<sockaddr *>(&dest._value), sizeof(dest._value));
if (sent_count == -1) {
LdH::throwFromLastLinuxErr();
}
}
address_t recv_datagram(std::size_t size, char *data) {
address_t out;
socklen_t out_size = sizeof(out);
int sent_count = ::recvfrom(this->_value, data, size, 0, reinterpret_cast<sockaddr *>(&out), &out_size);
if (sent_count == -1) {
LdH::throwFromLastLinuxErr();
}
return out;
}
};
};
static_assert(Berkeley::BerkeleySocketsContext<_PosixSockContext>);
export using Address = Berkeley::Address<_PosixSockContext>;
export using StreamSocket = Berkeley::StreamSocket<_PosixSockContext>;
export using StreamSocketsServer = Berkeley::StreamSocketsServer<_PosixSockContext>;
export
StreamSocket connect_tcp(Address addr) {
return Berkeley::connect_tcp<_PosixSockContext>(addr);
}
export
StreamSocketsServer listen_tcp(Address addr, std::size_t queue_size) {
return Berkeley::listen_tcp<_PosixSockContext>(addr, queue_size);
}
export using ClientDatagramSocket = Berkeley::ClientDatagramSocket<_PosixSockContext>;
export using ServerDatagramSocket = Berkeley::ServerDatagramSocket<_PosixSockContext>;
export
ClientDatagramSocket connect_udp(Address addr) {
return Berkeley::connect_udp<_PosixSockContext>(addr);
}
export
ServerDatagramSocket listen_udp(Address addr) {
return Berkeley::listen_udp<_PosixSockContext>(addr);
}
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <bits/stdc++.h>

View File

@ -9,6 +9,7 @@ target_sources(
src/thread_routine.cppm
src/highlevel_impl.cppm
src/platform/windows.cppm
src/platform/posix.cppm
)
target_link_libraries(threads PRIVATE exceptions Synchronization)

View File

@ -0,0 +1,111 @@
module;
#ifdef __linux__
#include <unistd.h>
#include <pthread.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <bits/stdc++.h>
#endif
export module ru.landgrafhomyak.BGTU.networks_1.threads:impl.posix;
#ifdef __linux__
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.exceptions.posix;
import :thread_routine;
import :highlevel_impl;
namespace LdH {
class NativeThreadWrapperForPosix {
private:
pthread_t _thread;
public:
NativeThreadWrapperForPosix() : _thread{} {
}
void join() {
auto ret = pthread_join(this->_thread, nullptr);
if (ret != 0) {
LdH::throwFromLinuxErrCode(ret);
}
}
void destroy() {
auto ret = pthread_join(this->_thread, nullptr);
if (ret != 0) {
LdH::throwFromLinuxErrCode(ret);
}
}
~NativeThreadWrapperForPosix() = default;
class notifier_t {
std::uint32_t _ptr;
public:
notifier_t() : _ptr{0} {
}
void wait() {
long ret = syscall(SYS_futex, &(this->_ptr), FUTEX_WAIT, 0, nullptr);
if (ret == -1) {
switch (errno) {
case EAGAIN:
return;
default:
LdH::throwFromLastLinuxErr();
}
}
}
void notify() {
long ret = syscall(SYS_futex, &(this->_ptr), FUTEX_WAIT, INT_MAX);
if (ret == -1) {
switch (errno) {
case EAGAIN:
return;
default:
LdH::throwFromLastLinuxErr();
}
}
}
};
using kernel_ret_t = void *;
static void *kernel_ret() {
return nullptr;
}
private:
explicit NativeThreadWrapperForPosix(pthread_t hThread) : _thread{hThread} {
}
public:
static NativeThreadWrapperForPosix start(std::string &, void * (*kernel)(void *), void *kernel_arg) {
pthread_t native_thread;
int ret = pthread_create(&native_thread, nullptr, kernel, kernel_arg);
if (ret != 0) {
LdH::throwFromLinuxErrCode(ret);
}
return NativeThreadWrapperForPosix{native_thread};
}
};
static_assert(LdH::NativeHighLevelThreadWrapper<NativeThreadWrapperForPosix>);
export
using ThreadController = LdH::CommonHighLevelThreadWrapper<NativeThreadWrapperForPosix>;
export ThreadController fork(std::string &&name, ThreadRoutine auto &&routine) {
return _common_highlevel_fork<NativeThreadWrapperForPosix>(std::move(name), std::move(routine));
}
}
#endif