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(&(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(&(addr._value)), sizeof(sockaddr))) LdH::throwFromWindowsErrCode(WSAGetLastError()); } void bind(address_t addr) { if (0 != ::bind(this->_value, reinterpret_cast(&(addr._value)), sizeof(sockaddr))) LdH::throwFromWindowsErrCode(WSAGetLastError()); } socket_t accept(address_t *addr) { SOCKET sock = ::accept(this->_value, reinterpret_cast(&(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 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); } }