201 lines
5.0 KiB
C++
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);
|
|
}
|
|
}
|