5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
12 #include "request.hpp"
18 server::server(boost::asio::io_service& io_service,
19 const std::string& address, const std::string& port,
20 boost::function<void(const request&, reply&)> request_handler)
21 : request_handler_(request_handler)
23 tcp::resolver resolver(io_service);
24 tcp::resolver::query query(address, port);
25 acceptor_.reset(new tcp::acceptor(io_service, *resolver.resolve(query)));
28 // Enable the pseudo-keywords reenter, yield and fork.
29 #include <boost/asio/yield.hpp>
31 void server::operator()(boost::system::error_code ec, std::size_t length)
33 // In this example we keep the error handling code in one place by
34 // hoisting it outside the coroutine. An alternative approach would be to
35 // check the value of ec after each yield for an asynchronous operation.
38 // On reentering a coroutine, control jumps to the location of the last
39 // yield or fork. The argument to the "reenter" pseudo-keyword can be a
40 // pointer or reference to an object of type coroutine.
43 // Loop to accept incoming connections.
46 // Create a new socket for the next incoming connection.
47 socket_.reset(new tcp::socket(acceptor_->get_io_service()));
49 // Accept a new connection. The "yield" pseudo-keyword saves the current
50 // line number and exits the coroutine's "reenter" block. We use the
51 // server coroutine as the completion handler for the async_accept
52 // operation. When the asynchronous operation completes, the io_service
53 // invokes the function call operator, we "reenter" the coroutine, and
54 // then control resumes at the following line.
55 yield acceptor_->async_accept(*socket_, *this);
57 // We "fork" by cloning a new server coroutine to handle the connection.
58 // After forking we have a parent coroutine and a child coroutine. Both
59 // parent and child continue execution at the following line. They can
60 // be distinguished using the functions coroutine::is_parent() and
61 // coroutine::is_child().
64 // The parent continues looping to accept the next incoming connection.
65 // The child exits the loop and processes the connection.
66 } while (is_parent());
68 // Create the objects needed to receive a request on the connection.
69 buffer_.reset(new boost::array<char, 8192>);
70 request_.reset(new request);
72 // Loop until a complete request (or an invalid one) has been received.
75 // Receive some more data. When control resumes at the following line,
76 // the ec and length parameters reflect the result of the asynchronous
78 yield socket_->async_read_some(boost::asio::buffer(*buffer_), *this);
80 // Parse the data we just received.
81 boost::tie(valid_request_, boost::tuples::ignore)
82 = request_parser_.parse(*request_,
83 buffer_->data(), buffer_->data() + length);
85 // An indeterminate result means we need more data, so keep looping.
86 } while (boost::indeterminate(valid_request_));
88 // Create the reply object that will be sent back to the client.
89 reply_.reset(new reply);
93 // A valid request was received. Call the user-supplied function object
94 // to process the request and compose a reply.
95 request_handler_(*request_, *reply_);
99 // The request was invalid.
100 *reply_ = reply::stock_reply(reply::bad_request);
103 // Send the reply back to the client.
104 yield boost::asio::async_write(*socket_, reply_->to_buffers(), *this);
106 // Initiate graceful connection closure.
107 socket_->shutdown(tcp::socket::shutdown_both, ec);
111 // If an error occurs then the coroutine is not reentered. Consequently, no
112 // new asynchronous operations are started. This means that all shared_ptr
113 // references will disappear and the resources associated with the coroutine
114 // will be destroyed automatically after this function call returns.
117 // Disable the pseudo-keywords reenter, yield and fork.
118 #include <boost/asio/unyield.hpp>
120 } // namespace server4