]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp03/chat/chat_server.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / asio / example / cpp03 / chat / chat_server.cpp
1 //
2 // chat_server.cpp
3 // ~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 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 <algorithm>
12 #include <cstdlib>
13 #include <deque>
14 #include <iostream>
15 #include <list>
16 #include <set>
17 #include <boost/bind.hpp>
18 #include <boost/shared_ptr.hpp>
19 #include <boost/enable_shared_from_this.hpp>
20 #include <boost/asio.hpp>
21 #include "chat_message.hpp"
22
23 using boost::asio::ip::tcp;
24
25 //----------------------------------------------------------------------
26
27 typedef std::deque<chat_message> chat_message_queue;
28
29 //----------------------------------------------------------------------
30
31 class chat_participant
32 {
33 public:
34 virtual ~chat_participant() {}
35 virtual void deliver(const chat_message& msg) = 0;
36 };
37
38 typedef boost::shared_ptr<chat_participant> chat_participant_ptr;
39
40 //----------------------------------------------------------------------
41
42 class chat_room
43 {
44 public:
45 void join(chat_participant_ptr participant)
46 {
47 participants_.insert(participant);
48 std::for_each(recent_msgs_.begin(), recent_msgs_.end(),
49 boost::bind(&chat_participant::deliver, participant, _1));
50 }
51
52 void leave(chat_participant_ptr participant)
53 {
54 participants_.erase(participant);
55 }
56
57 void deliver(const chat_message& msg)
58 {
59 recent_msgs_.push_back(msg);
60 while (recent_msgs_.size() > max_recent_msgs)
61 recent_msgs_.pop_front();
62
63 std::for_each(participants_.begin(), participants_.end(),
64 boost::bind(&chat_participant::deliver, _1, boost::ref(msg)));
65 }
66
67 private:
68 std::set<chat_participant_ptr> participants_;
69 enum { max_recent_msgs = 100 };
70 chat_message_queue recent_msgs_;
71 };
72
73 //----------------------------------------------------------------------
74
75 class chat_session
76 : public chat_participant,
77 public boost::enable_shared_from_this<chat_session>
78 {
79 public:
80 chat_session(boost::asio::io_context& io_context, chat_room& room)
81 : socket_(io_context),
82 room_(room)
83 {
84 }
85
86 tcp::socket& socket()
87 {
88 return socket_;
89 }
90
91 void start()
92 {
93 room_.join(shared_from_this());
94 boost::asio::async_read(socket_,
95 boost::asio::buffer(read_msg_.data(), chat_message::header_length),
96 boost::bind(
97 &chat_session::handle_read_header, shared_from_this(),
98 boost::asio::placeholders::error));
99 }
100
101 void deliver(const chat_message& msg)
102 {
103 bool write_in_progress = !write_msgs_.empty();
104 write_msgs_.push_back(msg);
105 if (!write_in_progress)
106 {
107 boost::asio::async_write(socket_,
108 boost::asio::buffer(write_msgs_.front().data(),
109 write_msgs_.front().length()),
110 boost::bind(&chat_session::handle_write, shared_from_this(),
111 boost::asio::placeholders::error));
112 }
113 }
114
115 void handle_read_header(const boost::system::error_code& error)
116 {
117 if (!error && read_msg_.decode_header())
118 {
119 boost::asio::async_read(socket_,
120 boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
121 boost::bind(&chat_session::handle_read_body, shared_from_this(),
122 boost::asio::placeholders::error));
123 }
124 else
125 {
126 room_.leave(shared_from_this());
127 }
128 }
129
130 void handle_read_body(const boost::system::error_code& error)
131 {
132 if (!error)
133 {
134 room_.deliver(read_msg_);
135 boost::asio::async_read(socket_,
136 boost::asio::buffer(read_msg_.data(), chat_message::header_length),
137 boost::bind(&chat_session::handle_read_header, shared_from_this(),
138 boost::asio::placeholders::error));
139 }
140 else
141 {
142 room_.leave(shared_from_this());
143 }
144 }
145
146 void handle_write(const boost::system::error_code& error)
147 {
148 if (!error)
149 {
150 write_msgs_.pop_front();
151 if (!write_msgs_.empty())
152 {
153 boost::asio::async_write(socket_,
154 boost::asio::buffer(write_msgs_.front().data(),
155 write_msgs_.front().length()),
156 boost::bind(&chat_session::handle_write, shared_from_this(),
157 boost::asio::placeholders::error));
158 }
159 }
160 else
161 {
162 room_.leave(shared_from_this());
163 }
164 }
165
166 private:
167 tcp::socket socket_;
168 chat_room& room_;
169 chat_message read_msg_;
170 chat_message_queue write_msgs_;
171 };
172
173 typedef boost::shared_ptr<chat_session> chat_session_ptr;
174
175 //----------------------------------------------------------------------
176
177 class chat_server
178 {
179 public:
180 chat_server(boost::asio::io_context& io_context,
181 const tcp::endpoint& endpoint)
182 : io_context_(io_context),
183 acceptor_(io_context, endpoint)
184 {
185 start_accept();
186 }
187
188 void start_accept()
189 {
190 chat_session_ptr new_session(new chat_session(io_context_, room_));
191 acceptor_.async_accept(new_session->socket(),
192 boost::bind(&chat_server::handle_accept, this, new_session,
193 boost::asio::placeholders::error));
194 }
195
196 void handle_accept(chat_session_ptr session,
197 const boost::system::error_code& error)
198 {
199 if (!error)
200 {
201 session->start();
202 }
203
204 start_accept();
205 }
206
207 private:
208 boost::asio::io_context& io_context_;
209 tcp::acceptor acceptor_;
210 chat_room room_;
211 };
212
213 typedef boost::shared_ptr<chat_server> chat_server_ptr;
214 typedef std::list<chat_server_ptr> chat_server_list;
215
216 //----------------------------------------------------------------------
217
218 int main(int argc, char* argv[])
219 {
220 try
221 {
222 if (argc < 2)
223 {
224 std::cerr << "Usage: chat_server <port> [<port> ...]\n";
225 return 1;
226 }
227
228 boost::asio::io_context io_context;
229
230 chat_server_list servers;
231 for (int i = 1; i < argc; ++i)
232 {
233 using namespace std; // For atoi.
234 tcp::endpoint endpoint(tcp::v4(), atoi(argv[i]));
235 chat_server_ptr server(new chat_server(io_context, endpoint));
236 servers.push_back(server);
237 }
238
239 io_context.run();
240 }
241 catch (std::exception& e)
242 {
243 std::cerr << "Exception: " << e.what() << "\n";
244 }
245
246 return 0;
247 }