add simple inefficient server socket implementation (WIP)

This commit is contained in:
MihailRis
2024-11-27 15:38:57 +03:00
parent 233bc3174c
commit a72d36f53c
3 changed files with 164 additions and 11 deletions
+16 -1
View File
@@ -42,7 +42,9 @@ static int l_connect(lua::State* L) {
lua::pushvalue(L, 3); lua::pushvalue(L, 3);
auto callback = lua::create_lambda(L); auto callback = lua::create_lambda(L);
u64id_t id = engine->getNetwork().connect(address, port, [callback](u64id_t id) { u64id_t id = engine->getNetwork().connect(address, port, [callback](u64id_t id) {
callback({id}); engine->postRunnable([=]() {
callback({id});
});
}); });
return lua::pushinteger(L, id); return lua::pushinteger(L, id);
} }
@@ -109,9 +111,22 @@ static int l_recv(lua::State* L) {
return 1; return 1;
} }
static int l_open(lua::State* L) {
int port = lua::tointeger(L, 1);
lua::pushvalue(L, 2);
auto callback = lua::create_lambda(L);
u64id_t id = engine->getNetwork().openServer(port, [callback](u64id_t id) {
engine->postRunnable([=]() {
callback({id});
});
});
return lua::pushinteger(L, id);
}
const luaL_Reg networklib[] = { const luaL_Reg networklib[] = {
{"get", lua::wrap<l_get>}, {"get", lua::wrap<l_get>},
{"get_binary", lua::wrap<l_get_binary>}, {"get_binary", lua::wrap<l_get_binary>},
{"__open", lua::wrap<l_open>},
{"__connect", lua::wrap<l_connect>}, {"__connect", lua::wrap<l_connect>},
{"__close", lua::wrap<l_close>}, {"__close", lua::wrap<l_close>},
{"__send", lua::wrap<l_send>}, {"__send", lua::wrap<l_send>},
+131 -10
View File
@@ -244,18 +244,26 @@ static inline int sendsocket(
return send(descriptor, buf, len, flags); return send(descriptor, buf, len, flags);
} }
static std::string to_string(const sockaddr_in* addr) {
char ip[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN)) {
return std::string(ip)+":"+std::to_string(addr->sin_port);
}
return "";
}
static std::string to_string(const addrinfo* addr) { static std::string to_string(const addrinfo* addr) {
if (addr->ai_family == AF_INET) { if (addr->ai_family == AF_INET) {
auto psai = reinterpret_cast<sockaddr_in*>(addr->ai_addr); auto psai = reinterpret_cast<sockaddr_in*>(addr->ai_addr);
char ip[INET_ADDRSTRLEN]; char ip[INET_ADDRSTRLEN];
if (inet_ntop(addr->ai_family, &(psai->sin_addr), ip, INET_ADDRSTRLEN)) { if (inet_ntop(addr->ai_family, &(psai->sin_addr), ip, INET_ADDRSTRLEN)) {
return std::string(ip); return std::string(ip)+":"+std::to_string(psai->sin_port);
} }
} else if (addr->ai_family == AF_INET6) { } else if (addr->ai_family == AF_INET6) {
auto psai = reinterpret_cast<sockaddr_in6*>(addr->ai_addr); auto psai = reinterpret_cast<sockaddr_in6*>(addr->ai_addr);
char ip[INET6_ADDRSTRLEN]; char ip[INET6_ADDRSTRLEN];
if (inet_ntop(addr->ai_family, &(psai->sin6_addr), ip, INET6_ADDRSTRLEN)) { if (inet_ntop(addr->ai_family, &(psai->sin6_addr), ip, INET6_ADDRSTRLEN)) {
return std::string(ip); return std::string(ip)+":"+std::to_string(psai->sin6_port);
} }
} }
return ""; return "";
@@ -265,6 +273,7 @@ class SocketConnection : public Connection {
SOCKET descriptor; SOCKET descriptor;
bool open = true; bool open = true;
addrinfo* addr; addrinfo* addr;
std::string addrString;
size_t totalUpload = 0; size_t totalUpload = 0;
size_t totalDownload = 0; size_t totalDownload = 0;
ConnectionState state = ConnectionState::INITIAL; ConnectionState state = ConnectionState::INITIAL;
@@ -288,8 +297,8 @@ class SocketConnection : public Connection {
state = ConnectionState::CONNECTED; state = ConnectionState::CONNECTED;
} }
public: public:
SocketConnection(SOCKET descriptor, addrinfo* addr) SocketConnection(SOCKET descriptor, addrinfo* addr, const std::string& addrString)
: descriptor(descriptor), addr(addr), buffer(16'384) {} : descriptor(descriptor), addr(addr), addrString(addrString), buffer(16'384) {}
~SocketConnection() { ~SocketConnection() {
if (state != ConnectionState::CLOSED) { if (state != ConnectionState::CLOSED) {
@@ -299,7 +308,9 @@ public:
if (thread) { if (thread) {
thread->join(); thread->join();
} }
freeaddrinfo(addr); if (addr) {
freeaddrinfo(addr);
}
} }
void connect(runnable callback) override { void connect(runnable callback) override {
@@ -352,8 +363,8 @@ public:
int err = errno; int err = errno;
close(); close();
throw std::runtime_error( throw std::runtime_error(
"Send failed [errno=" + std::to_string(err) + "Send failed [errno=" + std::to_string(err) + "]: "
"]: " + std::string(strerror(err)) + std::string(strerror(err))
); );
} }
totalUpload += len; totalUpload += len;
@@ -370,8 +381,10 @@ public:
shutdown(descriptor, 2); shutdown(descriptor, 2);
closesocket(descriptor); closesocket(descriptor);
} }
thread->join(); if (thread) {
thread = nullptr; thread->join();
thread = nullptr;
}
} }
size_t getTotalUpload() const override { size_t getTotalUpload() const override {
@@ -403,7 +416,7 @@ public:
freeaddrinfo(addrinfo); freeaddrinfo(addrinfo);
throw std::runtime_error("Could not create socket"); throw std::runtime_error("Could not create socket");
} }
auto socket = std::make_shared<SocketConnection>(descriptor, addrinfo); auto socket = std::make_shared<SocketConnection>(descriptor, addrinfo, to_string(addrinfo));
socket->connect(std::move(callback)); socket->connect(std::move(callback));
return socket; return socket;
} }
@@ -413,6 +426,101 @@ public:
} }
}; };
class SocketTcpSServer : public TcpServer {
Network* network;
SOCKET descriptor;
std::vector<u64id_t> clients;
bool open = true;
std::unique_ptr<std::thread> thread = nullptr;
public:
SocketTcpSServer(Network* network, SOCKET descriptor)
: network(network), descriptor(descriptor) {}
~SocketTcpSServer() {
closeSocket();
}
void startListen(consumer<u64id_t> handler) override {
thread = std::make_unique<std::thread>([this, handler]() {
while (open) {
logger.info() << "listening for connections";
if (listen(descriptor, 2) < 0) {
close();
break;
}
socklen_t addrlen = sizeof(sockaddr_in);
SOCKET clientDescriptor;
sockaddr_in address;
logger.info() << "accepting clients";
if ((clientDescriptor = accept(descriptor, (sockaddr*)&address, &addrlen)) < 0) {
close();
break;
}
logger.info() << "client connected: " << to_string(&address);
auto socket = std::make_shared<SocketConnection>(
clientDescriptor, nullptr, to_string(&address)
);
u64id_t id = network->addConnection(socket);
clients.push_back(id);
handler(id);
}
});
}
void closeSocket() {
if (!open) {
return;
}
logger.info() << "closing server";
open = false;
for (u64id_t clientid : clients) {
if (auto client = network->getConnection(clientid)) {
client->close();
}
}
clients.clear();
shutdown(descriptor, 2);
closesocket(descriptor);
thread->join();
}
void close() override {
closeSocket();
}
bool isOpen() override {
return open;
}
static std::shared_ptr<SocketTcpSServer> openServer(
Network* network, int port, consumer<u64id_t> handler
) {
SOCKET descriptor = socket(
AF_INET, SOCK_STREAM, 0
);
if (descriptor == -1) {
throw std::runtime_error("Could not create server socket");
}
int opt = 1;
if (setsockopt(descriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
closesocket(descriptor);
throw std::runtime_error("setsockopt");
}
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(descriptor, (sockaddr*)&address, sizeof(address)) < 0) {
closesocket(descriptor);
throw std::runtime_error("could not bind port "+std::to_string(port));
}
logger.info() << "opened server at port " << port;
auto server = std::make_shared<SocketTcpSServer>(network, descriptor);
server->startListen(std::move(handler));
return server;
}
};
Network::Network(std::unique_ptr<Requests> requests) Network::Network(std::unique_ptr<Requests> requests)
: requests(std::move(requests)) { : requests(std::move(requests)) {
} }
@@ -445,6 +553,19 @@ u64id_t Network::connect(const std::string& address, int port, consumer<u64id_t>
return id; return id;
} }
u64id_t Network::openServer(int port, consumer<u64id_t> handler) {
u64id_t id = nextServer++;
auto server = SocketTcpSServer::openServer(this, port, handler);
servers[id] = std::move(server);
return id;
}
u64id_t Network::addConnection(const std::shared_ptr<Connection>& socket) {
u64id_t id = nextConnection++;
connections[id] = std::move(socket);
return id;
}
size_t Network::getTotalUpload() const { size_t Network::getTotalUpload() const {
size_t totalUpload = 0; size_t totalUpload = 0;
for (const auto& [_, socket] : connections) { for (const auto& [_, socket] : connections) {
+17
View File
@@ -34,6 +34,8 @@ namespace network {
class Connection { class Connection {
public: public:
virtual ~Connection() {}
virtual void connect(runnable callback) = 0; virtual void connect(runnable callback) = 0;
virtual int recv(char* buffer, size_t length) = 0; virtual int recv(char* buffer, size_t length) = 0;
virtual int send(const char* buffer, size_t length) = 0; virtual int send(const char* buffer, size_t length) = 0;
@@ -46,10 +48,21 @@ namespace network {
virtual ConnectionState getState() const = 0; virtual ConnectionState getState() const = 0;
}; };
class TcpServer {
public:
virtual ~TcpServer() {}
virtual void startListen(consumer<u64id_t> handler) = 0;
virtual void close() = 0;
virtual bool isOpen() = 0;
};
class Network { class Network {
std::unique_ptr<Requests> requests; std::unique_ptr<Requests> requests;
std::unordered_map<u64id_t, std::shared_ptr<Connection>> connections; std::unordered_map<u64id_t, std::shared_ptr<Connection>> connections;
u64id_t nextConnection = 1; u64id_t nextConnection = 1;
std::unordered_map<u64id_t, std::shared_ptr<TcpServer>> servers;
u64id_t nextServer = 1;
public: public:
Network(std::unique_ptr<Requests> requests); Network(std::unique_ptr<Requests> requests);
~Network(); ~Network();
@@ -65,6 +78,10 @@ namespace network {
u64id_t connect(const std::string& address, int port, consumer<u64id_t> callback); u64id_t connect(const std::string& address, int port, consumer<u64id_t> callback);
u64id_t openServer(int port, consumer<u64id_t> handler);
u64id_t addConnection(const std::shared_ptr<Connection>& connection);
size_t getTotalUpload() const; size_t getTotalUpload() const;
size_t getTotalDownload() const; size_t getTotalDownload() const;