207 lines
3.9 KiB
C++
207 lines
3.9 KiB
C++
#include <stdio.h>
|
|
|
|
#include <WinSock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <iphlpapi.h>
|
|
|
|
#include <memory>
|
|
|
|
#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<char[]> 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;
|
|
}
|