108 lines
2.9 KiB
C++
108 lines
2.9 KiB
C++
|
// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers
|
||
|
//
|
||
|
// This file is part of Bytecoin.
|
||
|
//
|
||
|
// Bytecoin is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// Bytecoin is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU Lesser General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU Lesser General Public License
|
||
|
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
#include "HttpServer.h"
|
||
|
#include <boost/scope_exit.hpp>
|
||
|
|
||
|
#include <HTTP/HttpParser.h>
|
||
|
#include <System/InterruptedException.h>
|
||
|
#include <System/TcpStream.h>
|
||
|
#include <System/Ipv4Address.h>
|
||
|
|
||
|
using namespace Logging;
|
||
|
|
||
|
namespace CryptoNote {
|
||
|
|
||
|
HttpServer::HttpServer(System::Dispatcher& dispatcher, Logging::ILogger& log)
|
||
|
: m_dispatcher(dispatcher), logger(log, "HttpServer"), m_shutdownCompleteEvent(dispatcher) {
|
||
|
|
||
|
}
|
||
|
|
||
|
void HttpServer::start(const std::string& address, uint16_t port) {
|
||
|
m_listener = System::TcpListener(m_dispatcher, System::Ipv4Address(address), port);
|
||
|
++m_spawnCount;
|
||
|
m_dispatcher.spawn(std::bind(&HttpServer::acceptLoop, this));
|
||
|
}
|
||
|
|
||
|
void HttpServer::stop() {
|
||
|
m_listener.stop();
|
||
|
for (auto connPtr : m_connections) {
|
||
|
connPtr->stop();
|
||
|
}
|
||
|
|
||
|
if (m_spawnCount) {
|
||
|
m_shutdownCompleteEvent.wait();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HttpServer::acceptLoop() {
|
||
|
try {
|
||
|
|
||
|
System::TcpConnection connection;
|
||
|
bool accepted = false;
|
||
|
|
||
|
while (!accepted) {
|
||
|
try {
|
||
|
connection = m_listener.accept();
|
||
|
accepted = true;
|
||
|
} catch (System::InterruptedException&) {
|
||
|
throw;
|
||
|
} catch (std::exception&) {
|
||
|
// try again
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_connections.insert(&connection);
|
||
|
BOOST_SCOPE_EXIT_ALL(this, &connection) {
|
||
|
m_connections.erase(&connection); };
|
||
|
|
||
|
auto addr = connection.getPeerAddressAndPort();
|
||
|
|
||
|
logger(DEBUGGING) << "Incoming connection from " << addr.first.toDottedDecimal() << ":" << addr.second;
|
||
|
|
||
|
++m_spawnCount;
|
||
|
m_dispatcher.spawn(std::bind(&HttpServer::acceptLoop, this));
|
||
|
|
||
|
System::TcpStreambuf streambuf(connection);
|
||
|
std::iostream stream(&streambuf);
|
||
|
HttpParser parser;
|
||
|
|
||
|
for (;;) {
|
||
|
HttpRequest req;
|
||
|
HttpResponse resp;
|
||
|
|
||
|
parser.receiveRequest(stream, req);
|
||
|
processRequest(req, resp);
|
||
|
|
||
|
stream << resp;
|
||
|
stream.flush();
|
||
|
}
|
||
|
|
||
|
logger(DEBUGGING) << "Closing connection from " << addr.first.toDottedDecimal() << ":" << addr.second << " total=" << m_connections.size();
|
||
|
|
||
|
} catch (System::InterruptedException&) {
|
||
|
} catch (std::exception& e) {
|
||
|
logger(WARNING) << "Connection error: " << e.what();
|
||
|
}
|
||
|
|
||
|
if (--m_spawnCount == 0) {
|
||
|
m_shutdownCompleteEvent.set();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|