forked from boostorg/beast
		
	A new server framework is introduced, allowing users to quickly get off the ground. Example servers are refactored to use the common framework.
		
			
				
	
	
		
			243 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
 | |
| //
 | |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
| //
 | |
| 
 | |
| #include "server.hpp"
 | |
| 
 | |
| #include "http_async_port.hpp"
 | |
| #include "http_sync_port.hpp"
 | |
| #include "ws_async_port.hpp"
 | |
| #include "ws_sync_port.hpp"
 | |
| 
 | |
| #include "file_service.hpp"
 | |
| #include "ws_upgrade_service.hpp"
 | |
| 
 | |
| #include <boost/program_options.hpp>
 | |
| 
 | |
| #include <iostream>
 | |
| 
 | |
| /// Block until SIGINT or SIGTERM is received.
 | |
| void
 | |
| sig_wait()
 | |
| {
 | |
|     // Create our own io_service for this
 | |
|     boost::asio::io_service ios;
 | |
| 
 | |
|     // Get notified on the signals we want
 | |
|     boost::asio::signal_set signals(
 | |
|         ios, SIGINT, SIGTERM);
 | |
| 
 | |
|     // Now perform the asynchronous call
 | |
|     signals.async_wait(
 | |
|         [&](boost::system::error_code const&, int)
 | |
|         {
 | |
|         });
 | |
| 
 | |
|     // Block the current thread on run(), when the
 | |
|     // signal is received then this call will return.
 | |
|     ios.run();
 | |
| }
 | |
| 
 | |
| /** Set the options on a WebSocket stream.
 | |
| 
 | |
|     This is used by the websocket server port handlers.
 | |
|     It is called every time a new websocket stream is
 | |
|     created, to provide the opportunity to set settings
 | |
|     for the connection.
 | |
| */
 | |
| class set_ws_options
 | |
| {
 | |
|     beast::websocket::permessage_deflate pmd_;
 | |
| 
 | |
| public:
 | |
|     set_ws_options(beast::websocket::permessage_deflate const& pmd)
 | |
|         : pmd_(pmd)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template<class NextLayer>
 | |
|     void
 | |
|     operator()(beast::websocket::stream<NextLayer>& ws) const
 | |
|     {
 | |
|         ws.auto_fragment(false);
 | |
|         ws.set_option(pmd_);
 | |
|         ws.read_message_max(64 * 1024 * 1024);
 | |
|     }
 | |
| };
 | |
| 
 | |
| int
 | |
| main(
 | |
|     int ac,
 | |
|     char const* av[])
 | |
| {
 | |
|     // Helper for reporting failures
 | |
|     //
 | |
|     using namespace framework;
 | |
|     using namespace beast::http;
 | |
| 
 | |
|     auto const fail =
 | |
|         [&](
 | |
|             std::string const& what,
 | |
|             error_code const& ec)
 | |
|         {
 | |
|             std::cerr <<
 | |
|                 av[0] << ": " <<
 | |
|                 what << " failed, " <<
 | |
|                 ec.message() <<
 | |
|                 std::endl;
 | |
|             return EXIT_FAILURE;
 | |
|         };
 | |
| 
 | |
|     namespace po = boost::program_options;
 | |
|     po::options_description desc("Options");
 | |
| 
 | |
|     desc.add_options()
 | |
|         ("root,r",      po::value<std::string>()->default_value("."),
 | |
|                         "Set the root directory for serving files")
 | |
|         ("port,p",      po::value<std::uint16_t>()->default_value(1000),
 | |
|                         "Set the base port number for the server")
 | |
|         ("ip",          po::value<std::string>()->default_value("0.0.0.0"),
 | |
|                         "Set the IP address to bind to, \"0.0.0.0\" for all")
 | |
|         ("threads,n",   po::value<std::size_t>()->default_value(4),
 | |
|                         "Set the number of threads to use")
 | |
|         ;
 | |
|     po::variables_map vm;
 | |
|     po::store(po::parse_command_line(ac, av, desc), vm);
 | |
| 
 | |
|     // Get the IP address from the options
 | |
|     std::string const ip = vm["ip"].as<std::string>();
 | |
|     
 | |
|     // Get the port number from the options
 | |
|     std::uint16_t const port = vm["port"].as<std::uint16_t>();
 | |
| 
 | |
|     // Build an endpoint from the address and port
 | |
|     address_type const addr{address_type::from_string(ip)};
 | |
| 
 | |
|     // Get the number of threads from the command line
 | |
|     std::size_t const threads = vm["threads"].as<std::size_t>();
 | |
| 
 | |
|     // Get the root path from the command line
 | |
|     boost::filesystem::path const root =  vm["root"].as<std::string>();
 | |
| 
 | |
|     // These settings will be applied to all new websocket connections
 | |
|     beast::websocket::permessage_deflate pmd;
 | |
|     pmd.client_enable = true;
 | |
|     pmd.server_enable = true;
 | |
|     pmd.compLevel = 3;
 | |
| 
 | |
|     error_code ec;
 | |
| 
 | |
|     // Create our server instance with the specified number of threads
 | |
|     server instance{threads};
 | |
| 
 | |
|     {
 | |
|         // Install an asynchronous WebSocket echo port handler
 | |
|         //
 | |
|         auto wsp = instance.make_port<ws_async_port>(
 | |
|             ec,
 | |
|             endpoint_type{addr, port},
 | |
|             instance,
 | |
|             std::cout,
 | |
|             set_ws_options{pmd}
 | |
|         );
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("ws_async_port", ec);
 | |
| 
 | |
|         // Install an asynchronous HTTP port handler
 | |
|         //
 | |
|         auto sp = instance.make_port<http_async_port<
 | |
|                 ws_upgrade_service<ws_async_port>,
 | |
|                 file_service
 | |
|             >>(
 | |
|             ec,
 | |
|             endpoint_type{addr,
 | |
|                 static_cast<unsigned short>(port + 1)},
 | |
|             instance,
 | |
|             std::cout);
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("http_async_port", ec);
 | |
| 
 | |
|         // Set up the ws_upgrade_service. We will route upgrade
 | |
|         // requests to the websocket port handler created earlier.
 | |
|         //
 | |
|         sp->template init<0>(
 | |
|             ec,
 | |
|             wsp                     // The websocket port handler
 | |
|             );
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("http_async_port/ws_upgrade_service", ec);
 | |
| 
 | |
|         // Set up the file_service to point to the root path.
 | |
|         //
 | |
|         sp->template init<1>(
 | |
|             ec,
 | |
|             root,                   // The root path
 | |
|             "http_async_port"       // The value for the Server field
 | |
|             );
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("http_async_port/file_service", ec);
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         // Install a synchronous WebSocket echo port handler
 | |
|         //
 | |
|         auto wsp = instance.make_port<ws_sync_port>(
 | |
|             ec,
 | |
|             endpoint_type{addr,
 | |
|                 static_cast<unsigned short>(port + 2)},
 | |
|             instance,
 | |
|             std::cout,
 | |
|             set_ws_options{pmd});
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("ws_sync_port", ec);
 | |
| 
 | |
| 
 | |
|         // Install a synchronous HTTP port handler
 | |
|         //
 | |
|         auto sp = instance.make_port<http_sync_port<
 | |
|                 ws_upgrade_service<ws_sync_port>,
 | |
|                 file_service
 | |
|             >>(
 | |
|             ec,
 | |
|             endpoint_type{addr,
 | |
|                 static_cast<unsigned short>(port + 3)},
 | |
|             instance,
 | |
|             std::cout);
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("http_sync_port", ec);
 | |
| 
 | |
|         // Set up the ws_upgrade_service. We will route upgrade
 | |
|         // requests to the websocket port handler created earlier.
 | |
|         //
 | |
|         sp->template init<0>(
 | |
|             ec,
 | |
|             wsp
 | |
|             );
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("http_sync_port/ws_upgrade_service", ec);
 | |
| 
 | |
|         // Set up the file_service to point to the root path.
 | |
|         //
 | |
|         sp->template init<1>(
 | |
|             ec,
 | |
|             root,
 | |
|             "http_sync_port"
 | |
|             );
 | |
| 
 | |
|         if(ec)
 | |
|             return fail("http_sync_port/file_service", ec);
 | |
|     }
 | |
| 
 | |
|     sig_wait();
 | |
| }
 |