diff --git a/socket.cpp b/socket.cpp new file mode 100644 index 0000000..850c20f --- /dev/null +++ b/socket.cpp @@ -0,0 +1,206 @@ +#include + +#include +#include +#include + +#include + +#pragma comment(lib, "ws2_32.lib") + +struct WSA { + WSADATA wsa; + + explicit WSA(WORD version = MAKEWORD(2, 2)) { + int result = WSAStartup(version, &wsa); + if (result) throw result; + } + ~WSA() noexcept { + WSACleanup(); + } +}; + +struct AddrInfoPtr { + struct addrinfo *info; + + AddrInfoPtr() noexcept: + info(nullptr) {} + + ~AddrInfoPtr() noexcept { + freeaddrinfo(info); + } + + auto operator->() noexcept { + return info; + } + + auto operator&() noexcept { + return &info; + } + + auto& operator*() noexcept { + return *info; + } + + const auto& operator*() const noexcept { + return *info; + } + + operator addrinfo*() noexcept { + return info; + } +}; + +struct AddrInfo { + struct addrinfo info; + + AddrInfo() noexcept { + ZeroMemory(&info, sizeof(info)); + } + ~AddrInfo() noexcept = default; + + auto operator->() noexcept { + return &info; + } + + auto operator&() noexcept { + return &info; + } + + operator const addrinfo&() const noexcept { + return info; + } + + operator addrinfo&() noexcept { + return info; + } + + auto get_addrinfo(PCSTR node, PCSTR service) { + AddrInfoPtr ptr; + int result = getaddrinfo(node, service, &info, &ptr); + if (result == SOCKET_ERROR) throw result; + return ptr; + } +}; + +struct Socket { + enum AddrAction { + NO_ACTION, + CONNECT, + BIND, + }; + + SOCKET s; + + explicit Socket(SOCKET init = INVALID_SOCKET) noexcept: + s(init) {} + + ~Socket() noexcept { + closesocket(s); + } + + operator SOCKET() const noexcept { + return s; + } + + bool is_valid() const noexcept { + return s != INVALID_SOCKET; + } + + explicit operator bool() const noexcept { + return is_valid(); + } + + void from_addrinfo(const struct addrinfo &info, AddrAction action = NO_ACTION) { + s = socket(info.ai_family, info.ai_socktype, info.ai_protocol); + if (s == INVALID_SOCKET) throw -1; + + switch (action) { + case NO_ACTION: + break; + case CONNECT: + int result = connect(s, info.ai_addr, (int)info.ai_addrlen); + if (result == SOCKET_ERROR) throw result; + break; + case BIND: + int result = bind(s, info.ai_addr, (int)info.ai_addrlen); + if (result == SOCKET_ERROR) throw result; + result = listen(s, SOMAXCONN); + if (result == SOCKET_ERROR) throw result; + break; + } + } + + Socket accept_client() const noexcept { + return Socket(accept(s, NULL, NULL)); + } +}; + +struct Connection { + Socket s; + struct sockaddr addr; + + explicit Connection(Socket listen) noexcept { + int len = 0; + s = Socket(accept(listen, &addr, &len)); + } + + void stop_send() const { + int result = shutdown(s, SD_SEND); + if (result == SOCKET_ERROR) throw result; + } + + int send_data(const Buffer &data) const { + return send(s, data.get(), data.len(), 0); + } +}; + +struct Buffer { + std::unique_ptr data; + int size; + + Buffer(int len): + size(len), data(new char[len]) {} + + const char* get() const { + return data.get(); + } + + char* get() { + return data.get(); + } + + int len() const { + return size; + } +}; + +int main(int argc, char **argv) try { + int iResult = 0; + + WSA wsa; + + AddrInfoPtr ptr; + AddrInfo hints; + + hints->ai_family = AF_INET; + hints->ai_socktype = SOCK_STREAM; + hints->ai_protocol = IPPROTO_TCP; + hints->ai_flags = AI_PASSIVE; + + AddrInfoPtr result = hints.get_addrinfo(NULL, "8088"); + + Socket listen_socket; + + listen_socket.from_addrinfo(*ptr, Socket::BIND); + + Connection conn(listen_socket); + + return 0; +} +catch (const int &err) { + return err; +} +catch (...) { + return -1; +}