10 #include <boost/asio.hpp>
11 #include <boost/bind.hpp>
12 #include <boost/thread/mutex.hpp>
13 #include <pion/PionAdminRights.hpp>
14 #include <pion/net/TCPServer.hpp>
16 using boost::asio::ip::tcp;
26 : m_logger(PION_GET_LOGGER(
"pion.net.TCPServer")),
27 m_active_scheduler(scheduler),
28 m_tcp_acceptor(m_active_scheduler.getIOService()),
30 m_ssl_context(m_active_scheduler.getIOService(), boost::asio::ssl::context::sslv23),
34 m_endpoint(tcp::v4(), tcp_port), m_ssl_flag(false), m_is_listening(false)
38 : m_logger(PION_GET_LOGGER(
"pion.net.TCPServer")),
39 m_active_scheduler(scheduler),
40 m_tcp_acceptor(m_active_scheduler.getIOService()),
42 m_ssl_context(m_active_scheduler.getIOService(), boost::asio::ssl::context::sslv23),
46 m_endpoint(endpoint), m_ssl_flag(false), m_is_listening(false)
50 : m_logger(PION_GET_LOGGER(
"pion.net.TCPServer")),
51 m_default_scheduler(), m_active_scheduler(m_default_scheduler),
52 m_tcp_acceptor(m_active_scheduler.getIOService()),
54 m_ssl_context(m_active_scheduler.getIOService(), boost::asio::ssl::context::sslv23),
58 m_endpoint(tcp::v4(), tcp_port), m_ssl_flag(false), m_is_listening(false)
62 : m_logger(PION_GET_LOGGER(
"pion.net.TCPServer")),
63 m_default_scheduler(), m_active_scheduler(m_default_scheduler),
64 m_tcp_acceptor(m_active_scheduler.getIOService()),
66 m_ssl_context(m_active_scheduler.getIOService(), boost::asio::ssl::context::sslv23),
70 m_endpoint(endpoint), m_ssl_flag(false), m_is_listening(false)
76 boost::mutex::scoped_lock server_lock(m_mutex);
78 if (! m_is_listening) {
87 m_tcp_acceptor.open(m_endpoint.protocol());
91 m_tcp_acceptor.set_option(tcp::acceptor::reuse_address(
true));
93 m_tcp_acceptor.bind(m_endpoint);
94 if (m_endpoint.port() == 0) {
96 m_endpoint = m_tcp_acceptor.local_endpoint();
98 m_tcp_acceptor.listen();
99 }
catch (std::exception& e) {
100 PION_LOG_ERROR(
m_logger,
"Unable to bind to port " <<
getPort() <<
": " << e.what());
104 m_is_listening =
true;
107 server_lock.unlock();
118 boost::mutex::scoped_lock server_lock(m_mutex);
120 if (m_is_listening) {
123 m_is_listening =
false;
126 m_tcp_acceptor.close();
128 if (! wait_until_finished) {
130 std::for_each(m_conn_pool.begin(), m_conn_pool.end(),
135 while (! m_conn_pool.empty()) {
137 if (pruneConnections() == 0)
140 PION_LOG_INFO(
m_logger,
"Waiting for open connections to finish");
149 m_server_has_stopped.notify_all();
155 boost::mutex::scoped_lock server_lock(m_mutex);
156 while (m_is_listening) {
158 m_server_has_stopped.wait(server_lock);
167 m_ssl_context.set_options(boost::asio::ssl::context::default_workarounds
168 | boost::asio::ssl::context::no_sslv2
169 | boost::asio::ssl::context::single_dh_use);
170 m_ssl_context.use_certificate_file(pem_key_file, boost::asio::ssl::context::pem);
171 m_ssl_context.use_private_key_file(pem_key_file, boost::asio::ssl::context::pem);
175 void TCPServer::listen(
void)
178 boost::mutex::scoped_lock server_lock(m_mutex);
180 if (m_is_listening) {
183 m_ssl_context, m_ssl_flag,
184 boost::bind(&TCPServer::finishConnection,
191 m_conn_pool.insert(new_connection);
194 new_connection->async_accept(m_tcp_acceptor,
195 boost::bind(&TCPServer::handleAccept,
196 this, new_connection,
197 boost::asio::placeholders::error));
201 void TCPServer::handleAccept(TCPConnectionPtr& tcp_conn,
202 const boost::system::error_code& accept_error)
207 if (m_is_listening) {
209 PION_LOG_WARN(
m_logger,
"Accept error on port " <<
getPort() <<
": " << accept_error.message());
211 finishConnection(tcp_conn);
214 PION_LOG_DEBUG(
m_logger,
"New" << (tcp_conn->getSSLFlag() ?
" SSL " :
" ")
215 <<
"connection on port " <<
getPort());
219 if (m_is_listening) listen();
223 if (tcp_conn->getSSLFlag()) {
224 tcp_conn->async_handshake_server(boost::bind(&TCPServer::handleSSLHandshake,
226 boost::asio::placeholders::error));
234 void TCPServer::handleSSLHandshake(TCPConnectionPtr& tcp_conn,
235 const boost::system::error_code& handshake_error)
237 if (handshake_error) {
240 <<
" (" << handshake_error.message() <<
')');
241 finishConnection(tcp_conn);
244 PION_LOG_DEBUG(
m_logger,
"SSL handshake succeeded on port " <<
getPort());
249 void TCPServer::finishConnection(TCPConnectionPtr& tcp_conn)
251 boost::mutex::scoped_lock server_lock(m_mutex);
252 if (m_is_listening && tcp_conn->getKeepAlive()) {
261 ConnectionPool::iterator conn_itr = m_conn_pool.find(tcp_conn);
262 if (conn_itr != m_conn_pool.end())
263 m_conn_pool.erase(conn_itr);
266 if (!m_is_listening && m_conn_pool.empty())
267 m_no_more_connections.notify_all();
271 std::size_t TCPServer::pruneConnections(
void)
274 ConnectionPool::iterator conn_itr = m_conn_pool.begin();
275 while (conn_itr != m_conn_pool.end()) {
276 if (conn_itr->unique()) {
277 PION_LOG_WARN(
m_logger,
"Closing orphaned connection on port " <<
getPort());
278 ConnectionPool::iterator erase_itr = conn_itr;
280 (*erase_itr)->close();
281 m_conn_pool.erase(erase_itr);
288 return m_conn_pool.size();
293 boost::mutex::scoped_lock server_lock(m_mutex);
294 return (m_is_listening ? (m_conn_pool.size() - 1) : m_conn_pool.size());