1 /* 2 * Copyright (c) 2014, Peter Thorson. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * * Neither the name of the WebSocket++ Project nor the 12 * names of its contributors may be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 #ifndef WEBSOCKETPP_SERVER_ENDPOINT_HPP 29 #define WEBSOCKETPP_SERVER_ENDPOINT_HPP 30 31 #include <websocketpp/endpoint.hpp> 32 33 #include <websocketpp/logger/levels.hpp> 34 35 #include <websocketpp/common/system_error.hpp> 36 37 namespace websocketpp { 38 39 /// Server endpoint role based on the given config 40 /** 41 * 42 */ 43 template <typename config> 44 class server : public endpoint<connection<config>,config> { 45 public: 46 /// Type of this endpoint 47 typedef server<config> type; 48 49 /// Type of the endpoint concurrency component 50 typedef typename config::concurrency_type concurrency_type; 51 /// Type of the endpoint transport component 52 typedef typename config::transport_type transport_type; 53 54 /// Type of the connections this server will create 55 typedef connection<config> connection_type; 56 /// Type of a shared pointer to the connections this server will create 57 typedef typename connection_type::ptr connection_ptr; 58 59 /// Type of the connection transport component 60 typedef typename transport_type::transport_con_type transport_con_type; 61 /// Type of a shared pointer to the connection transport component 62 typedef typename transport_con_type::ptr transport_con_ptr; 63 64 /// Type of the endpoint component of this server 65 typedef endpoint<connection_type,config> endpoint_type; 66 server()67 explicit server() : endpoint_type(true) 68 { 69 endpoint_type::m_alog.write(log::alevel::devel, "server constructor"); 70 } 71 72 /// Create and initialize a new connection 73 /** 74 * The connection will be initialized and ready to begin. Call its start() 75 * method to begin the processing loop. 76 * 77 * Note: The connection must either be started or terminated using 78 * connection::terminate in order to avoid memory leaks. 79 * 80 * @return A pointer to the new connection. 81 */ get_connection()82 connection_ptr get_connection() { 83 return endpoint_type::create_connection(); 84 } 85 86 /// Starts the server's async connection acceptance loop (exception free) 87 /** 88 * Initiates the server connection acceptance loop. Must be called after 89 * listen. This method will have no effect until the underlying io_service 90 * starts running. It may be called after the io_service is already running. 91 * 92 * Refer to documentation for the transport policy you are using for 93 * instructions on how to stop this acceptance loop. 94 * 95 * @param [out] ec A status code indicating an error, if any. 96 */ start_accept(lib::error_code & ec)97 void start_accept(lib::error_code & ec) { 98 if (!transport_type::is_listening()) { 99 ec = error::make_error_code(error::async_accept_not_listening); 100 return; 101 } 102 103 ec = lib::error_code(); 104 connection_ptr con = get_connection(); 105 106 transport_type::async_accept( 107 lib::static_pointer_cast<transport_con_type>(con), 108 lib::bind(&type::handle_accept,this,con,lib::placeholders::_1), 109 ec 110 ); 111 112 if (ec && con) { 113 // If the connection was constructed but the accept failed, 114 // terminate the connection to prevent memory leaks 115 con->terminate(lib::error_code()); 116 } 117 } 118 119 /// Starts the server's async connection acceptance loop 120 /** 121 * Initiates the server connection acceptance loop. Must be called after 122 * listen. This method will have no effect until the underlying io_service 123 * starts running. It may be called after the io_service is already running. 124 * 125 * Refer to documentation for the transport policy you are using for 126 * instructions on how to stop this acceptance loop. 127 */ start_accept()128 void start_accept() { 129 lib::error_code ec; 130 start_accept(ec); 131 if (ec) { 132 throw exception(ec); 133 } 134 } 135 136 /// Handler callback for start_accept handle_accept(connection_ptr con,lib::error_code const & ec)137 void handle_accept(connection_ptr con, lib::error_code const & ec) { 138 if (ec) { 139 con->terminate(ec); 140 141 if (ec == error::operation_canceled) { 142 endpoint_type::m_elog.write(log::elevel::info, 143 "handle_accept error: "+ec.message()); 144 } else { 145 endpoint_type::m_elog.write(log::elevel::rerror, 146 "handle_accept error: "+ec.message()); 147 } 148 } else { 149 con->start(); 150 } 151 152 lib::error_code start_ec; 153 start_accept(start_ec); 154 if (start_ec == error::async_accept_not_listening) { 155 endpoint_type::m_elog.write(log::elevel::info, 156 "Stopping acceptance of new connections because the underlying transport is no longer listening."); 157 } else if (start_ec) { 158 endpoint_type::m_elog.write(log::elevel::rerror, 159 "Restarting async_accept loop failed: "+ec.message()); 160 } 161 } 162 }; 163 164 } // namespace websocketpp 165 166 #endif //WEBSOCKETPP_SERVER_ENDPOINT_HPP 167