Imported Upstream version 1.57.0
[platform/upstream/boost.git] / doc / html / boost_asio / example / cpp03 / allocation / server.cpp
1 //
2 // server.cpp
3 // ~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2014 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 }