]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // server.cpp | |
3 | // ~~~~~~~~~~ | |
4 | // | |
b32b8144 | 5 | // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
6 | // |
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) | |
9 | // | |
10 | ||
11 | #include <array> | |
12 | #include <cstdlib> | |
13 | #include <iostream> | |
14 | #include <memory> | |
15 | #include <type_traits> | |
16 | #include <utility> | |
17 | #include <boost/asio.hpp> | |
18 | ||
19 | using boost::asio::ip::tcp; | |
20 | ||
21 | // Class to manage the memory to be used for handler-based custom allocation. | |
22 | // It contains a single block of memory which may be returned for allocation | |
23 | // requests. If the memory is in use when an allocation request is made, the | |
24 | // allocator delegates allocation to the global heap. | |
b32b8144 | 25 | class handler_memory |
7c673cae FG |
26 | { |
27 | public: | |
b32b8144 | 28 | handler_memory() |
7c673cae FG |
29 | : in_use_(false) |
30 | { | |
31 | } | |
32 | ||
b32b8144 FG |
33 | handler_memory(const handler_memory&) = delete; |
34 | handler_memory& operator=(const handler_memory&) = delete; | |
7c673cae FG |
35 | |
36 | void* allocate(std::size_t size) | |
37 | { | |
38 | if (!in_use_ && size < sizeof(storage_)) | |
39 | { | |
40 | in_use_ = true; | |
41 | return &storage_; | |
42 | } | |
43 | else | |
44 | { | |
45 | return ::operator new(size); | |
46 | } | |
47 | } | |
48 | ||
49 | void deallocate(void* pointer) | |
50 | { | |
51 | if (pointer == &storage_) | |
52 | { | |
53 | in_use_ = false; | |
54 | } | |
55 | else | |
56 | { | |
57 | ::operator delete(pointer); | |
58 | } | |
59 | } | |
60 | ||
61 | private: | |
62 | // Storage space used for handler-based custom memory allocation. | |
63 | typename std::aligned_storage<1024>::type storage_; | |
64 | ||
65 | // Whether the handler-based custom allocation storage has been used. | |
66 | bool in_use_; | |
67 | }; | |
68 | ||
b32b8144 FG |
69 | // The allocator to be associated with the handler objects. This allocator only |
70 | // needs to satisfy the C++11 minimal allocator requirements. | |
71 | template <typename T> | |
72 | class handler_allocator | |
73 | { | |
74 | public: | |
75 | using value_type = T; | |
76 | ||
77 | explicit handler_allocator(handler_memory& mem) | |
78 | : memory_(mem) | |
79 | { | |
80 | } | |
81 | ||
82 | template <typename U> | |
83 | handler_allocator(const handler_allocator<U>& other) noexcept | |
84 | : memory_(other.memory_) | |
85 | { | |
86 | } | |
87 | ||
88 | bool operator==(const handler_allocator& other) const noexcept | |
89 | { | |
90 | return &memory_ == &other.memory_; | |
91 | } | |
92 | ||
93 | bool operator!=(const handler_allocator& other) const noexcept | |
94 | { | |
95 | return &memory_ != &other.memory_; | |
96 | } | |
97 | ||
98 | T* allocate(std::size_t n) const | |
99 | { | |
100 | return static_cast<T*>(memory_.allocate(sizeof(T) * n)); | |
101 | } | |
102 | ||
103 | void deallocate(T* p, std::size_t /*n*/) const | |
104 | { | |
105 | return memory_.deallocate(p); | |
106 | } | |
107 | ||
108 | private: | |
109 | template <typename> friend class handler_allocator; | |
110 | ||
111 | // The underlying memory. | |
112 | handler_memory& memory_; | |
113 | }; | |
114 | ||
7c673cae | 115 | // Wrapper class template for handler objects to allow handler memory |
b32b8144 FG |
116 | // allocation to be customised. The allocator_type type and get_allocator() |
117 | // member function are used by the asynchronous operations to obtain the | |
118 | // allocator. Calls to operator() are forwarded to the encapsulated handler. | |
7c673cae FG |
119 | template <typename Handler> |
120 | class custom_alloc_handler | |
121 | { | |
122 | public: | |
b32b8144 | 123 | using allocator_type = handler_allocator<Handler>; |
7c673cae | 124 | |
b32b8144 FG |
125 | custom_alloc_handler(handler_memory& m, Handler h) |
126 | : memory_(m), | |
127 | handler_(h) | |
7c673cae | 128 | { |
7c673cae FG |
129 | } |
130 | ||
b32b8144 | 131 | allocator_type get_allocator() const noexcept |
7c673cae | 132 | { |
b32b8144 | 133 | return allocator_type(memory_); |
7c673cae FG |
134 | } |
135 | ||
b32b8144 FG |
136 | template <typename ...Args> |
137 | void operator()(Args&&... args) | |
7c673cae | 138 | { |
b32b8144 | 139 | handler_(std::forward<Args>(args)...); |
7c673cae FG |
140 | } |
141 | ||
142 | private: | |
b32b8144 | 143 | handler_memory& memory_; |
7c673cae FG |
144 | Handler handler_; |
145 | }; | |
146 | ||
147 | // Helper function to wrap a handler object to add custom allocation. | |
148 | template <typename Handler> | |
149 | inline custom_alloc_handler<Handler> make_custom_alloc_handler( | |
b32b8144 | 150 | handler_memory& m, Handler h) |
7c673cae | 151 | { |
b32b8144 | 152 | return custom_alloc_handler<Handler>(m, h); |
7c673cae FG |
153 | } |
154 | ||
155 | class session | |
156 | : public std::enable_shared_from_this<session> | |
157 | { | |
158 | public: | |
159 | session(tcp::socket socket) | |
160 | : socket_(std::move(socket)) | |
161 | { | |
162 | } | |
163 | ||
164 | void start() | |
165 | { | |
166 | do_read(); | |
167 | } | |
168 | ||
169 | private: | |
170 | void do_read() | |
171 | { | |
172 | auto self(shared_from_this()); | |
173 | socket_.async_read_some(boost::asio::buffer(data_), | |
b32b8144 | 174 | make_custom_alloc_handler(handler_memory_, |
7c673cae FG |
175 | [this, self](boost::system::error_code ec, std::size_t length) |
176 | { | |
177 | if (!ec) | |
178 | { | |
179 | do_write(length); | |
180 | } | |
181 | })); | |
182 | } | |
183 | ||
184 | void do_write(std::size_t length) | |
185 | { | |
186 | auto self(shared_from_this()); | |
187 | boost::asio::async_write(socket_, boost::asio::buffer(data_, length), | |
b32b8144 | 188 | make_custom_alloc_handler(handler_memory_, |
7c673cae FG |
189 | [this, self](boost::system::error_code ec, std::size_t /*length*/) |
190 | { | |
191 | if (!ec) | |
192 | { | |
193 | do_read(); | |
194 | } | |
195 | })); | |
196 | } | |
197 | ||
198 | // The socket used to communicate with the client. | |
199 | tcp::socket socket_; | |
200 | ||
201 | // Buffer used to store data received from the client. | |
202 | std::array<char, 1024> data_; | |
203 | ||
b32b8144 FG |
204 | // The memory to use for handler-based custom memory allocation. |
205 | handler_memory handler_memory_; | |
7c673cae FG |
206 | }; |
207 | ||
208 | class server | |
209 | { | |
210 | public: | |
b32b8144 FG |
211 | server(boost::asio::io_context& io_context, short port) |
212 | : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) | |
7c673cae FG |
213 | { |
214 | do_accept(); | |
215 | } | |
216 | ||
217 | private: | |
218 | void do_accept() | |
219 | { | |
b32b8144 FG |
220 | acceptor_.async_accept( |
221 | [this](boost::system::error_code ec, tcp::socket socket) | |
7c673cae FG |
222 | { |
223 | if (!ec) | |
224 | { | |
b32b8144 | 225 | std::make_shared<session>(std::move(socket))->start(); |
7c673cae FG |
226 | } |
227 | ||
228 | do_accept(); | |
229 | }); | |
230 | } | |
231 | ||
232 | tcp::acceptor acceptor_; | |
7c673cae FG |
233 | }; |
234 | ||
235 | int main(int argc, char* argv[]) | |
236 | { | |
237 | try | |
238 | { | |
239 | if (argc != 2) | |
240 | { | |
241 | std::cerr << "Usage: server <port>\n"; | |
242 | return 1; | |
243 | } | |
244 | ||
b32b8144 FG |
245 | boost::asio::io_context io_context; |
246 | server s(io_context, std::atoi(argv[1])); | |
247 | io_context.run(); | |
7c673cae FG |
248 | } |
249 | catch (std::exception& e) | |
250 | { | |
251 | std::cerr << "Exception: " << e.what() << "\n"; | |
252 | } | |
253 | ||
254 | return 0; | |
255 | } |