]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // server.cpp | |
3 | // ~~~~~~~~~~ | |
4 | // | |
5 | // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) | |
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 <cstdlib> | |
12 | #include <iostream> | |
13 | #include <boost/aligned_storage.hpp> | |
14 | #include <boost/array.hpp> | |
15 | #include <boost/bind.hpp> | |
16 | #include <boost/enable_shared_from_this.hpp> | |
17 | #include <boost/noncopyable.hpp> | |
18 | #include <boost/shared_ptr.hpp> | |
19 | #include <boost/asio.hpp> | |
20 | ||
21 | using boost::asio::ip::tcp; | |
22 | ||
23 | // Class to manage the memory to be used for handler-based custom allocation. | |
24 | // It contains a single block of memory which may be returned for allocation | |
25 | // requests. If the memory is in use when an allocation request is made, the | |
26 | // allocator delegates allocation to the global heap. | |
27 | class handler_allocator | |
28 | : private boost::noncopyable | |
29 | { | |
30 | public: | |
31 | handler_allocator() | |
32 | : in_use_(false) | |
33 | { | |
34 | } | |
35 | ||
36 | void* allocate(std::size_t size) | |
37 | { | |
38 | if (!in_use_ && size < storage_.size) | |
39 | { | |
40 | in_use_ = true; | |
41 | return storage_.address(); | |
42 | } | |
43 | else | |
44 | { | |
45 | return ::operator new(size); | |
46 | } | |
47 | } | |
48 | ||
49 | void deallocate(void* pointer) | |
50 | { | |
51 | if (pointer == storage_.address()) | |
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 | boost::aligned_storage<1024> storage_; | |
64 | ||
65 | // Whether the handler-based custom allocation storage has been used. | |
66 | bool in_use_; | |
67 | }; | |
68 | ||
69 | // Wrapper class template for handler objects to allow handler memory | |
70 | // allocation to be customised. Calls to operator() are forwarded to the | |
71 | // encapsulated handler. | |
72 | template <typename Handler> | |
73 | class custom_alloc_handler | |
74 | { | |
75 | public: | |
76 | custom_alloc_handler(handler_allocator& a, Handler h) | |
77 | : allocator_(a), | |
78 | handler_(h) | |
79 | { | |
80 | } | |
81 | ||
82 | template <typename Arg1> | |
83 | void operator()(Arg1 arg1) | |
84 | { | |
85 | handler_(arg1); | |
86 | } | |
87 | ||
88 | template <typename Arg1, typename Arg2> | |
89 | void operator()(Arg1 arg1, Arg2 arg2) | |
90 | { | |
91 | handler_(arg1, arg2); | |
92 | } | |
93 | ||
94 | friend void* asio_handler_allocate(std::size_t size, | |
95 | custom_alloc_handler<Handler>* this_handler) | |
96 | { | |
97 | return this_handler->allocator_.allocate(size); | |
98 | } | |
99 | ||
100 | friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, | |
101 | custom_alloc_handler<Handler>* this_handler) | |
102 | { | |
103 | this_handler->allocator_.deallocate(pointer); | |
104 | } | |
105 | ||
106 | private: | |
107 | handler_allocator& allocator_; | |
108 | Handler handler_; | |
109 | }; | |
110 | ||
111 | // Helper function to wrap a handler object to add custom allocation. | |
112 | template <typename Handler> | |
113 | inline custom_alloc_handler<Handler> make_custom_alloc_handler( | |
114 | handler_allocator& a, Handler h) | |
115 | { | |
116 | return custom_alloc_handler<Handler>(a, h); | |
117 | } | |
118 | ||
119 | class session | |
120 | : public boost::enable_shared_from_this<session> | |
121 | { | |
122 | public: | |
123 | session(boost::asio::io_service& io_service) | |
124 | : socket_(io_service) | |
125 | { | |
126 | } | |
127 | ||
128 | tcp::socket& socket() | |
129 | { | |
130 | return socket_; | |
131 | } | |
132 | ||
133 | void start() | |
134 | { | |
135 | socket_.async_read_some(boost::asio::buffer(data_), | |
136 | make_custom_alloc_handler(allocator_, | |
137 | boost::bind(&session::handle_read, | |
138 | shared_from_this(), | |
139 | boost::asio::placeholders::error, | |
140 | boost::asio::placeholders::bytes_transferred))); | |
141 | } | |
142 | ||
143 | void handle_read(const boost::system::error_code& error, | |
144 | size_t bytes_transferred) | |
145 | { | |
146 | if (!error) | |
147 | { | |
148 | boost::asio::async_write(socket_, | |
149 | boost::asio::buffer(data_, bytes_transferred), | |
150 | make_custom_alloc_handler(allocator_, | |
151 | boost::bind(&session::handle_write, | |
152 | shared_from_this(), | |
153 | boost::asio::placeholders::error))); | |
154 | } | |
155 | } | |
156 | ||
157 | void handle_write(const boost::system::error_code& error) | |
158 | { | |
159 | if (!error) | |
160 | { | |
161 | socket_.async_read_some(boost::asio::buffer(data_), | |
162 | make_custom_alloc_handler(allocator_, | |
163 | boost::bind(&session::handle_read, | |
164 | shared_from_this(), | |
165 | boost::asio::placeholders::error, | |
166 | boost::asio::placeholders::bytes_transferred))); | |
167 | } | |
168 | } | |
169 | ||
170 | private: | |
171 | // The socket used to communicate with the client. | |
172 | tcp::socket socket_; | |
173 | ||
174 | // Buffer used to store data received from the client. | |
175 | boost::array<char, 1024> data_; | |
176 | ||
177 | // The allocator to use for handler-based custom memory allocation. | |
178 | handler_allocator allocator_; | |
179 | }; | |
180 | ||
181 | typedef boost::shared_ptr<session> session_ptr; | |
182 | ||
183 | class server | |
184 | { | |
185 | public: | |
186 | server(boost::asio::io_service& io_service, short port) | |
187 | : io_service_(io_service), | |
188 | acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) | |
189 | { | |
190 | session_ptr new_session(new session(io_service_)); | |
191 | acceptor_.async_accept(new_session->socket(), | |
192 | boost::bind(&server::handle_accept, this, new_session, | |
193 | boost::asio::placeholders::error)); | |
194 | } | |
195 | ||
196 | void handle_accept(session_ptr new_session, | |
197 | const boost::system::error_code& error) | |
198 | { | |
199 | if (!error) | |
200 | { | |
201 | new_session->start(); | |
202 | } | |
203 | ||
204 | new_session.reset(new session(io_service_)); | |
205 | acceptor_.async_accept(new_session->socket(), | |
206 | boost::bind(&server::handle_accept, this, new_session, | |
207 | boost::asio::placeholders::error)); | |
208 | } | |
209 | ||
210 | private: | |
211 | boost::asio::io_service& io_service_; | |
212 | tcp::acceptor acceptor_; | |
213 | }; | |
214 | ||
215 | int main(int argc, char* argv[]) | |
216 | { | |
217 | try | |
218 | { | |
219 | if (argc != 2) | |
220 | { | |
221 | std::cerr << "Usage: server <port>\n"; | |
222 | return 1; | |
223 | } | |
224 | ||
225 | boost::asio::io_service io_service; | |
226 | ||
227 | using namespace std; // For atoi. | |
228 | server s(io_service, atoi(argv[1])); | |
229 | ||
230 | io_service.run(); | |
231 | } | |
232 | catch (std::exception& e) | |
233 | { | |
234 | std::cerr << "Exception: " << e.what() << "\n"; | |
235 | } | |
236 | ||
237 | return 0; | |
238 | } |