Skip to content
Snippets Groups Projects
Commit 3d43918d authored by Florian Fischer's avatar Florian Fischer
Browse files

Add callback based EchoServer implementation

parent 827b79ae
No related branches found
No related tags found
No related merge requests found
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2020-2021 Florian Fischer
#include <sys/socket.h>
#include <array>
#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include "Common.hpp"
#include "Debug.hpp"
#include "Runtime.hpp"
#include "io.hpp"
#include "io/Future.hpp"
using SendFuture = emper::io::SendFuture;
using RecvFuture = emper::io::RecvFuture;
const std::string HOST = "::";
const std::string PORT = "12345";
const size_t BUF_SIZE = 1024;
class Client {
public:
int sockfd;
size_t bytes_recv;
size_t bytes_send;
std::array<char, BUF_SIZE> buf;
Client(int socket) : sockfd(socket), bytes_recv(0), bytes_send(0) {}
void submitSend() {
SendFuture sf(sockfd, &buf[bytes_send], bytes_recv - bytes_send, MSG_NOSIGNAL);
sf.setCallback([this](int32_t bytes_send) { this->onSend(bytes_send); });
sf.submit();
}
void onSend(int32_t res) {
if (unlikely(res < 0)) {
LOGE("server send failed: " << strerror(errno));
emper::io::closeAndForget(sockfd);
return;
}
bytes_send += res;
// Send again
if (bytes_send < bytes_recv) {
submitSend();
return;
}
submitRecv();
}
void submitRecv() {
bytes_send = 0;
RecvFuture rf(sockfd, buf.data(), BUF_SIZE, 0);
rf.setCallback([this](int32_t bytes_recv) { this->onRecv(bytes_recv); });
rf.submit();
}
void onRecv(int32_t res) {
if (unlikely(res <= 0)) {
// socket was shutdown
if (res < 0) {
LOGE("server read failed:" << strerror(errno));
}
emper::io::closeAndForget(sockfd);
return;
}
bytes_recv = res;
if (unlikely(bytes_recv == 5 && strncmp("quit\n", buf.data(), bytes_recv) == 0)) {
exit(EXIT_SUCCESS);
}
submitSend();
}
};
auto main(int argc, char* argv[]) -> int {
std::string host = HOST;
std::string port = PORT;
if (argc > 2) {
std::cerr << "Usage: " << argv[0] << " [port]" << std::endl;
exit(EXIT_FAILURE);
}
if (argc > 1) {
port = std::string(argv[1]);
}
std::cout << "Echoserver listening on " << host << ":" << port << std::endl;
Runtime runtime;
auto* listener = emper::io::tcp_listener(host, port, [](int socket) {
auto* client = new Client(socket);
client->submitRecv();
});
if (!listener) {
exit(EXIT_FAILURE);
}
runtime.scheduleFromAnywhere(*listener);
runtime.waitUntilFinished();
return EXIT_FAILURE;
}
......@@ -16,6 +16,12 @@ echoserver_exe = executable(
dependencies: emper_dep,
)
echoserver_callback_exe = executable(
'echoserver_callback',
'EchoServerCallback.cpp',
dependencies: emper_dep,
)
echoclient_exe = executable(
'echoclient',
'EchoClient.cpp',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment