Configured 'import std' in cmake and implemented and stub for threading module on windows

This commit is contained in:
Andrew Golovashevich 2025-09-20 19:05:03 +03:00
commit 4aad26efa7
15 changed files with 960 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/*build*/
/.idea/

26
CMakeLists.txt Normal file
View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.30 FATAL_ERROR)
message(STATUS "CMake version is ${CMAKE_VERSION}")
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")
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)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_MODULE_STD 1)
add_subdirectory(modules/exceptions)
add_subdirectory(modules/threads)
add_subdirectory(modules/asyncio)
add_subdirectory(programs/lab4)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE exceptions threads)

18
main.cpp Normal file
View File

@ -0,0 +1,18 @@
#include <iostream>
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.threads;
int main() {
try {
auto t = LdH::fork("123", []() { std::cout << "123" << std::endl; });
t.join();
t.destroy();
} catch (LdH::Exception const &e) {
std::cerr << "Uncaught exception in main:\n";
e.printStackTrace();
} catch (std::exception const &e) {
std::cerr << "Uncaught exception in main:\n" << e.what() << "\n";
}
}

View File

@ -0,0 +1,7 @@
add_library(
asyncio OBJECT
./Include/LdH/asyncio.hpp
src/eventloop.cpp
)
target_include_directories(exceptions PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include)
target_link_libraries(asyncio PUBLIC exceptions)

View File

@ -0,0 +1,154 @@
#pragma once
//#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <concepts>
#include <type_traits>
#include <LdH/exception.hpp>
namespace LdH::Asyncio {
#if 0
template<class ret_t, template<typename> class lambda_t>
concept OverlappedFunc = std::invocable<lambda_t<ret_t>, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>
&& std::same_as<std::invoke_result_t<lambda_t<ret_t>, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>, ret_t>;
#endif
template<class lambda_t>
concept OverlappedFunc = std::invocable<lambda_t, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>
&& std::same_as<std::invoke_result_t<lambda_t, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>, DWORD>;
class WindowsOverlappedEventloop {
private:
static thread_local struct _running_loop_variable_t {
private:
WindowsOverlappedEventloop *_value;
public:
[[nodiscard]]
WindowsOverlappedEventloop *get() {
auto cached = this->_value;
if (cached == nullptr) throw LdH::Exception{"No running loop"};
return cached;
}
[[nodiscard]]
WindowsOverlappedEventloop *getOrNull() {
return this->_value;
}
void set(WindowsOverlappedEventloop *v) {
if (this->_value != nullptr && v != nullptr) throw LdH::Exception{"Recursive loops not allowed"};
this->_value = v;
}
} _running_loop;
struct FiberMetadata {
public:
OVERLAPPED overlapped;
void *fiber_id;
FiberMetadata *next_existing;
FiberMetadata *prev_existing;
FiberMetadata *next_active;
FiberMetadata *prev_active;
DWORD err_code;
DWORD read_count;
};
HANDLE const notifier;
bool const need_rollback_to_thread;
void *const master_fiber;
bool interrupted;
FiberMetadata *next_existing;
FiberMetadata *next_active;
DWORD const fls_fiber_metadata;
void *fiber_to_destroy;
public:
WindowsOverlappedEventloop();
~WindowsOverlappedEventloop();
private:
[[nodiscard]]
HANDLE createEvent() const;
[[nodiscard]]
HANDLE prepareFibers() const;
[[nodiscard]]
DWORD allocFls() const;
public:
void runUntilHasTasksAndNotInterrupted();
private:
void _addTask(void (*routine)(void *), void *arg);
static void _overlapped_completion_routine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, FiberMetadata *lpOverlapped);
public:
template<class T>
static void addTaskToRuningLoop(void (*routine)(T *), T *arg) {
WindowsOverlappedEventloop::_running_loop.get()->_addTask(
reinterpret_cast<void (*)(void *)>(routine),
reinterpret_cast<void *>(arg)
);
}
template<class T>
void addTask(void (*routine)(T *), T *arg) {
this->_addTask(
reinterpret_cast<void (*)(void *)>(routine),
reinterpret_cast<void *>(arg)
);
}
static DWORD overlappedCall(OverlappedFunc auto func) {
auto loop = WindowsOverlappedEventloop::_running_loop.get();
auto metadata = reinterpret_cast<FiberMetadata *>(FlsGetValue(loop->fls_fiber_metadata));
if (metadata == nullptr) LdH::Exception::throwFromLastWindowsErr();
DWORD read_count = func(reinterpret_cast<LPOVERLAPPED>(metadata), reinterpret_cast<LPOVERLAPPED_COMPLETION_ROUTINE>(&WindowsOverlappedEventloop::_overlapped_completion_routine));
if (read_count != 0) return read_count;
if (loop->next_active == metadata)
loop->next_active = metadata->next_active;
if (metadata->next_active != nullptr)
metadata->next_active->prev_active = metadata->prev_active;
if (metadata->prev_active != nullptr)
metadata->prev_active->next_active = metadata->next_active;
metadata->next_active = nullptr;
metadata->prev_active = nullptr;
SwitchToFiber(loop->master_fiber);
if (metadata->err_code != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(metadata->err_code);
return metadata->read_count;
}
static void interruptEventLoop() {
WindowsOverlappedEventloop::_running_loop.get()->interrupted = true;
}
private:
struct FiberInitializer {
WindowsOverlappedEventloop *loop;
void (*routine)(void *);
void *routine_arg;
void *caller_fiber;
};
static void fiber_kernel(FiberInitializer *init);
};
}

View File

@ -0,0 +1,172 @@
thread_local LdH::Asyncio::WindowsOverlappedEventloop::_running_loop_variable_t LdH::Asyncio::WindowsOverlappedEventloop::_running_loop{};
LdH::Asyncio::WindowsOverlappedEventloop::WindowsOverlappedEventloop() :
notifier{this->createEvent()},
need_rollback_to_thread{true},
master_fiber{this->prepareFibers()},
interrupted{false},
next_existing{nullptr},
next_active{nullptr},
fls_fiber_metadata{this->allocFls()} {
}
HANDLE LdH::Asyncio::WindowsOverlappedEventloop::createEvent() const {
HANDLE e = CreateEventA(nullptr, false, false, nullptr);
if (e == nullptr)
LdH::Exception::throwFromLastWindowsErr();
return e;
}
void *LdH::Asyncio::WindowsOverlappedEventloop::prepareFibers() const {
void *f = ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
if (f == nullptr) {
auto err = GetLastError();
if (err != ERROR_ALREADY_FIBER)
LdH::Exception::throwFromWindowsErrCode(err);
*const_cast<bool *>(&this->need_rollback_to_thread) = false;
return GetCurrentFiber();
}
return f;
}
DWORD LdH::Asyncio::WindowsOverlappedEventloop::allocFls() const {
auto index = FlsAlloc(nullptr);
if (index == FLS_OUT_OF_INDEXES)
LdH::Exception::throwFromLastWindowsErr();
return index;
}
LdH::Asyncio::WindowsOverlappedEventloop::~WindowsOverlappedEventloop() {
if (this->need_rollback_to_thread) {
if (0 == ConvertFiberToThread()) LdH::Exception::throwFromLastWindowsErr();
}
if (0 == CloseHandle(this->notifier)) LdH::Exception::throwFromLastWindowsErr();
}
void LdH::Asyncio::WindowsOverlappedEventloop::_addTask(void (*routine)(void *), void *arg) {
LdH::Asyncio::WindowsOverlappedEventloop::FiberInitializer init{
.loop = this,
.routine = routine,
.routine_arg = arg,
.caller_fiber = GetCurrentFiber()
};
auto new_fiber = CreateFiber(
0,
reinterpret_cast<LPFIBER_START_ROUTINE >(&LdH::Asyncio::WindowsOverlappedEventloop::fiber_kernel),
&init
);
if (new_fiber == nullptr) LdH::Exception::throwFromLastWindowsErr();
SwitchToFiber(new_fiber);
}
void LdH::Asyncio::WindowsOverlappedEventloop::fiber_kernel(LdH::Asyncio::WindowsOverlappedEventloop::FiberInitializer *p_init) {
auto init = *p_init;
WindowsOverlappedEventloop::FiberMetadata metadata;
metadata.fiber_id = GetCurrentFiber();
metadata.next_existing = init.loop->next_existing;
if (init.loop->next_existing != nullptr)
init.loop->next_existing->prev_existing = &metadata;
init.loop->next_existing = &metadata;
metadata.prev_existing = nullptr;
metadata.next_active = init.loop->next_active;
if (init.loop->next_active != nullptr)
init.loop->next_active->prev_active = &metadata;
init.loop->next_active = &metadata;
metadata.prev_active = nullptr;
FlsSetValue(init.loop->fls_fiber_metadata, &metadata);
SwitchToFiber(init.caller_fiber);
try {
init.routine(init.routine_arg);
} catch (LdH::Exception &e) {
e.printStackTrace();
} catch (std::exception &e) {
std::cerr << e.what() << "\n";
}
if (init.loop->next_active == &metadata)
init.loop->next_active = metadata.next_active;
if (metadata.next_active != nullptr)
metadata.next_active->prev_active = metadata.prev_active;
if (metadata.prev_active != nullptr)
metadata.prev_active->next_active = metadata.next_active;
metadata.next_active = nullptr;
metadata.prev_active = nullptr;
if (init.loop->next_existing == &metadata)
init.loop->next_existing = metadata.next_existing;
if (metadata.next_existing != nullptr)
metadata.next_existing->prev_existing = metadata.prev_existing;
if (metadata.prev_existing != nullptr)
metadata.prev_existing->next_existing = metadata.next_existing;
metadata.next_existing = nullptr;
metadata.prev_existing = nullptr;
init.loop->fiber_to_destroy = metadata.fiber_id;
SwitchToFiber(init.loop->master_fiber);
}
void LdH::Asyncio::WindowsOverlappedEventloop::_overlapped_completion_routine(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LdH::Asyncio::WindowsOverlappedEventloop::FiberMetadata *lpOverlapped
) {
lpOverlapped->err_code = dwErrorCode;
lpOverlapped->read_count = dwNumberOfBytesTransfered;
auto loop = WindowsOverlappedEventloop::_running_loop.get();
lpOverlapped->next_active = loop->next_active;
if (loop->next_active != nullptr)
loop->next_active->prev_active = lpOverlapped;
loop->next_active = lpOverlapped;
if (0 == SetEvent(loop->notifier))
LdH::Exception::throwFromLastWindowsErr();
}
void LdH::Asyncio::WindowsOverlappedEventloop::runUntilHasTasksAndNotInterrupted() {
WindowsOverlappedEventloop::_running_loop.set(this);
while (!this->interrupted) {
while (this->next_active != nullptr) {
SwitchToFiber(this->next_active->fiber_id);
if (this->fiber_to_destroy != nullptr) {
DeleteFiber(this->fiber_to_destroy);
this->fiber_to_destroy = nullptr;
}
if (this->interrupted)
goto CLEANUP;
}
if (this->next_existing == nullptr)
goto CLEANUP;
switch (WaitForSingleObjectEx(this->notifier, INFINITE, true)) {
case WAIT_FAILED:
WindowsOverlappedEventloop::_running_loop.set(nullptr);
LdH::Exception::throwFromLastWindowsErr();
return;
case WAIT_ABANDONED:
WindowsOverlappedEventloop::_running_loop.set(nullptr);
throw LdH::Exception{"Unexpected WAIT_ABANDONED"};
case WAIT_IO_COMPLETION:
WindowsOverlappedEventloop::_running_loop.set(nullptr);
throw LdH::Exception{"Unexpected WAIT_IO_COMPLETION"};
case WAIT_OBJECT_0:
case WAIT_TIMEOUT:
continue;
}
}
CLEANUP:
WindowsOverlappedEventloop::_running_loop.set(nullptr);
}

View File

@ -0,0 +1,10 @@
add_library(exceptions STATIC)
target_sources(
exceptions
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES FILES
./src/exception.cppm
./src/windows.cppm
)

View File

@ -0,0 +1,57 @@
export module ru.landgrafhomyak.BGTU.networks_1.exceptions;
import std;
namespace LdH {
export class Exception : public std::exception {
public:
static thread_local std::vector<std::stacktrace_entry> _async_caller_stacktrace;
const std::string message;
const std::vector<std::stacktrace_entry> stacktrace;
explicit inline Exception(char const *message) : message{message}, stacktrace{Exception::generateStacktrace(-1)} {}
explicit inline Exception(std::string const &message) : message{message}, stacktrace{Exception::generateStacktrace(-1)} {}
explicit inline Exception(std::string const &&message) : message{message}, stacktrace{Exception::generateStacktrace(-1)} {}
[[nodiscard]]
static std::vector<std::stacktrace_entry> generateStacktrace(std::int_fast16_t hidden_frames_count);
[[nodiscard]]
const char *what() const override {
return this->message.c_str();
};
std::string formatOutput() const;
void printStackTrace() const {
std::cerr << this->formatOutput();
}
};
}
module : private;
thread_local std::vector<std::stacktrace_entry> LdH::Exception::_async_caller_stacktrace{};
std::vector<std::stacktrace_entry> LdH::Exception::generateStacktrace(std::int_fast16_t hidden_frames_count) {
if (hidden_frames_count > 0)
throw Exception("Frames count must be negative");
std::vector<std::stacktrace_entry> joined{Exception::_async_caller_stacktrace};
auto current = std::stacktrace::current();
joined.insert(joined.begin(), current.begin() + 1 - hidden_frames_count, current.end());
return joined;
}
std::string LdH::Exception::formatOutput() const {
std::stringstream builder;
builder << "Exception: " << this->message << '\n';
for (auto const &frame: this->stacktrace) {
builder << "\t" << frame.description();
if (!frame.source_file().empty()) {
builder << "\t\t" << frame.source_file() << ":" << frame.source_line() << '\n';
}
}
return builder.str();
}

View File

@ -0,0 +1,51 @@
module;
#include <Windows.h>
export module ru.landgrafhomyak.BGTU.networks_1.exceptions.windows;
import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
namespace LdH {
export
[[noreturn]]
void throwFromWindowsErrCode(DWORD code);
export
[[noreturn]]
void throwFromLastWindowsErr();
export void throwFromLastWindowsErrOrTimeout();
}
module : private;
[[noreturn]]
void LdH::throwFromWindowsErrCode(DWORD code) {
char *msg;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<char *>(&msg),
0,
nullptr
);
std::string msgpp{msg};
LocalFree(msg);
throw LdH::Exception{std::move(msgpp)};
}
[[noreturn]]
void LdH::throwFromLastWindowsErr() {
LdH::throwFromWindowsErrCode(GetLastError());
}
void LdH::throwFromLastWindowsErrOrTimeout() {
DWORD err = GetLastError();
if (err == ERROR_TIMEOUT)
return;
LdH::throwFromWindowsErrCode(err);
}

View File

@ -0,0 +1,11 @@
add_library(threads STATIC)
target_sources(
threads
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES FILES
src/windows.cppm
)
target_link_libraries(threads PRIVATE exceptions Synchronization)

View File

@ -0,0 +1,190 @@
module;
#include <Windows.h>
export module ru.landgrafhomyak.BGTU.networks_1.threads;
import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.exceptions.windows;
namespace LdH {
enum class _thread_state {
_thread_state_UNINITIALIZED,
_thread_state_RUNNING,
_thread_state_JOINED,
_thread_state_DESTROYED,
_thread_state_MOVED
};
using _thread_state::_thread_state_UNINITIALIZED;
using _thread_state::_thread_state_RUNNING;
using _thread_state::_thread_state_JOINED;
using _thread_state::_thread_state_DESTROYED;
using _thread_state::_thread_state_MOVED;
export
template<class lambda_t>
concept ThreadRoutine = std::invocable<lambda_t> && std::same_as<std::invoke_result_t<lambda_t>, void> && std::movable<lambda_t>;
export class ThreadController;
export ThreadController fork(std::string name, ThreadRoutine auto);
export class ThreadController {
private:
_thread_state state;
HANDLE hThread;
public:
ThreadController();
ThreadController(ThreadController &&other);
void join();
void destroy();
~ThreadController() noexcept(false);
private:
ThreadController(_thread_state state, HANDLE hThread) : state{state}, hThread{hThread} {
}
template<ThreadRoutine thread_routine_t>
struct _initializer {
public:
void *volatile notifier;
std::string name;
thread_routine_t thread_routine;
};
template<ThreadRoutine thread_routine_t>
static DWORD _kernel(_initializer<thread_routine_t> *init) {
std::string thread_name = std::move(init->name);
thread_routine_t thread_routine = std::move(init->thread_routine);
init->notifier = init;
WakeByAddressSingle(const_cast<void **>(&init->notifier));
try {
thread_routine();
} catch (LdH::Exception const &e) {
std::cerr << "Uncaught exception in thread" << thread_name << ":\n";
e.printStackTrace();
} catch (std::exception const &e) {
std::cerr << "Uncaught exception in thread" << thread_name << ":\n" << e.what() << "\n";
}
return 0;
};
friend
ThreadController fork(std::string name, ThreadRoutine auto);
};
}
export LdH::ThreadController LdH::fork(std::string name, LdH::ThreadRoutine auto routine) {
using thread_routine_t = decltype(routine);
void *notifier_expected = nullptr;
LdH::ThreadController::_initializer<thread_routine_t> initializer{
.notifier = nullptr,
.name = std::move(name),
.thread_routine = std::move(routine)
};
HANDLE hThread = CreateThread(
nullptr,
0,
(LPTHREAD_START_ROUTINE) &LdH::ThreadController::_kernel<thread_routine_t>,
&initializer,
0u,
nullptr
);
if (hThread == nullptr)
LdH::throwFromLastWindowsErr();
while (true) {
if (TRUE == WaitOnAddress(&(initializer.notifier), &notifier_expected, sizeof(void *), INFINITE))
break;
LdH::throwFromLastWindowsErrOrTimeout();
}
return ThreadController{_thread_state_RUNNING, hThread};
}
module : private;
LdH::ThreadController::ThreadController() : state{_thread_state_UNINITIALIZED}, hThread{nullptr} {
}
LdH::ThreadController::ThreadController(LdH::ThreadController &&other) : state{other.state}, hThread{other.hThread} {
other.hThread = nullptr;
other.state = _thread_state_DESTROYED;
}
void LdH::ThreadController::join() {
switch (this->state) {
case _thread_state_UNINITIALIZED:
throw Exception{"Variable not initialized"};
case _thread_state_RUNNING:
break;
case _thread_state_JOINED:
throw Exception{"Thread already joined"};
case _thread_state_DESTROYED:
throw Exception{"Thread already destroyed"};
case _thread_state_MOVED:
throw Exception{"Content of this variable was moved to another variable"};
}
while (true) {
switch (WaitForSingleObject(this->hThread, INFINITE)) {
case WAIT_FAILED:
LdH::throwFromLastWindowsErr();
case WAIT_TIMEOUT:
continue;
case WAIT_ABANDONED:
throw LdH::Exception{"Unexpected return WAIT_ABANDONED of WaitForSingleObject"};
case WAIT_OBJECT_0:
this->state = _thread_state_JOINED;
return;
}
}
}
void LdH::ThreadController::destroy() {
switch (this->state) {
case _thread_state_UNINITIALIZED:
throw Exception{"Variable not initialized"};
case _thread_state_RUNNING:
throw Exception{"Thread not finished yet"};
case _thread_state_JOINED:
break;
case _thread_state_DESTROYED:
throw Exception{"Thread already destroyed"};
case _thread_state_MOVED:
throw Exception{"Content of this variable was moved to another variable"};
}
if (0 == CloseHandle(this->hThread))
LdH::throwFromLastWindowsErr();
this->state = _thread_state_DESTROYED;
this->hThread = nullptr;
}
LdH::ThreadController::~ThreadController() noexcept(false) {
switch (this->state) {
case _thread_state_UNINITIALIZED:
break;
case _thread_state_RUNNING:
throw Exception{"Thread not finished yet"};
case _thread_state_JOINED:
throw Exception{"Thread not destroyed yet"};
case _thread_state_DESTROYED:
break;
case _thread_state_MOVED:
break;
}
}

View File

@ -0,0 +1,5 @@
add_executable(lab4_ping ./src/ping.cpp)
add_executable(lab4_pong ./src/pong.cpp)
target_link_libraries(lab4_ping PRIVATE wsock32 ws2_32 exceptions asyncio)
target_link_libraries(lab4_pong PRIVATE wsock32 ws2_32 exceptions asyncio)

View File

@ -0,0 +1,80 @@
#include <Winsock2.h>
#include <Windows.h>
#include <iostream>
#include <LdH/exception.hpp>
#include <LdH/asyncio.hpp>
static void ping() {
SOCKET sock = WSASocketW(
AF_INET,
SOCK_DGRAM,
0,
nullptr,
0,
/*WSA_FLAG_OVERLAPPED | */WSA_FLAG_NO_HANDLE_INHERIT
);
if (sock == INVALID_SOCKET)
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
sockaddr selfaddr;
INT selfaddrlen = sizeof(sockaddr);
if (SOCKET_ERROR == WSAStringToAddressW((wchar_t *) L"127.0.0.1:8082", AF_INET, nullptr, &selfaddr, &selfaddrlen))
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
while (true) {
char buffer[1024] = "hello world";
WSABUF buffers_meta[1] = {{1024, buffer}};
sockaddr addr;
INT addrlen = sizeof(sockaddr);
DWORD flags = 0;/* MSG_PARTIAL*/
DWORD transferred_count;
auto res = WSASendTo(
sock,
buffers_meta, 1,
&transferred_count,
/* MSG_PARTIAL*/ 0,
&selfaddr, selfaddrlen,
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
res = WSARecvFrom(
sock,
buffers_meta, 1,
&transferred_count,
&flags,
&addr, &addrlen,
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
std::cout << buffer << std::endl;
}
}
int main() {
try {
WSADATA wsaData;
auto wsa_init_res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsa_init_res != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(wsa_init_res);
ping();
WSACleanup();
} catch (LdH::Exception &e) {
e.printStackTrace();
}
}

View File

@ -0,0 +1,83 @@
#include <Winsock2.h>
#include <Windows.h>
#include <iostream>
#include <LdH/exception.hpp>
#include <LdH/asyncio.hpp>
static void connections_listener() {
SOCKET sock = WSASocketW(
AF_INET,
SOCK_DGRAM,
0,
nullptr,
0,
/*WSA_FLAG_OVERLAPPED | */WSA_FLAG_NO_HANDLE_INHERIT
);
if (sock == INVALID_SOCKET)
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
sockaddr selfaddr;
INT selfaddrlen = sizeof(sockaddr);
if (SOCKET_ERROR == WSAStringToAddressW((wchar_t *) L"127.0.0.1:8082", AF_INET, nullptr, &selfaddr, &selfaddrlen))
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
if (SOCKET_ERROR == bind(sock, &selfaddr, selfaddrlen))
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
while (true) {
char buffer[1024];
WSABUF buffers_meta[1] = {{1024, buffer}};
sockaddr addr;
INT addrlen = sizeof(sockaddr);
DWORD flags = 0;/* MSG_PARTIAL*/
DWORD transferred_count;
auto res = WSARecvFrom(
sock,
buffers_meta, 1,
&transferred_count,
&flags,
&addr, &addrlen,
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
buffers_meta[0].len = transferred_count;
std::cout << buffer << std::endl;
res = WSASendTo(
sock,
buffers_meta, 1,
&transferred_count,
/* MSG_PARTIAL*/ 0,
&addr, sizeof(sockaddr),
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
}
}
int main() {
try {
WSADATA wsaData;
auto wsa_init_res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsa_init_res != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(wsa_init_res);
connections_listener();
WSACleanup();
} catch (LdH::Exception &e) {
e.printStackTrace();
}
}

View File

@ -0,0 +1,94 @@
#include <Winsock2.h>
#include <Windows.h>
#include <LdH/exception.hpp>
#include <LdH/asyncio.hpp>
struct request_t {
char buffer[1024];
WSABUF buffers_meta[1] = {{1024, buffer}};
sockaddr addr;
SOCKET socket;
};
static void connections_listener(void *) {
SOCKET server = WSASocketW(
AF_INET,
SOCK_DGRAM,
0,
nullptr,
0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT
);
if (server == INVALID_SOCKET)
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
while (true) {
auto req = new request_t{};
req->socket = server;
LdH::Asyncio::WindowsOverlappedEventloop::overlappedCall(
[&](LPOVERLAPPED o, LPOVERLAPPED_COMPLETION_ROUTINE ocr) -> DWORD {
DWORD recived_count;
auto res = WSARecvFrom(
server,
req->buffers_meta, 1,
&recived_count,
/* MSG_PARTIAL*/ nullptr,
&req->addr, nullptr,
o, reinterpret_cast<LPWSAOVERLAPPED_COMPLETION_ROUTINE>(ocr)
);
if (res == SOCKET_ERROR) {
auto err = WSAGetLastError();
if (err == WSA_IO_PENDING)
return 0;
LdH::Exception::throwFromWindowsErrCode(err);
}
return recived_count;
}
);
}
}
static void answer(request_t *data) {
LdH::Asyncio::WindowsOverlappedEventloop::overlappedCall(
[&](LPOVERLAPPED o, LPOVERLAPPED_COMPLETION_ROUTINE ocr) -> DWORD {
DWORD recived_count;
auto res = WSASendTo(
data->socket,
data->buffers_meta, 1,
&recived_count,
/* MSG_PARTIAL*/ 0,
&data->addr, sizeof(sockaddr),
o, reinterpret_cast<LPWSAOVERLAPPED_COMPLETION_ROUTINE>(ocr)
);
if (res == SOCKET_ERROR) {
auto err = WSAGetLastError();
if (err == WSA_IO_PENDING)
return 0;
LdH::Exception::throwFromWindowsErrCode(err);
}
return recived_count;
}
);
}
int main() {
try {
WSADATA wsaData;
auto wsa_init_res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsa_init_res != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(wsa_init_res);
LdH::Asyncio::WindowsOverlappedEventloop eventloop{};
eventloop.addTask<void>(&connections_listener, nullptr);
eventloop.runUntilHasTasksAndNotInterrupted();
WSACleanup();
} catch (LdH::Exception &e) {
e.printStackTrace();
}
}