File: server.cpp

package info (click to toggle)
boost1.90 1.90.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 593,168 kB
  • sloc: cpp: 4,190,642; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,776; makefile: 1,162; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (133 lines) | stat: -rw-r--r-- 3,402 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//
// Copyright (c) 2025 Mohammad Nejati
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>

#include <iostream>

#if defined(BOOST_ASIO_HAS_CO_AWAIT)

namespace beast = boost::beast;
namespace http  = beast::http;
namespace net   = boost::asio;
namespace ssl   = net::ssl;

void
print_exception(std::exception_ptr eptr)
{
    if(eptr)
    {
        try
        {
            std::rethrow_exception(eptr);
        }
        catch(std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }
    }
}

net::awaitable<void>
handle_session(ssl::stream<net::ip::tcp::socket> stream)
{
    // Perform the SSL handshake
    co_await stream.async_handshake(ssl::stream_base::server);

    // Read and discard a request
    beast::flat_buffer buf;
    http::request<http::empty_body> req;
    co_await http::async_read(stream, buf, req);

    // Write the response
    http::response<http::string_body> res;
    res.body() = "Hello!";
    co_await http::async_write(stream, res);

    // Gracefully shutdown the SSL stream
    auto [ec] = co_await stream.async_shutdown(net::as_tuple);
    if(ec && ec != ssl::error::stream_truncated)
        throw boost::system::system_error(ec);
}

net::awaitable<void>
acceptor(ssl::context& ctx)
{
    auto executor = co_await net::this_coro::executor;
    net::ip::tcp::endpoint endpoint{ {}, 8080 };
    net::ip::tcp::acceptor acceptor{ executor, endpoint };

    for(;;)
    {
        net::co_spawn(
            executor,
            handle_session({ co_await acceptor.async_accept(), ctx }),
            print_exception);
    }
}

int
main()
{
    try
    {
        // The io_context is required for all I/O
        net::io_context ioc;

        // The SSL context is required, and holds certificates,
        // configurations and session related data
        ssl::context ctx{ ssl::context::sslv23 };

        // https://docs.openssl.org/3.4/man3/SSL_CTX_set_options/
        ctx.set_options(
            ssl::context::no_sslv2 | ssl::context::default_workarounds |
            ssl::context::single_dh_use);

        // Comment this line to disable client certificate request.
        ctx.set_verify_mode(
            ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);

        // The client's certificate will be verified against this
        // certificate authority.
        ctx.load_verify_file("ca.crt");

        // In a real application, the passphrase would be read from
        // a secure place, such as a key vault.
        ctx.set_password_callback([](auto, auto) { return "123456"; });

        // Server certificate and private key.
        ctx.use_certificate_chain_file("server.crt");
        ctx.use_private_key_file("server.key", ssl::context::pem);

        // DH parameters for DHE-based cipher suites
        ctx.use_tmp_dh_file("dh4096.pem");

        net::co_spawn(ioc, acceptor(ctx), print_exception);

        ioc.run();
    }
    catch(std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

#else

int
main(int, char*[])
{
    std::printf("awaitables require C++20\n");
    return EXIT_FAILURE;
}

#endif