Condy v1.3.0
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
echo-server.cpp
Go to the documentation of this file.
1
5
6#include <arpa/inet.h>
7#include <condy.hpp>
8#include <cstdint>
9#include <cstdio>
10#include <cstring>
11#include <netinet/in.h>
12#include <sys/socket.h>
13#include <unistd.h>
14
15constexpr size_t BACKLOG = 128;
16constexpr size_t MAX_CONNECTIONS = 1024;
17constexpr size_t MAX_MESSAGE_LEN = 2048;
18
19condy::Coro<void> session(int client_fd) {
20 char buffer[MAX_MESSAGE_LEN];
21
22 while (true) {
23 int n = co_await condy::async_recv(condy::fixed(client_fd),
24 condy::buffer(buffer), 0);
25 if (n <= 0) {
26 if (n < 0) {
27 std::fprintf(stderr, "Read error: %d\n", n);
28 }
29 break;
30 }
31
32 n = co_await condy::async_send(condy::fixed(client_fd),
33 condy::buffer(buffer, n), 0);
34 if (n < 0) {
35 std::fprintf(stderr, "Write error: %d\n", n);
36 break;
37 }
38 }
39
40 co_await condy::async_close(condy::fixed(client_fd));
41}
42
43condy::Coro<int> co_main(int server_fd) {
44 while (true) {
45 sockaddr_in client_addr;
46 socklen_t client_len = sizeof(client_addr);
47 int client_fd = co_await condy::async_accept_direct(
48 server_fd, (struct sockaddr *)&client_addr, &client_len, 0,
50 if (client_fd < 0) {
51 std::fprintf(stderr, "Failed to accept connection: %d\n",
52 client_fd);
53 co_return 1;
54 }
55
56 condy::co_spawn(session(client_fd)).detach();
57 }
58}
59
60void prepare_address(const std::string &host, uint16_t port,
61 sockaddr_in &addr) {
62 memset(&addr, 0, sizeof(addr));
63 addr.sin_family = AF_INET;
64 addr.sin_port = htons(port);
65 inet_pton(AF_INET, host.c_str(), &addr.sin_addr);
66}
67
68int main(int argc, char **argv) noexcept(false) {
69 if (argc < 3) {
70 std::fprintf(stderr, "Usage: %s <host> <port>\n", argv[0]);
71 return 1;
72 }
73
74 std::string host = argv[1];
75 uint16_t port = static_cast<uint16_t>(std::stoi(argv[2]));
76
77 sockaddr_in server_addr;
78 prepare_address(host, port, server_addr);
79
80 int server_fd = socket(AF_INET, SOCK_STREAM, 0);
81 if (server_fd < 0) {
82 std::perror("Failed to create socket");
83 return 1;
84 }
85
86 if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) <
87 0) {
88 std::perror("Failed to bind socket");
89 close(server_fd);
90 return 1;
91 }
92
93 if (listen(server_fd, BACKLOG) < 0) {
94 std::perror("Failed to listen on socket");
95 close(server_fd);
96 return 1;
97 }
98
99 std::printf("Echo server listening on %s:%d\n", host.c_str(), port);
100
101 condy::Runtime runtime(condy::RuntimeOptions().sq_size(MAX_CONNECTIONS));
102
103 runtime.fd_table().init(MAX_CONNECTIONS);
104
105 return condy::sync_wait(runtime, co_main(server_fd));
106}
Coroutine type used to define a coroutine function.
Definition coro.hpp:26
The event loop runtime for executing asynchronous.
Definition runtime.hpp:76
Main include file for the Condy library.
#define CONDY_FILE_INDEX_ALLOC
Placeholder to let io_uring allocate a direct file descriptor.
Definition helpers.hpp:20
T sync_wait(Runtime &runtime, Coro< T, Allocator > coro)
Synchronously wait for a coroutine to complete in the given runtime.
Definition sync_wait.hpp:24
auto async_recv(Fd sockfd, Buffer &&buf, int flags)
See io_uring_prep_recv.
auto fixed(int fd)
Mark a file descriptor as fixed for io_uring operations.
Definition helpers.hpp:98
MutableBuffer buffer(void *data, size_t size)
Create a buffer object from various data sources.
Definition buffers.hpp:84
auto async_close(int fd)
See io_uring_prep_close.
auto async_send(Fd sockfd, Buffer &&buf, int flags)
See io_uring_prep_send.
auto async_accept_direct(Fd fd, struct sockaddr *addr, socklen_t *addrlen, int flags, unsigned int file_index)
See io_uring_prep_accept_direct.
Task< T, Allocator > co_spawn(Runtime &runtime, Coro< T, Allocator > coro)
Spawn a coroutine as a task in the given runtime.
Definition task.hpp:240