networks-1.cpp/modules/sockets/src/platform/windows.cpp.inc

201 lines
5.0 KiB
C++

import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.exceptions.windows;
import ru.landgrafhomyak.BGTU.networks_1.streams;
import :berkeley_sockets;
namespace LdH::Sockets {
export
void init_sockets() {
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
if (0 != WSAStartup(wVersionRequested, &wsaData))
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
export
void deinit_sockets() {
WSACleanup();
}
struct _WinsockContext {
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;
if (0 != getaddrinfo(addr, service, nullptr, &p)) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
sockaddr_storage out;
ZeroMemory(&out, sizeof(sockaddr_storage));
CopyMemory(&out, p->ai_addr, p->ai_addrlen);
freeaddrinfo(p);
return address_t{out};
}
std::string to_string() {
char buffer[1024];
DWORD buf_size = 1024;
if (0 != WSAAddressToStringA(reinterpret_cast<sockaddr *>(&(this->_value)), sizeof(sockaddr_storage), nullptr, buffer, &buf_size)) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
return std::string{buffer, buf_size - 1};
}
};
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:
SOCKET _value;
explicit socket_t(SOCKET value) : _value{value} {
}
public:
socket_t() : _value{INVALID_SOCKET} {
}
socket_t(socket_t &&other) noexcept : _value{other._value} {
other._value = INVALID_SOCKET;
}
socket_t &operator=(socket_t &&other) noexcept {
this->_value = other._value;
other._value = INVALID_SOCKET;
return *this;
}
~socket_t() = default;
static socket_t create(address_t const &addr, int type, int proto) {
SOCKET sock = ::socket(addr._value.ss_family, type, proto);
if (sock == INVALID_SOCKET) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
return socket_t{sock};
}
void close() {
if (0 != closesocket(this->_value)) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
this->_value = INVALID_SOCKET;
}
void connect(address_t addr) {
if (0 != ::connect(this->_value, reinterpret_cast<sockaddr *>(&(addr._value)), sizeof(sockaddr)))
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
void bind(address_t addr) {
if (0 != ::bind(this->_value, reinterpret_cast<sockaddr *>(&(addr._value)), sizeof(sockaddr)))
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
socket_t accept(address_t *addr) {
SOCKET sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), nullptr);
if (sock == INVALID_SOCKET) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
return socket_t{sock};
}
void listen(std::size_t queue_size) {
if (0 != ::listen(this->_value, queue_size)) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
}
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 == SOCKET_ERROR) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
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 == SOCKET_ERROR) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
data += sent_count;
size -= sent_count;
if (size <= 0) return;
}
}
};
};
static_assert(Berkeley::BerkeleySocketsContext<_WinsockContext>);
export using Address = Berkeley::Address<_WinsockContext>;
export
template<class sock_t>
using SocketWithAddress = Berkeley::SocketWithAddress<_WinsockContext, sock_t>;
export using StreamSocket = Berkeley::StreamSocket<_WinsockContext>;
export using StreamSocketsServer = Berkeley::StreamSocketsServer<_WinsockContext>;
export
StreamSocket connect_tcp(Address addr) {
return Berkeley::connect_tcp<_WinsockContext>(addr);
}
export
StreamSocketsServer listen_tcp(Address addr, std::size_t queue_size) {
return Berkeley::listen_tcp<_WinsockContext>(addr, queue_size);
}
}