Labs 3 & 4 implementation
This commit is contained in:
parent
ca1cedae85
commit
65b6aedf86
@ -26,7 +26,7 @@ add_subdirectory(modules/streams)
|
|||||||
add_subdirectory(modules/sockets)
|
add_subdirectory(modules/sockets)
|
||||||
|
|
||||||
add_subdirectory(modules/asyncio)
|
add_subdirectory(modules/asyncio)
|
||||||
add_subdirectory(programs/lab4)
|
add_subdirectory(programs/lab34)
|
||||||
|
|
||||||
add_executable(main main.cpp)
|
add_executable(main main.cpp)
|
||||||
target_link_libraries(main PRIVATE exceptions threads sockets streams)
|
target_link_libraries(main PRIVATE exceptions threads sockets streams)
|
||||||
|
|||||||
@ -44,7 +44,7 @@ namespace LdH {
|
|||||||
template<class prefix_printer_t, class routine_t>
|
template<class prefix_printer_t, class routine_t>
|
||||||
requires std::invocable<routine_t> && std::same_as<std::invoke_result_t<routine_t>, void>
|
requires std::invocable<routine_t> && std::same_as<std::invoke_result_t<routine_t>, void>
|
||||||
&& std::invocable<prefix_printer_t> && std::same_as<std::invoke_result_t<prefix_printer_t>, void>
|
&& std::invocable<prefix_printer_t> && std::same_as<std::invoke_result_t<prefix_printer_t>, void>
|
||||||
void run_catching(prefix_printer_t const &prefix_printer, routine_t const &routine) {
|
void run_catching(prefix_printer_t const &prefix_printer, routine_t &routine) {
|
||||||
try {
|
try {
|
||||||
routine();
|
routine();
|
||||||
} catch (LdH::Exception const &e) {
|
} catch (LdH::Exception const &e) {
|
||||||
|
|||||||
@ -25,9 +25,9 @@ namespace LdH::Sockets::Berkeley {
|
|||||||
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e) { { s.connect(e) } -> std::same_as<void>; } &&
|
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e) { { s.connect(e) } -> std::same_as<void>; } &&
|
||||||
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e) { { s.bind(e) } -> std::same_as<void>; } &&
|
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e) { { s.bind(e) } -> std::same_as<void>; } &&
|
||||||
requires(typename ctx_t::socket_t s) { { s.close() } -> std::same_as<void>; } &&
|
requires(typename ctx_t::socket_t s) { { s.close() } -> std::same_as<void>; } &&
|
||||||
requires(typename ctx_t::socket_t s, std::size_t c, char const *d) { { s.send_stream(c, d) } -> std::same_as<void>; } &&
|
requires(typename ctx_t::socket_t s, std::size_t *c, char const *d, bool r) { { s.send_stream(c, d, r) } -> std::same_as<bool>; } &&
|
||||||
requires(typename ctx_t::socket_t s, std::size_t c, char *d) { { s.recv_stream(c, d) } -> std::same_as<void>; } &&
|
requires(typename ctx_t::socket_t s, std::size_t *c, char *d, bool r) { { s.recv_stream(c, d, r) } -> std::same_as<bool>; } &&
|
||||||
requires(typename ctx_t::socket_t s, std::size_t c, char *d) { { s.recv_datagram(c, d) } -> std::same_as<typename ctx_t::address_t>; } &&
|
requires(typename ctx_t::socket_t s, std::size_t *c, char *d) { { s.recv_datagram(c, d) } -> std::same_as<typename ctx_t::address_t>; } &&
|
||||||
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e, std::size_t c, char const *d) { { s.send_datagram(e, c, d) } -> std::same_as<void>; } &&
|
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e, std::size_t c, char const *d) { { s.send_datagram(e, c, d) } -> std::same_as<void>; } &&
|
||||||
requires(typename ctx_t::socket_t s, typename ctx_t::address_t *a) { { s.accept(a) } -> std::same_as<typename ctx_t::socket_t>; };
|
requires(typename ctx_t::socket_t s, typename ctx_t::address_t *a) { { s.accept(a) } -> std::same_as<typename ctx_t::socket_t>; };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -190,7 +190,7 @@ namespace LdH::Sockets::Berkeley {
|
|||||||
ServerDatagramSocket &operator=(ServerDatagramSocket &&other) noexcept = default;
|
ServerDatagramSocket &operator=(ServerDatagramSocket &&other) noexcept = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Address<ctx_t> recvOneTruncating(std::size_t size, char *data) {
|
Address<ctx_t> recvOneTruncating(std::size_t *size, char *data) {
|
||||||
this->_start_usage();
|
this->_start_usage();
|
||||||
auto addr = this->_value.recv_datagram(size, data);
|
auto addr = this->_value.recv_datagram(size, data);
|
||||||
this->_finish_usage();
|
this->_finish_usage();
|
||||||
@ -199,7 +199,7 @@ namespace LdH::Sockets::Berkeley {
|
|||||||
|
|
||||||
void sendOne(Address<ctx_t> destination, std::size_t size, char const *data) {
|
void sendOne(Address<ctx_t> destination, std::size_t size, char const *data) {
|
||||||
this->_start_usage();
|
this->_start_usage();
|
||||||
this->_value.send_datagram(destination, size, data);
|
this->_value.send_datagram(_addr_internals<ctx_t>::unwrap(destination), size, data);
|
||||||
this->_finish_usage();
|
this->_finish_usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,15 +238,15 @@ namespace LdH::Sockets::Berkeley {
|
|||||||
ClientDatagramSocket &operator=(ClientDatagramSocket &&other) noexcept = default;
|
ClientDatagramSocket &operator=(ClientDatagramSocket &&other) noexcept = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void recvOneTruncating(std::size_t size, char *data) override {
|
void recvOneTruncating(std::size_t *size, char *data) override {
|
||||||
this->_start_usage();
|
this->_start_usage();
|
||||||
this->_value.recv_stream(size, data);
|
this->_value.recv_stream(size, data, false);
|
||||||
this->_finish_usage();
|
this->_finish_usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendOne(std::size_t size, char const *data) override {
|
void sendOne(std::size_t size, char const *data) override {
|
||||||
this->_start_usage();
|
this->_start_usage();
|
||||||
this->_value.send_stream(size, data);
|
this->_value.send_stream(&size, data, false);
|
||||||
this->_finish_usage();
|
this->_finish_usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -208,16 +208,18 @@ namespace LdH::Sockets::Berkeley {
|
|||||||
|
|
||||||
StreamSocket &operator=(StreamSocket &&other) noexcept = default;
|
StreamSocket &operator=(StreamSocket &&other) noexcept = default;
|
||||||
|
|
||||||
void read(std::size_t size, char *data) override {
|
bool read(std::size_t *size, char *data) override {
|
||||||
this->_start_reading("Socket already read by another thread");
|
this->_start_reading("Socket already read by another thread");
|
||||||
this->_value.recv_stream(size, data);
|
bool closed = this->_value.recv_stream(size, data, true);
|
||||||
this->_finish_reading();
|
this->_finish_reading();
|
||||||
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(std::size_t size, char const *data) override {
|
bool write(std::size_t *size, char const *data) override {
|
||||||
this->_start_writing("Socket already written by another thread");
|
this->_start_writing("Socket already written by another thread");
|
||||||
this->_value.send_stream(size, data);
|
bool closed = this->_value.send_stream(size, data, true);
|
||||||
this->_finish_writing();
|
this->_finish_writing();
|
||||||
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() override {
|
void close() override {
|
||||||
@ -261,7 +263,9 @@ namespace LdH::Sockets::Berkeley {
|
|||||||
typename ctx_t::socket_t raw = this->_value.accept(&addr_raw);
|
typename ctx_t::socket_t raw = this->_value.accept(&addr_raw);
|
||||||
this->_finish_reading();
|
this->_finish_reading();
|
||||||
|
|
||||||
|
if (addr != nullptr)
|
||||||
*addr = std::move(_addr_internals<ctx_t>::wrap(addr_raw));
|
*addr = std::move(_addr_internals<ctx_t>::wrap(addr_raw));
|
||||||
|
|
||||||
return _socket_internals<StreamSocket<ctx_t> >::wrap(std::move(raw));
|
return _socket_internals<StreamSocket<ctx_t> >::wrap(std::move(raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -135,7 +135,8 @@ namespace LdH::Sockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
socket_t accept(address_t *addr) {
|
socket_t accept(address_t *addr) {
|
||||||
SOCKET sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), nullptr);
|
int addrlen = sizeof(sockaddr_storage);
|
||||||
|
SOCKET sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), &addrlen);
|
||||||
if (sock == INVALID_SOCKET) {
|
if (sock == INVALID_SOCKET) {
|
||||||
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
||||||
}
|
}
|
||||||
@ -149,27 +150,41 @@ namespace LdH::Sockets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_stream(std::size_t size, char const *data) {
|
bool send_stream(std::size_t *size, char const *data, bool repeat) {
|
||||||
|
size_t expected_size = *size;
|
||||||
|
*size = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
std::size_t sent_count = ::send(this->_value, data, size, 0);
|
std::size_t sent_count = ::send(this->_value, data, expected_size, 0);
|
||||||
if (sent_count == SOCKET_ERROR) {
|
if (sent_count == SOCKET_ERROR) {
|
||||||
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
data += sent_count;
|
data += sent_count;
|
||||||
size -= sent_count;
|
expected_size -= sent_count;
|
||||||
if (size <= 0) return;
|
*size += sent_count;
|
||||||
|
if (expected_size <= 0) return false;
|
||||||
|
if (!repeat) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recv_stream(std::size_t size, char *data) {
|
bool recv_stream(std::size_t *size, char *data, bool repeat) {
|
||||||
|
size_t expected_size = *size;
|
||||||
|
*size = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
std::size_t sent_count = ::recv(this->_value, data, size, 0);
|
std::size_t read_count = ::recv(this->_value, data, expected_size, 0);
|
||||||
if (sent_count == SOCKET_ERROR) {
|
switch (read_count) {
|
||||||
|
case SOCKET_ERROR:
|
||||||
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
data += sent_count;
|
data += read_count;
|
||||||
size -= sent_count;
|
expected_size -= read_count;
|
||||||
if (size <= 0) return;
|
*size += read_count;
|
||||||
|
if (expected_size <= 0) return false;
|
||||||
|
if (!repeat) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,13 +195,14 @@ namespace LdH::Sockets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
address_t recv_datagram(std::size_t size, char *data) {
|
address_t recv_datagram(std::size_t *size, char *data) {
|
||||||
address_t out;
|
address_t out;
|
||||||
int out_size = sizeof(out);
|
int out_size = sizeof(out);
|
||||||
int sent_count = ::recvfrom(this->_value, data, size, 0, reinterpret_cast<sockaddr *>(&out), &out_size);
|
int sent_count = ::recvfrom(this->_value, data, *size, 0, reinterpret_cast<sockaddr *>(&out), &out_size);
|
||||||
if (sent_count == SOCKET_ERROR) {
|
if (sent_count == SOCKET_ERROR) {
|
||||||
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
LdH::throwFromWindowsErrCode(WSAGetLastError());
|
||||||
}
|
}
|
||||||
|
*size = sent_count;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import std;
|
|||||||
namespace LdH::Streams {
|
namespace LdH::Streams {
|
||||||
export class OutputStream {
|
export class OutputStream {
|
||||||
public:
|
public:
|
||||||
virtual void write(std::size_t, char const *) = 0;
|
virtual bool write(std::size_t *, char const *) = 0;
|
||||||
|
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ namespace LdH::Streams {
|
|||||||
|
|
||||||
export class InputStream {
|
export class InputStream {
|
||||||
public:
|
public:
|
||||||
virtual void read(std::size_t, char *) = 0;
|
virtual bool read(std::size_t *, char *) = 0;
|
||||||
|
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ namespace LdH::Streams {
|
|||||||
|
|
||||||
export class InputMessanger {
|
export class InputMessanger {
|
||||||
public:
|
public:
|
||||||
virtual void recvOneTruncating(std::size_t, char *) = 0;
|
virtual void recvOneTruncating(std::size_t *, char *) = 0;
|
||||||
|
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
|
|||||||
17
programs/lab34/CMakeLists.txt
Normal file
17
programs/lab34/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
add_library(lab34_ping_ OBJECT src/_ping.cpp src/variant.hpp)
|
||||||
|
target_link_libraries(lab34_ping_ PRIVATE sockets exceptions)
|
||||||
|
|
||||||
|
add_executable(lab34_ping_tcp src/ping_tcp.cpp)
|
||||||
|
target_link_libraries(lab34_ping_tcp PRIVATE lab34_ping_)
|
||||||
|
|
||||||
|
add_executable(lab34_ping_udp src/ping_udp.cpp)
|
||||||
|
target_link_libraries(lab34_ping_udp PRIVATE lab34_ping_)
|
||||||
|
|
||||||
|
add_library(lab34_pong_ OBJECT ./src/pong.cpp src/variant.hpp)
|
||||||
|
target_link_libraries(lab34_pong_ PRIVATE sockets exceptions)
|
||||||
|
|
||||||
|
add_executable(lab34_pong_tcp src/pong_tcp.cpp)
|
||||||
|
target_link_libraries(lab34_pong_tcp PRIVATE lab34_pong_)
|
||||||
|
|
||||||
|
add_executable(lab34_pong_udp src/pong_udp.cpp)
|
||||||
|
target_link_libraries(lab34_pong_udp PRIVATE lab34_pong_)
|
||||||
104
programs/lab34/src/_ping.cpp
Normal file
104
programs/lab34/src/_ping.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import std;
|
||||||
|
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
||||||
|
import ru.landgrafhomyak.BGTU.networks_1.sockets;
|
||||||
|
|
||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <Protocol>
|
||||||
|
class PingVariant
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class PingVariant<Protocol::TCP>
|
||||||
|
{
|
||||||
|
using socket_t = LdH::Sockets::StreamSocket;
|
||||||
|
|
||||||
|
static socket_t connect(LdH::Sockets::Address& addr)
|
||||||
|
{
|
||||||
|
return LdH::Sockets::connect_tcp(addr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Protocol PING_TYPE>
|
||||||
|
int ping_main(int argc, char const* const* argv)
|
||||||
|
{
|
||||||
|
int ret_v;
|
||||||
|
bool was_error = true;
|
||||||
|
LdH::run_catching_main([&]
|
||||||
|
{
|
||||||
|
if (argc != 3 && argc != 4)
|
||||||
|
{
|
||||||
|
std::cout << "Wrong CLI arguments count: " << (argc - 1) << "\n";
|
||||||
|
std::cout << "Usage: " << argv[0] << " {dst_addr} {payload}" << std::endl;
|
||||||
|
std::cout << "Usage: " << argv[0] << " {dst_addr} {port/service} {payload}" << std::endl;
|
||||||
|
ret_v = 1, was_error = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t payload_size = std::strlen(argv[(argc == 3 ? 2 : 3)]);
|
||||||
|
|
||||||
|
if (payload_size > 255)
|
||||||
|
{
|
||||||
|
std::cout << "Payloand too long: " << payload_size << "\n";
|
||||||
|
std::cout << "Maximum payload size is 255" << std::endl;
|
||||||
|
ret_v = 1, was_error = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char payload[256];
|
||||||
|
payload[0] = static_cast<unsigned char>(payload_size);
|
||||||
|
std::memcpy(payload + 1, argv[(argc == 3 ? 2 : 3)], payload_size);
|
||||||
|
payload_size++;
|
||||||
|
|
||||||
|
|
||||||
|
LdH::Sockets::init_sockets();
|
||||||
|
auto dst = LdH::Sockets::Address::parse(argv[1], (argc == 3 ? nullptr : argv[2]));
|
||||||
|
|
||||||
|
|
||||||
|
if constexpr (PING_TYPE == Protocol::TCP)
|
||||||
|
{
|
||||||
|
auto sock = LdH::Sockets::connect_tcp(dst);
|
||||||
|
|
||||||
|
sock.write(&payload_size, payload);
|
||||||
|
std::cout << "Sent " << payload_size << " bytes\nReceiving:\n\n";
|
||||||
|
std::cout.flush();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char buff[1024];
|
||||||
|
std::size_t buff_size = sizeof(buff);
|
||||||
|
bool is_closed = sock.read(&buff_size, buff);
|
||||||
|
std::cout << std::string{buff, buff_size};
|
||||||
|
if (is_closed) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock.close();
|
||||||
|
ret_v = 0, was_error = false;
|
||||||
|
}
|
||||||
|
else if constexpr (PING_TYPE == Protocol::UDP)
|
||||||
|
{
|
||||||
|
auto sock = LdH::Sockets::connect_udp(dst);
|
||||||
|
|
||||||
|
sock.sendOne(payload_size, payload);
|
||||||
|
std::cout << "Sent " << payload_size << " bytes\nReceiving:\n\n";
|
||||||
|
std::cout.flush();
|
||||||
|
|
||||||
|
char buff[65536];
|
||||||
|
std::size_t buff_size = sizeof(buff);
|
||||||
|
sock.recvOneTruncating(&buff_size, buff);
|
||||||
|
std::cout << std::string{buff, buff_size};
|
||||||
|
|
||||||
|
sock.close();
|
||||||
|
ret_v = 0, was_error = false;
|
||||||
|
}
|
||||||
|
LdH::Sockets::deinit_sockets();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (was_error)
|
||||||
|
return 3;
|
||||||
|
return ret_v;
|
||||||
|
}
|
||||||
5
programs/lab34/src/ping_tcp.cpp
Normal file
5
programs/lab34/src/ping_tcp.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char const *const*argv) {
|
||||||
|
return ping_main<Protocol::TCP>(argc, argv);
|
||||||
|
}
|
||||||
5
programs/lab34/src/ping_udp.cpp
Normal file
5
programs/lab34/src/ping_udp.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char const *const*argv) {
|
||||||
|
return ping_main<Protocol::UDP>(argc, argv);
|
||||||
|
}
|
||||||
160
programs/lab34/src/pong.cpp
Normal file
160
programs/lab34/src/pong.cpp
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import std;
|
||||||
|
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
||||||
|
import ru.landgrafhomyak.BGTU.networks_1.sockets;
|
||||||
|
|
||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class ByteCounter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::size_t bytes[std::numeric_limits<char>::max() - std::numeric_limits<char>::min() + 1];
|
||||||
|
|
||||||
|
public:
|
||||||
|
ByteCounter() : bytes{}
|
||||||
|
{
|
||||||
|
for (auto& e : this->bytes)
|
||||||
|
{
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t& operator[](char c)
|
||||||
|
{
|
||||||
|
return this->bytes[c - std::numeric_limits<char>::min()];
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(char const* payload, std::size_t count)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < count; i++)
|
||||||
|
this->operator[](payload[i])++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(std::ostream& out)
|
||||||
|
{
|
||||||
|
for (char c = std::numeric_limits<char>::min(); c < std::numeric_limits<char>::max(); c++)
|
||||||
|
{
|
||||||
|
if (this->operator[](c) != 0)
|
||||||
|
{
|
||||||
|
out << static_cast<int>(c) << ": " << this->operator[](c) << " times\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this->operator[](std::numeric_limits<char>::max()) != 0)
|
||||||
|
{
|
||||||
|
out << static_cast<int>(std::numeric_limits<char>::max()) << ": " << this->operator[](
|
||||||
|
std::numeric_limits<char>::max()) << " times\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void do_tcp(LdH::Sockets::Address& listen_addr)
|
||||||
|
{
|
||||||
|
auto server = LdH::Sockets::listen_tcp(listen_addr, 10);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
LdH::Sockets::Address addr;
|
||||||
|
auto sock = server.wait_for_connection(&addr);
|
||||||
|
std::cout << "Connection from " << addr.to_string() << std::endl;
|
||||||
|
|
||||||
|
std::size_t read_count;
|
||||||
|
bool closed;
|
||||||
|
|
||||||
|
char payload_size;
|
||||||
|
read_count = 1;
|
||||||
|
closed = sock.read(&read_count, &payload_size);
|
||||||
|
if (closed)
|
||||||
|
{
|
||||||
|
sock.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char payload[255];
|
||||||
|
read_count = static_cast<unsigned char>(payload_size);
|
||||||
|
closed = sock.read(&read_count, payload);
|
||||||
|
if (closed)
|
||||||
|
{
|
||||||
|
sock.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteCounter counter;
|
||||||
|
counter.apply(payload, read_count);
|
||||||
|
|
||||||
|
std::stringstream resp_builder;
|
||||||
|
resp_builder << "Bytes summary:\n";
|
||||||
|
counter.print(resp_builder);
|
||||||
|
|
||||||
|
auto resp = resp_builder.str();
|
||||||
|
read_count = resp.length();
|
||||||
|
|
||||||
|
sock.write(&read_count, resp.c_str());
|
||||||
|
|
||||||
|
sock.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_udp(LdH::Sockets::Address& listen_addr)
|
||||||
|
{
|
||||||
|
auto server = LdH::Sockets::listen_udp(listen_addr);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char payload[65536];
|
||||||
|
std::size_t read_count = 65536;
|
||||||
|
LdH::Sockets::Address addr = server.recvOneTruncating(&read_count, payload);
|
||||||
|
|
||||||
|
std::cout << "Connection from " << addr.to_string() << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
ByteCounter counter;
|
||||||
|
counter.apply(payload, read_count);
|
||||||
|
|
||||||
|
std::stringstream resp_builder;
|
||||||
|
resp_builder << "Bytes summary:\n";
|
||||||
|
counter.print(resp_builder);
|
||||||
|
|
||||||
|
auto resp = resp_builder.str();
|
||||||
|
read_count = resp.length();
|
||||||
|
|
||||||
|
server.sendOne(addr, read_count, resp.c_str());
|
||||||
|
}
|
||||||
|
server.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Protocol PROTOCOL>
|
||||||
|
int pong_main(int argc, char const* const* argv)
|
||||||
|
{
|
||||||
|
int ret_v;
|
||||||
|
bool was_error = true;
|
||||||
|
LdH::run_catching_main([&]
|
||||||
|
{
|
||||||
|
if (argc != 2 && argc != 3)
|
||||||
|
{
|
||||||
|
std::cout << "Wrong CLI arguments count: " << (argc - 1) << "\n";
|
||||||
|
std::cout << "Usage: " << argv[0] << " {listen_addr}" << std::endl;
|
||||||
|
std::cout << "Usage: " << argv[0] << " {listen_addr} {port/service}" << std::endl;
|
||||||
|
ret_v = 1, was_error = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LdH::Sockets::init_sockets();
|
||||||
|
|
||||||
|
auto addr = LdH::Sockets::Address::parse(argv[1], (argc == 2 ? nullptr : argv[2]));
|
||||||
|
|
||||||
|
if constexpr (PROTOCOL == Protocol::TCP)
|
||||||
|
{
|
||||||
|
do_tcp(addr);
|
||||||
|
}
|
||||||
|
else if constexpr (PROTOCOL == Protocol::UDP)
|
||||||
|
{
|
||||||
|
do_udp(addr);
|
||||||
|
}
|
||||||
|
LdH::Sockets::deinit_sockets();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (was_error)
|
||||||
|
return 3;
|
||||||
|
return ret_v;
|
||||||
|
}
|
||||||
5
programs/lab34/src/pong_tcp.cpp
Normal file
5
programs/lab34/src/pong_tcp.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char const *const*argv) {
|
||||||
|
return pong_main<Protocol::TCP>(argc, argv);
|
||||||
|
}
|
||||||
5
programs/lab34/src/pong_udp.cpp
Normal file
5
programs/lab34/src/pong_udp.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "variant.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char const *const*argv) {
|
||||||
|
return pong_main<Protocol::UDP>(argc, argv);
|
||||||
|
}
|
||||||
25
programs/lab34/src/variant.hpp
Normal file
25
programs/lab34/src/variant.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class Protocol {
|
||||||
|
TCP,
|
||||||
|
UDP,
|
||||||
|
};
|
||||||
|
|
||||||
|
template<Protocol>
|
||||||
|
extern int ping_main(int argc, char const* const* argv);
|
||||||
|
|
||||||
|
template
|
||||||
|
int ping_main<Protocol::TCP>(int, char const* const*);
|
||||||
|
|
||||||
|
template
|
||||||
|
int ping_main<Protocol::UDP>(int, char const* const*);
|
||||||
|
|
||||||
|
|
||||||
|
template<Protocol>
|
||||||
|
extern int pong_main(int argc, char const* const* argv);
|
||||||
|
|
||||||
|
template
|
||||||
|
int pong_main<Protocol::TCP>(int, char const* const*);
|
||||||
|
|
||||||
|
template
|
||||||
|
int pong_main<Protocol::UDP>(int, char const* const*);
|
||||||
@ -1,5 +0,0 @@
|
|||||||
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)
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
|
|
||||||
#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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
|
|
||||||
#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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
|
|
||||||
#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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user