1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/vinniefalco/CppCon2018
8 //
9
10 #include "listener.hpp"
11 #include "http_session.hpp"
12 #include <iostream>
13
14 listener::
listener(net::io_context & ioc,tcp::endpoint endpoint,boost::shared_ptr<shared_state> const & state)15 listener(
16 net::io_context& ioc,
17 tcp::endpoint endpoint,
18 boost::shared_ptr<shared_state> const& state)
19 : ioc_(ioc)
20 , acceptor_(ioc)
21 , state_(state)
22 {
23 beast::error_code ec;
24
25 // Open the acceptor
26 acceptor_.open(endpoint.protocol(), ec);
27 if(ec)
28 {
29 fail(ec, "open");
30 return;
31 }
32
33 // Allow address reuse
34 acceptor_.set_option(net::socket_base::reuse_address(true), ec);
35 if(ec)
36 {
37 fail(ec, "set_option");
38 return;
39 }
40
41 // Bind to the server address
42 acceptor_.bind(endpoint, ec);
43 if(ec)
44 {
45 fail(ec, "bind");
46 return;
47 }
48
49 // Start listening for connections
50 acceptor_.listen(
51 net::socket_base::max_listen_connections, ec);
52 if(ec)
53 {
54 fail(ec, "listen");
55 return;
56 }
57 }
58
59 void
60 listener::
run()61 run()
62 {
63 // The new connection gets its own strand
64 acceptor_.async_accept(
65 net::make_strand(ioc_),
66 beast::bind_front_handler(
67 &listener::on_accept,
68 shared_from_this()));
69 }
70
71 // Report a failure
72 void
73 listener::
fail(beast::error_code ec,char const * what)74 fail(beast::error_code ec, char const* what)
75 {
76 // Don't report on canceled operations
77 if(ec == net::error::operation_aborted)
78 return;
79 std::cerr << what << ": " << ec.message() << "\n";
80 }
81
82 // Handle a connection
83 void
84 listener::
on_accept(beast::error_code ec,tcp::socket socket)85 on_accept(beast::error_code ec, tcp::socket socket)
86 {
87 if(ec)
88 return fail(ec, "accept");
89 else
90 // Launch a new session for this connection
91 boost::make_shared<http_session>(
92 std::move(socket),
93 state_)->run();
94
95 // The new connection gets its own strand
96 acceptor_.async_accept(
97 net::make_strand(ioc_),
98 beast::bind_front_handler(
99 &listener::on_accept,
100 shared_from_this()));
101 }
102