Condy v1.5.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 <format>
12#include <iostream>
13#include <netinet/in.h>
14#include <sys/socket.h>
15#include <unistd.h>
16
17constexpr size_t BACKLOG = 128;
18constexpr size_t MAX_CONNECTIONS = 1024;
19constexpr size_t MAX_MESSAGE_LEN = 2048;
20
21condy::Coro<void> session(int client_fd) {
22 char buffer[MAX_MESSAGE_LEN];
23
24 while (true) {
25 int n = co_await condy::async_recv(condy::fixed(client_fd),
26 condy::buffer(buffer), 0);
27 if (n <= 0) {
28 if (n < 0) {
29 std::cerr << std::format("Read error: {}\n", n);
30 }
31 break;
32 }
33
34 n = co_await condy::async_send(condy::fixed(client_fd),
35 condy::buffer(buffer, n), 0);
36 if (n < 0) {
37 std::cerr << std::format("Write error: {}\n", n);
38 break;
39 }
40 }
41
42 co_await condy::async_close(condy::fixed(client_fd));
43}
44
45condy::Coro<int> co_main(int server_fd) {
46 while (true) {
47 sockaddr_in client_addr;
48 socklen_t client_len = sizeof(client_addr);
49 int client_fd = co_await condy::async_accept_direct(
50 server_fd, (struct sockaddr *)&client_addr, &client_len, 0,
52 if (client_fd < 0) {
53 std::cerr << std::format("Failed to accept connection: {}\n",
54 client_fd);
55 co_return 1;
56 }
57
58 condy::co_spawn(session(client_fd)).detach();
59 }
60}
61
62void prepare_address(const std::string &host, uint16_t port,
63 sockaddr_in &addr) {
64 memset(&addr, 0, sizeof(addr));
65 addr.sin_family = AF_INET;
66 addr.sin_port = htons(port);
67 inet_pton(AF_INET, host.c_str(), &addr.sin_addr);
68}
69
70int main(int argc, char **argv) noexcept(false) {
71 if (argc < 3) {
72 std::cerr << std::format("Usage: {} <host> <port>\n", argv[0]);
73 return 1;
74 }
75
76 std::string host = argv[1];
77 uint16_t port = static_cast<uint16_t>(std::stoi(argv[2]));
78
79 sockaddr_in server_addr;
80 prepare_address(host, port, server_addr);
81
82 int server_fd = socket(AF_INET, SOCK_STREAM, 0);
83 if (server_fd < 0) {
84 std::perror("Failed to create socket");
85 return 1;
86 }
87
88 if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) <
89 0) {
90 std::perror("Failed to bind socket");
91 close(server_fd);
92 return 1;
93 }
94
95 if (listen(server_fd, BACKLOG) < 0) {
96 std::perror("Failed to listen on socket");
97 close(server_fd);
98 return 1;
99 }
100
101 std::cout << std::format("Echo server listening on {}:{}\n", host, port);
102
103 condy::Runtime runtime(condy::RuntimeOptions().sq_size(MAX_CONNECTIONS));
104
105 runtime.fd_table().init(MAX_CONNECTIONS);
106
107 return condy::sync_wait(runtime, co_main(server_fd));
108}
Coroutine type used to define a coroutine function.
Definition coro.hpp:26
The event loop runtime for executing asynchronous.
Definition runtime.hpp:68
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:85
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:266