• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // server.cpp
3 // ~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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/bind/bind.hpp>
14 #include <boost/asio.hpp>
15 #include <boost/asio/ssl.hpp>
16 
17 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
18 
19 class session
20 {
21 public:
session(boost::asio::io_context & io_context,boost::asio::ssl::context & context)22   session(boost::asio::io_context& io_context,
23       boost::asio::ssl::context& context)
24     : socket_(io_context, context)
25   {
26   }
27 
socket()28   ssl_socket::lowest_layer_type& socket()
29   {
30     return socket_.lowest_layer();
31   }
32 
start()33   void start()
34   {
35     socket_.async_handshake(boost::asio::ssl::stream_base::server,
36         boost::bind(&session::handle_handshake, this,
37           boost::asio::placeholders::error));
38   }
39 
handle_handshake(const boost::system::error_code & error)40   void handle_handshake(const boost::system::error_code& error)
41   {
42     if (!error)
43     {
44       socket_.async_read_some(boost::asio::buffer(data_, max_length),
45           boost::bind(&session::handle_read, this,
46             boost::asio::placeholders::error,
47             boost::asio::placeholders::bytes_transferred));
48     }
49     else
50     {
51       delete this;
52     }
53   }
54 
handle_read(const boost::system::error_code & error,size_t bytes_transferred)55   void handle_read(const boost::system::error_code& error,
56       size_t bytes_transferred)
57   {
58     if (!error)
59     {
60       boost::asio::async_write(socket_,
61           boost::asio::buffer(data_, bytes_transferred),
62           boost::bind(&session::handle_write, this,
63             boost::asio::placeholders::error));
64     }
65     else
66     {
67       delete this;
68     }
69   }
70 
handle_write(const boost::system::error_code & error)71   void handle_write(const boost::system::error_code& error)
72   {
73     if (!error)
74     {
75       socket_.async_read_some(boost::asio::buffer(data_, max_length),
76           boost::bind(&session::handle_read, this,
77             boost::asio::placeholders::error,
78             boost::asio::placeholders::bytes_transferred));
79     }
80     else
81     {
82       delete this;
83     }
84   }
85 
86 private:
87   ssl_socket socket_;
88   enum { max_length = 1024 };
89   char data_[max_length];
90 };
91 
92 class server
93 {
94 public:
server(boost::asio::io_context & io_context,unsigned short port)95   server(boost::asio::io_context& io_context, unsigned short port)
96     : io_context_(io_context),
97       acceptor_(io_context,
98           boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
99       context_(boost::asio::ssl::context::sslv23)
100   {
101     context_.set_options(
102         boost::asio::ssl::context::default_workarounds
103         | boost::asio::ssl::context::no_sslv2
104         | boost::asio::ssl::context::single_dh_use);
105     context_.set_password_callback(boost::bind(&server::get_password, this));
106     context_.use_certificate_chain_file("server.pem");
107     context_.use_private_key_file("server.pem", boost::asio::ssl::context::pem);
108     context_.use_tmp_dh_file("dh2048.pem");
109 
110     start_accept();
111   }
112 
get_password() const113   std::string get_password() const
114   {
115     return "test";
116   }
117 
start_accept()118   void start_accept()
119   {
120     session* new_session = new session(io_context_, context_);
121     acceptor_.async_accept(new_session->socket(),
122         boost::bind(&server::handle_accept, this, new_session,
123           boost::asio::placeholders::error));
124   }
125 
handle_accept(session * new_session,const boost::system::error_code & error)126   void handle_accept(session* new_session,
127       const boost::system::error_code& error)
128   {
129     if (!error)
130     {
131       new_session->start();
132     }
133     else
134     {
135       delete new_session;
136     }
137 
138     start_accept();
139   }
140 
141 private:
142   boost::asio::io_context& io_context_;
143   boost::asio::ip::tcp::acceptor acceptor_;
144   boost::asio::ssl::context context_;
145 };
146 
main(int argc,char * argv[])147 int main(int argc, char* argv[])
148 {
149   try
150   {
151     if (argc != 2)
152     {
153       std::cerr << "Usage: server <port>\n";
154       return 1;
155     }
156 
157     boost::asio::io_context io_context;
158 
159     using namespace std; // For atoi.
160     server s(io_context, atoi(argv[1]));
161 
162     io_context.run();
163   }
164   catch (std::exception& e)
165   {
166     std::cerr << "Exception: " << e.what() << "\n";
167   }
168 
169   return 0;
170 }
171