A TCP Echo Server with authentication and encryption support.
- A new client connects via TCP/IPv4 to port
31216
and is assigned a session. - The client should send a
login_request
message with any username and password combination. - The server will reply with a
login_response
with statusOK
. - The client can now send
echo_request
messages with an encryptedcipher_message
. - The server will reply with
echo_response
messages, containing the decryptedplain_message
. - The client can disconnect at any time, and their session will destroyed.
- To close the server from a terminal, please send a
SIGINT
(Ctrl+C).
For more details about the cipher algorithm, please check client_crypto.cpp and the cipher test.
For a reference implementation of a client software, please check the business rules test.
A single thread is spawned to run the client coroutine tasks concurrently.
This supports multiple concurrent clients with IO multiplexing.
For further details, please check the concurrency test, which runs a complete business rule test over 500 simultaneous connections.
It is possible to implement parallelism in combination with concurrency by using a thread_pool
instead of io_context
in main.cpp.
You can edit the server_config.hpp to change build-time configurations.
The default byte order for this network protocol w.r.t. binary serialization and deserialization of integers of size higher than 1 is assumed to be little endian.
To change this behavior please set byte_order
to either LITTLE_ENDIAN_MODE
or BIG_ENDIAN_MODE
.
- C++20 and a compiler that implements P0912R5
- Boost.Asio with coroutines support
- Boost.Endian to handle protocol endianness
- Boost.Uuid to identify client sessions
- Boost.Test to test business rules and concurrency
- spdlog to provide detailed logging
- Uses my personal DevContainer template for VSCode
- Provides Docker environment for building, testing and running
- Open this project in VSCode while having the Dev Containers installed.
- Reopen the folder in container using the extension.
Build dependencies:
- GCC >=12 (build-essential)
- CMake >=3.25
- Ninja
- vcpkg ($VCPKG_ROOT must be set)
cmake -B build/ --preset debug
cmake --build build/
cmake -B build/ --preset release
cmake --build build/
./build/server/mori_echo_server
docker compose up
docker run --rm -p 31216:31216 ghcr.io/rfsc-mori/mori_echo:little_endian
docker run --rm -p 31216:31216 ghcr.io/rfsc-mori/mori_echo:big_endian
If you decided to use docker compose up
, the tests are already executed during the build process.
ctest --preset tests
ctest --preset tests -R business_rules
ctest --preset tests -R concurrency
ctest --preset tests -R cipher
- Provides a TCP server capable of asynchronous processing
- Validates messages as efficiently as possible
- Rejects invalid messages and attempts to fail fast
- Requires user authentication before echoing
- Accepts any combination of username and password
- Keeps a per-session user context, containing the username and password checksums
- Echoes the message from the request
- Decrypts client messages
enum class message_type : uint8_t {
LOGIN_REQUEST = 0,
LOGIN_RESPONSE = 1,
ECHO_REQUEST = 2,
ECHO_RESPONSE = 3
};
struct message_header {
uint16_t total_size;
message_type type;
uint8_t sequence;
};
inline constexpr auto username_size = 32;
inline constexpr auto password_size = 32;
struct login_request {
message_header header; // .message_type = LOGIN_REQUEST (0)
fixed_length_container<char, message_limits::username_size> username;
fixed_length_container<char, message_limits::password_size> password;
};
enum class login_status : uint16_t {
FAILED = 0,
OK = 1
};
struct login_response {
message_header header; // .message_type = LOGIN_RESPONSE (1)
login_status status_code;
};
struct echo_request {
message_header header; // .message_type = ECHO_REQUEST (2)
uint16_t message_size;
fixed_length_container<char, message_size> cipher_message;
};
struct echo_response {
message_header header; // .message_type = ECHO_RESPONSE (3)
uint16_t message_size;
fixed_length_container<char, message_size> plain_message;
};
This project uses Microsoft's CPP DevContainer image for the development environment:
https://github.com/devcontainers/images/blob/main/src/cpp/README.md
This project uses the spdlog logging library:
https://github.com/gabime/spdlog/blob/v1.x/LICENSE
This project uses libraries from Boost:
https://www.boost.org/LICENSE_1_0.txt
This project uses vcpkg to install dependencies:
https://github.com/microsoft/vcpkg/blob/master/LICENSE.txt
MIT
Rafael Fillipe Silva (https://github.com/rfsc-mori)