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 67 friend class connection<config>; 68 server()69 explicit server() : endpoint_type(true) 70 { 71 endpoint_type::m_alog.write(log::alevel::devel, "server constructor"); 72 } 73 74 /// Destructor 75 ~server<config>() {} 76 77 #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ 78 // no copy constructor because endpoints are not copyable 79 server<config>(server<config> &) = delete; 80 81 // no copy assignment operator because endpoints are not copyable 82 server<config> & operator=(server<config> const &) = delete; 83 #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ 84 85 #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ 86 /// Move constructor 87 server<config>(server<config> && o) : endpoint<connection<config>,config>(std::move(o)) {} 88 89 #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ 90 // no move assignment operator because of const member variables 91 server<config> & operator=(server<config> &&) = delete; 92 #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ 93 94 #endif // _WEBSOCKETPP_MOVE_SEMANTICS_ 95 96 /// Create and initialize a new connection 97 /** 98 * The connection will be initialized and ready to begin. Call its start() 99 * method to begin the processing loop. 100 * 101 * Note: The connection must either be started or terminated using 102 * connection::terminate in order to avoid memory leaks. 103 * 104 * @return A pointer to the new connection. 105 */ get_connection()106 connection_ptr get_connection() { 107 return endpoint_type::create_connection(); 108 } 109 110 /// Starts the server's async connection acceptance loop (exception free) 111 /** 112 * Initiates the server connection acceptance loop. Must be called after 113 * listen. This method will have no effect until the underlying io_service 114 * starts running. It may be called after the io_service is already running. 115 * 116 * Refer to documentation for the transport policy you are using for 117 * instructions on how to stop this acceptance loop. 118 * 119 * @param [out] ec A status code indicating an error, if any. 120 */ start_accept(lib::error_code & ec)121 void start_accept(lib::error_code & ec) { 122 if (!transport_type::is_listening()) { 123 ec = error::make_error_code(error::async_accept_not_listening); 124 return; 125 } 126 127 ec = lib::error_code(); 128 connection_ptr con = get_connection(); 129 130 transport_type::async_accept( 131 lib::static_pointer_cast<transport_con_type>(con), 132 lib::bind(&type::handle_accept,this,con,lib::placeholders::_1), 133 ec 134 ); 135 136 if (ec && con) { 137 // If the connection was constructed but the accept failed, 138 // terminate the connection to prevent memory leaks 139 con->terminate(lib::error_code()); 140 } 141 } 142 143 /// Starts the server's async connection acceptance loop 144 /** 145 * Initiates the server connection acceptance loop. Must be called after 146 * listen. This method will have no effect until the underlying io_service 147 * starts running. It may be called after the io_service is already running. 148 * 149 * Refer to documentation for the transport policy you are using for 150 * instructions on how to stop this acceptance loop. 151 */ start_accept()152 void start_accept() { 153 lib::error_code ec; 154 start_accept(ec); 155 if (ec) { 156 throw exception(ec); 157 } 158 } 159 160 /// Handler callback for start_accept handle_accept(connection_ptr con,lib::error_code const & ec)161 void handle_accept(connection_ptr con, lib::error_code const & ec) { 162 if (ec) { 163 con->terminate(ec); 164 165 if (ec == error::operation_canceled) { 166 endpoint_type::m_elog.write(log::elevel::info, 167 "handle_accept error: "+ec.message()); 168 } else { 169 endpoint_type::m_elog.write(log::elevel::rerror, 170 "handle_accept error: "+ec.message()); 171 } 172 } else { 173 con->start(); 174 } 175 176 lib::error_code start_ec; 177 start_accept(start_ec); 178 if (start_ec == error::async_accept_not_listening) { 179 endpoint_type::m_elog.write(log::elevel::info, 180 "Stopping acceptance of new connections because the underlying transport is no longer listening."); 181 } else if (start_ec) { 182 endpoint_type::m_elog.write(log::elevel::rerror, 183 "Restarting async_accept loop failed: "+ec.message()); 184 } 185 } 186 }; 187 188 } // namespace websocketpp 189 190 #endif //WEBSOCKETPP_SERVER_ENDPOINT_HPP 191