Bug #11301 » 0002-WT-11302-avoid-use-after-free-with-closed-listeners.patch
| src/http/Server.C | ||
|---|---|---|
|
const std::string &address,
|
||
|
Wt::AsioWrapper::error_code &errc)
|
||
|
{
|
||
|
tcp_listeners_.push_back(TcpListener(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back().acceptor;
|
||
|
tcp_listeners_.push_back(std::make_shared<TcpListener>(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back()->acceptor;
|
||
|
tcp_acceptor.open(endpoint.protocol());
|
||
|
tcp_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
|
||
|
#ifndef WT_WIN32
|
||
| ... | ... | |
|
LOG_INFO_S(&wt_, "started server: " << addressString("http", endpoint, address));
|
||
|
tcp_listeners_.back().new_connection.reset
|
||
|
tcp_listeners_.back()->new_connection.reset
|
||
|
(new TcpConnection(wt_.ioService(), this, connection_manager_,
|
||
|
request_handler_));
|
||
|
} else {
|
||
| ... | ... | |
|
const std::string &address,
|
||
|
Wt::AsioWrapper::error_code &errc)
|
||
|
{
|
||
|
ssl_listeners_.push_back(SslListener(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back().acceptor;
|
||
|
ssl_listeners_.push_back(std::make_shared<SslListener>(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
|
||
|
asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back()->acceptor;
|
||
|
ssl_acceptor.open(endpoint.protocol());
|
||
|
ssl_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
|
||
|
#ifndef WT_WIN32
|
||
| ... | ... | |
|
LOG_INFO_S(&wt_, "started server: " << addressString("https", endpoint, address));
|
||
|
ssl_listeners_.back().new_connection.reset
|
||
|
ssl_listeners_.back()->new_connection.reset
|
||
|
(new SslConnection(wt_.ioService(), this, ssl_context_, connection_manager_,
|
||
|
request_handler_));
|
||
|
} else {
|
||
| ... | ... | |
|
if (ssl_listeners_.empty())
|
||
|
return -1;
|
||
|
else
|
||
|
return ssl_listeners_.front().acceptor.local_endpoint().port();
|
||
|
return ssl_listeners_.front()->acceptor.local_endpoint().port();
|
||
|
#else // HTTP_WITH_SSL
|
||
|
return -1;
|
||
|
#endif // HTTP_WITH_SSL
|
||
|
}
|
||
|
return tcp_listeners_.front().acceptor.local_endpoint().port();
|
||
|
return tcp_listeners_.front()->acceptor.local_endpoint().port();
|
||
|
}
|
||
|
void Server::startAccept()
|
||
| ... | ... | |
|
* need to access the ConnectionManager mutex in any case).
|
||
|
*/
|
||
|
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i) {
|
||
|
asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i].acceptor;
|
||
|
TcpConnectionPtr &new_connection = tcp_listeners_[i].new_connection;
|
||
|
asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i]->acceptor;
|
||
|
TcpConnectionPtr &new_connection = tcp_listeners_[i]->new_connection;
|
||
|
acceptor.async_accept(new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleTcpAccept, this,
|
||
|
&tcp_listeners_[i],
|
||
|
tcp_listeners_[i],
|
||
|
std::placeholders::_1)));
|
||
|
}
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i) {
|
||
|
asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i].acceptor;
|
||
|
SslConnectionPtr &new_connection = ssl_listeners_[i].new_connection;
|
||
|
asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i]->acceptor;
|
||
|
SslConnectionPtr &new_connection = ssl_listeners_[i]->new_connection;
|
||
|
acceptor.async_accept(new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleSslAccept, this,
|
||
|
&ssl_listeners_[i],
|
||
|
ssl_listeners_[i],
|
||
|
std::placeholders::_1)));
|
||
|
}
|
||
|
#endif // HTTP_WITH_SSL
|
||
| ... | ... | |
|
if (!err) {
|
||
|
// tcp_listeners_.front() should be fine here:
|
||
|
// it should be the only acceptor when this is a session process
|
||
|
auto port = tcp_listeners_.front().acceptor.local_endpoint().port();
|
||
|
auto port = tcp_listeners_.front()->acceptor.local_endpoint().port();
|
||
|
Wt::WStringStream ss;
|
||
|
ss << "port:" << port << "\n";
|
||
|
auto buf = std::make_shared<std::string>(ss.str());
|
||
| ... | ... | |
|
void Server::handleResume()
|
||
|
{
|
||
|
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
|
||
|
tcp_listeners_[i].acceptor.close();
|
||
|
tcp_listeners_[i]->acceptor.close();
|
||
|
tcp_listeners_.clear();
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
|
||
|
ssl_listeners_[i].acceptor.close();
|
||
|
ssl_listeners_[i]->acceptor.close();
|
||
|
ssl_listeners_.clear();
|
||
|
#endif // HTTP_WITH_SSL
|
||
|
start();
|
||
|
}
|
||
|
void Server::handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e)
|
||
|
void Server::handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e)
|
||
|
{
|
||
|
if (!e) {
|
||
|
connection_manager_.start(listener->new_connection);
|
||
|
listener->new_connection.reset(new TcpConnection(wt_.ioService(), this,
|
||
|
connection_manager_, request_handler_));
|
||
|
} else if (!listener->acceptor.is_open()) {
|
||
|
auto l = listener.lock();
|
||
|
if (!l || (e && !l->acceptor.is_open())) {
|
||
|
// server shutdown
|
||
|
LOG_DEBUG("handleTcpAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
|
||
|
LOG_DEBUG("handleTcpAccept: async_accept error (no listener, probably server shutdown): " << e.message());
|
||
|
return;
|
||
|
}
|
||
|
if (!e) {
|
||
|
connection_manager_.start(l->new_connection);
|
||
|
l->new_connection.reset(new TcpConnection(wt_.ioService(), this,
|
||
|
connection_manager_, request_handler_));
|
||
|
} else {
|
||
|
LOG_ERROR("handleTcpAccept: async_accept error: " << e.message());
|
||
|
}
|
||
|
listener->acceptor.async_accept(listener->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleTcpAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
l->acceptor.async_accept(l->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleTcpAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
}
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
void Server::handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e)
|
||
|
void Server::handleSslAccept(const std::weak_ptr<SslListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e)
|
||
|
{
|
||
|
if (!e) {
|
||
|
connection_manager_.start(listener->new_connection);
|
||
|
listener->new_connection.reset(new SslConnection(wt_.ioService(), this,
|
||
|
ssl_context_, connection_manager_, request_handler_));
|
||
|
} else if (!listener->acceptor.is_open()) {
|
||
|
auto l = listener.lock();
|
||
|
if (!l || (e && !l->acceptor.is_open())) {
|
||
|
// server shutdown
|
||
|
LOG_DEBUG("handleSslAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
|
||
|
LOG_DEBUG("handleSslAccept: async_accept error (no listener, probably server shutdown): " << e.message());
|
||
|
return;
|
||
|
}
|
||
|
if (!e) {
|
||
|
connection_manager_.start(l->new_connection);
|
||
|
l->new_connection.reset(new SslConnection(wt_.ioService(), this,
|
||
|
ssl_context_, connection_manager_, request_handler_));
|
||
|
} else {
|
||
|
LOG_ERROR("handleSslAccept: async_accept error: " << e.message());
|
||
|
}
|
||
|
listener->acceptor.async_accept(listener->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleSslAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
l->acceptor.async_accept(l->new_connection->socket(),
|
||
|
accept_strand_.wrap(
|
||
|
std::bind(&Server::handleSslAccept, this,
|
||
|
listener, std::placeholders::_1)));
|
||
|
}
|
||
|
#endif // HTTP_WITH_SSL
|
||
| ... | ... | |
|
// operations. Once all operations have finished the io_service::run() call
|
||
|
// will exit.
|
||
|
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
|
||
|
tcp_listeners_[i].acceptor.close();
|
||
|
tcp_listeners_[i]->acceptor.close();
|
||
|
tcp_listeners_.clear();
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
|
||
|
ssl_listeners_[i].acceptor.close();
|
||
|
ssl_listeners_[i]->acceptor.close();
|
||
|
ssl_listeners_.clear();
|
||
|
#endif // HTTP_WITH_SSL
|
||
| src/http/Server.h | ||
|---|---|---|
|
#include "Wt/WLogger.h"
|
||
|
#include <memory>
|
||
|
namespace http {
|
||
|
namespace server {
|
||
| ... | ... | |
|
void closeParentConnection();
|
||
|
/// Handle completion of an asynchronous accept operation.
|
||
|
void handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e);
|
||
|
void handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e);
|
||
|
/// Handle a request to stop the server.
|
||
|
void handleStop();
|
||
| ... | ... | |
|
Wt::AsioWrapper::strand accept_strand_;
|
||
|
/// Acceptors used to listen for incoming http connections.
|
||
|
std::vector<TcpListener> tcp_listeners_;
|
||
|
std::vector<std::shared_ptr<TcpListener>> tcp_listeners_;
|
||
|
#ifdef HTTP_WITH_SSL
|
||
|
struct SslListener {
|
||
| ... | ... | |
|
asio::ssl::context ssl_context_;
|
||
|
/// Acceptors used to listen for incoming https connections
|
||
|
std::vector<SslListener> ssl_listeners_;
|
||
|
std::vector<std::shared_ptr<SslListener>> ssl_listeners_;
|
||
|
/// Add new SSL listener, called from start()
|
||
|
void addSslListener(asio::ip::tcp::resolver &resolver,
|
||
| ... | ... | |
|
Wt::AsioWrapper::error_code &errc);
|
||
|
/// Handle completion of an asynchronous SSL accept operation.
|
||
|
void handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e);
|
||
|
void handleSslAccept(const std::weak_ptr<SslListener>& listener,
|
||
|
const Wt::AsioWrapper::error_code& e);
|
||
|
#endif // HTTP_WITH_SSL
|
||
|
void handleTimeout(asio::steady_timer *timer,
|
||
- « Previous
- 1
- 2
- 3
- 4
- Next »