New TCP server
This commit is contained in:
parent
6b1858d965
commit
6d741947cb
15 changed files with 950 additions and 1 deletions
|
@ -83,7 +83,7 @@ if(STATIC)
|
|||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
endif()
|
||||
find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options)
|
||||
find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options coroutine context)
|
||||
if((${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54))
|
||||
message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA")
|
||||
endif()
|
||||
|
|
98
src/System/Event.cpp
Normal file
98
src/System/Event.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2012-2014, 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 "Event.h"
|
||||
#include <cassert>
|
||||
#include "System.h"
|
||||
|
||||
struct Event::Waiter {
|
||||
Event::Waiter* next;
|
||||
void* context;
|
||||
};
|
||||
|
||||
Event::Event() : system(nullptr) {
|
||||
}
|
||||
|
||||
Event::Event(System& system) : system(&system), first(nullptr), state(false) {
|
||||
}
|
||||
|
||||
Event::Event(Event&& other) : system(other.system) {
|
||||
if (other.system != nullptr) {
|
||||
first = other.first;
|
||||
if (other.first != nullptr) {
|
||||
last = other.last;
|
||||
}
|
||||
|
||||
state = other.state;
|
||||
other.system = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
assert(first == nullptr);
|
||||
}
|
||||
|
||||
Event& Event::operator=(Event&& other) {
|
||||
assert(first == nullptr);
|
||||
system = other.system;
|
||||
if (other.system != nullptr) {
|
||||
first = other.first;
|
||||
if (other.first != nullptr) {
|
||||
last = other.last;
|
||||
}
|
||||
|
||||
state = other.state;
|
||||
other.system = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Event::get() const {
|
||||
assert(system != nullptr);
|
||||
return state;
|
||||
}
|
||||
|
||||
void Event::clear() {
|
||||
assert(system != nullptr);
|
||||
state = false;
|
||||
}
|
||||
|
||||
void Event::set() {
|
||||
assert(system != nullptr);
|
||||
state = true;
|
||||
for (Waiter* waiter = first; waiter != nullptr; waiter = waiter->next) {
|
||||
system->pushContext(waiter->context);
|
||||
}
|
||||
|
||||
first = nullptr;
|
||||
}
|
||||
|
||||
void Event::wait() {
|
||||
assert(system != nullptr);
|
||||
Waiter waiter = {nullptr, system->getCurrentContext()};
|
||||
if (first != nullptr) {
|
||||
last->next = &waiter;
|
||||
} else {
|
||||
first = &waiter;
|
||||
}
|
||||
|
||||
last = &waiter;
|
||||
while (!state) {
|
||||
system->yield();
|
||||
}
|
||||
}
|
43
src/System/Event.h
Normal file
43
src/System/Event.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
class System;
|
||||
|
||||
class Event {
|
||||
public:
|
||||
Event();
|
||||
explicit Event(System& system);
|
||||
Event(const Event&) = delete;
|
||||
Event(Event&& other);
|
||||
~Event();
|
||||
Event& operator=(const Event&) = delete;
|
||||
Event& operator=(Event&& other);
|
||||
bool get() const;
|
||||
void clear();
|
||||
void set();
|
||||
void wait();
|
||||
|
||||
private:
|
||||
struct Waiter;
|
||||
|
||||
System* system;
|
||||
Waiter* first;
|
||||
Waiter* last;
|
||||
bool state;
|
||||
};
|
133
src/System/System.cpp
Normal file
133
src/System/System.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
// Copyright (c) 2012-2014, 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 "System.h"
|
||||
#include <iostream>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/context/fcontext.hpp>
|
||||
|
||||
namespace {
|
||||
void contextProcedureStatic(intptr_t context) {
|
||||
reinterpret_cast<System*>(context)->contextProcedure();
|
||||
}
|
||||
}
|
||||
|
||||
System::System() {
|
||||
ioService = new boost::asio::io_service;
|
||||
work = new boost::asio::io_service::work(*static_cast<boost::asio::io_service*>(ioService));
|
||||
currentContext = new boost::context::fcontext_t;
|
||||
}
|
||||
|
||||
System::~System() {
|
||||
assert(procedures.empty());
|
||||
assert(resumingContexts.empty());
|
||||
while (!contexts.empty()) {
|
||||
|
||||
delete static_cast<boost::context::fcontext_t*>(contexts.top());
|
||||
|
||||
contexts.pop();
|
||||
}
|
||||
delete static_cast<boost::asio::io_service::work*>(work);
|
||||
if (!static_cast<boost::asio::io_service*>(ioService)->stopped()) {
|
||||
static_cast<boost::asio::io_service*>(ioService)->stop();
|
||||
}
|
||||
delete static_cast<boost::asio::io_service*>(ioService);
|
||||
}
|
||||
|
||||
void* System::getCurrentContext() const {
|
||||
|
||||
return currentContext;
|
||||
}
|
||||
|
||||
void* System::getIoService() {
|
||||
return ioService;
|
||||
}
|
||||
|
||||
void System::pushContext(void* context) {
|
||||
resumingContexts.push(context);
|
||||
}
|
||||
|
||||
void System::spawn(std::function<void()>&& procedure) {
|
||||
procedures.emplace(std::move(procedure));
|
||||
}
|
||||
|
||||
void System::wake() {
|
||||
static_cast<boost::asio::io_service*>(ioService)->post([] {});
|
||||
}
|
||||
|
||||
void System::yield() {
|
||||
if (procedures.empty()) {
|
||||
void* context;
|
||||
for (;;) {
|
||||
if (resumingContexts.empty()) {
|
||||
boost::system::error_code errorCode;
|
||||
static_cast<boost::asio::io_service*>(ioService)->run_one(errorCode);
|
||||
if (errorCode) {
|
||||
std::cerr << "boost::asio::io_service::run_onw failed, result=" << errorCode << '.' << std::endl;
|
||||
throw std::runtime_error("System::yield");
|
||||
}
|
||||
} else {
|
||||
context = resumingContexts.front();
|
||||
resumingContexts.pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (context != currentContext) {
|
||||
boost::context::fcontext_t* oldContext = static_cast<boost::context::fcontext_t*>(currentContext);
|
||||
currentContext = context;
|
||||
#if (BOOST_VERSION >= 105600)
|
||||
boost::context::jump_fcontext(oldContext, *static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
|
||||
#else
|
||||
boost::context::jump_fcontext(oldContext, static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
void* context;
|
||||
if (contexts.empty()) {
|
||||
#if (BOOST_VERSION >= 105600)
|
||||
context = new boost::context::fcontext_t(boost::context::make_fcontext(new uint8_t[65536] + 65536, 65536, contextProcedureStatic));
|
||||
#else
|
||||
context = new boost::context::fcontext_t(*boost::context::make_fcontext(new uint8_t[65536] + 65536, 65536, contextProcedureStatic));
|
||||
#endif
|
||||
} else {
|
||||
context = contexts.top();
|
||||
contexts.pop();
|
||||
}
|
||||
|
||||
|
||||
boost::context::fcontext_t* oldContext = static_cast<boost::context::fcontext_t*>(currentContext);
|
||||
currentContext = context;
|
||||
#if (BOOST_VERSION >= 105600)
|
||||
boost::context::jump_fcontext(oldContext, *static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
|
||||
#else
|
||||
boost::context::jump_fcontext(oldContext, static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void System::contextProcedure() {
|
||||
void* context = currentContext;
|
||||
for (;;) {
|
||||
assert(!procedures.empty());
|
||||
std::function<void()> procedure = std::move(procedures.front());
|
||||
procedures.pop();
|
||||
procedure();
|
||||
contexts.push(context);
|
||||
yield();
|
||||
}
|
||||
}
|
46
src/System/System.h
Normal file
46
src/System/System.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
|
||||
class System {
|
||||
public:
|
||||
System();
|
||||
System(const System&) = delete;
|
||||
~System();
|
||||
System& operator=(const System&) = delete;
|
||||
void* getCurrentContext() const;
|
||||
void* getIoService();
|
||||
void pushContext(void* context);
|
||||
void spawn(std::function<void()>&& procedure);
|
||||
void yield();
|
||||
void wake();
|
||||
|
||||
void contextProcedure();
|
||||
|
||||
private:
|
||||
void* ioService;
|
||||
void* work;
|
||||
std::stack<void*> contexts;
|
||||
std::queue<std::function<void()>> procedures;
|
||||
std::queue<void*> resumingContexts;
|
||||
void* currentContext;
|
||||
};
|
110
src/System/TcpConnection.cpp
Normal file
110
src/System/TcpConnection.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
// Copyright (c) 2012-2014, 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 "TcpConnection.h"
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include "System.h"
|
||||
|
||||
TcpConnection::TcpConnection() : system(nullptr) {
|
||||
}
|
||||
|
||||
TcpConnection::TcpConnection(System& system, void* socket) : system(&system), socket(socket), stopped(false) {
|
||||
}
|
||||
|
||||
TcpConnection::TcpConnection(TcpConnection&& other) : system(other.system) {
|
||||
if (other.system != nullptr) {
|
||||
socket = other.socket;
|
||||
stopped = other.stopped;
|
||||
other.system = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TcpConnection::~TcpConnection() {
|
||||
if (system != nullptr) {
|
||||
delete static_cast<boost::asio::ip::tcp::socket*>(socket);
|
||||
}
|
||||
}
|
||||
|
||||
TcpConnection& TcpConnection::operator=(TcpConnection&& other) {
|
||||
if (system != nullptr) {
|
||||
delete static_cast<boost::asio::ip::tcp::socket*>(socket);
|
||||
}
|
||||
|
||||
system = other.system;
|
||||
if (other.system != nullptr) {
|
||||
socket = other.socket;
|
||||
stopped = other.stopped;
|
||||
other.system = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void TcpConnection::start() {
|
||||
stopped = false;
|
||||
}
|
||||
|
||||
void TcpConnection::stop() {
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
size_t TcpConnection::read(uint8_t* data, size_t size) {
|
||||
assert(system != nullptr);
|
||||
if (stopped) {
|
||||
throw std::runtime_error("Stopped");
|
||||
}
|
||||
|
||||
void* context = system->getCurrentContext();
|
||||
boost::system::error_code errorCode;
|
||||
std::size_t transferred;
|
||||
static_cast<boost::asio::ip::tcp::socket*>(socket)->async_read_some(boost::asio::buffer(data, size), [&](const boost::system::error_code& callbackErrorCode, std::size_t callbackTransferred) {
|
||||
errorCode = callbackErrorCode;
|
||||
transferred = callbackTransferred;
|
||||
system->pushContext(context);
|
||||
});
|
||||
|
||||
system->yield();
|
||||
if (errorCode) {
|
||||
throw boost::system::system_error(errorCode);
|
||||
}
|
||||
|
||||
return transferred;
|
||||
}
|
||||
|
||||
void TcpConnection::write(const uint8_t* data, size_t size) {
|
||||
assert(system != nullptr);
|
||||
if (stopped) {
|
||||
throw std::runtime_error("Stopped");
|
||||
}
|
||||
|
||||
void* context = system->getCurrentContext();
|
||||
boost::system::error_code errorCode;
|
||||
std::size_t transferred;
|
||||
boost::asio::async_write(*static_cast<boost::asio::ip::tcp::socket*>(socket), boost::asio::buffer(data, size), [&](const boost::system::error_code& callbackErrorCode, std::size_t callbackTransferred) {
|
||||
errorCode = callbackErrorCode;
|
||||
transferred = callbackTransferred;
|
||||
system->pushContext(context);
|
||||
});
|
||||
|
||||
system->yield();
|
||||
if (errorCode) {
|
||||
throw boost::system::system_error(errorCode);
|
||||
}
|
||||
|
||||
assert(transferred == size);
|
||||
}
|
47
src/System/TcpConnection.h
Normal file
47
src/System/TcpConnection.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class System;
|
||||
|
||||
class TcpConnection {
|
||||
public:
|
||||
TcpConnection();
|
||||
TcpConnection(const TcpConnection&) = delete;
|
||||
TcpConnection(TcpConnection&& other);
|
||||
~TcpConnection();
|
||||
TcpConnection& operator=(const TcpConnection&) = delete;
|
||||
TcpConnection& operator=(TcpConnection&& other);
|
||||
void start();
|
||||
void stop();
|
||||
std::size_t read(uint8_t* data, std::size_t size);
|
||||
void write(const uint8_t* data, std::size_t size);
|
||||
|
||||
private:
|
||||
friend class TcpConnector;
|
||||
friend class TcpListener;
|
||||
|
||||
explicit TcpConnection(System& system, void* socket);
|
||||
|
||||
System* system;
|
||||
void* socket;
|
||||
bool stopped;
|
||||
};
|
67
src/System/TcpConnector.cpp
Normal file
67
src/System/TcpConnector.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2012-2014, 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 "TcpConnector.h"
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include "System.h"
|
||||
#include "TcpConnection.h"
|
||||
|
||||
TcpConnector::TcpConnector() : system(nullptr) {
|
||||
}
|
||||
|
||||
TcpConnector::TcpConnector(System& system, const std::string& address, uint16_t port) : system(&system), m_address(address), m_port(port) { }
|
||||
|
||||
TcpConnector::TcpConnector(TcpConnector&& other) : system(other.system) {
|
||||
if (other.system != nullptr) {
|
||||
m_address = other.m_address;
|
||||
m_port = other.m_port;
|
||||
other.system = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TcpConnector::~TcpConnector() {
|
||||
}
|
||||
|
||||
TcpConnector& TcpConnector::operator=(TcpConnector&& other) {
|
||||
system = other.system;
|
||||
if (other.system != nullptr) {
|
||||
m_address = other.m_address;
|
||||
m_port = other.m_port;
|
||||
other.system = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TcpConnection TcpConnector::connect() {
|
||||
assert(system != nullptr);
|
||||
void* context = system->getCurrentContext();
|
||||
boost::asio::ip::tcp::socket* socket = new boost::asio::ip::tcp::socket(*static_cast<boost::asio::io_service*>(system->getIoService()));
|
||||
boost::system::error_code errorCode;
|
||||
socket->async_connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(m_address), m_port), [&](const boost::system::error_code& callbackErrorCode) {
|
||||
errorCode = callbackErrorCode;
|
||||
system->pushContext(context);
|
||||
});
|
||||
|
||||
system->yield();
|
||||
if (errorCode) {
|
||||
delete socket;
|
||||
throw boost::system::system_error(errorCode);
|
||||
}
|
||||
|
||||
return TcpConnection(*system, socket);
|
||||
}
|
41
src/System/TcpConnector.h
Normal file
41
src/System/TcpConnector.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class System;
|
||||
class TcpConnection;
|
||||
|
||||
class TcpConnector {
|
||||
public:
|
||||
TcpConnector();
|
||||
TcpConnector(System& system, const std::string& address, uint16_t port);
|
||||
TcpConnector(const TcpConnector&) = delete;
|
||||
TcpConnector(TcpConnector&& other);
|
||||
~TcpConnector();
|
||||
TcpConnector& operator=(const TcpConnector&) = delete;
|
||||
TcpConnector& operator=(TcpConnector&& other);
|
||||
TcpConnection connect();
|
||||
|
||||
private:
|
||||
System* system;
|
||||
std::string m_address;
|
||||
uint16_t m_port;
|
||||
};
|
88
src/System/TcpListener.cpp
Normal file
88
src/System/TcpListener.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) 2012-2014, 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 "TcpListener.h"
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include "System.h"
|
||||
#include "TcpConnection.h"
|
||||
|
||||
TcpListener::TcpListener() : system(nullptr) {
|
||||
}
|
||||
|
||||
TcpListener::TcpListener(System& system, const std::string& address, uint16_t port) : system(&system), stopped(false) {
|
||||
listener = new boost::asio::ip::tcp::acceptor(*static_cast<boost::asio::io_service*>(system.getIoService()), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port), true);
|
||||
}
|
||||
|
||||
TcpListener::TcpListener(TcpListener&& other) : system(other.system) {
|
||||
if (other.system != nullptr) {
|
||||
listener = other.listener;
|
||||
stopped = other.stopped;
|
||||
other.system = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TcpListener::~TcpListener() {
|
||||
if (system != nullptr) {
|
||||
delete static_cast<boost::asio::ip::tcp::acceptor*>(listener);
|
||||
}
|
||||
}
|
||||
|
||||
TcpListener& TcpListener::operator=(TcpListener&& other) {
|
||||
if (system != nullptr) {
|
||||
delete static_cast<boost::asio::ip::tcp::acceptor*>(listener);
|
||||
}
|
||||
|
||||
system = other.system;
|
||||
if (other.system != nullptr) {
|
||||
listener = other.listener;
|
||||
stopped = other.stopped;
|
||||
other.system = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void TcpListener::start() {
|
||||
stopped = false;
|
||||
}
|
||||
|
||||
void TcpListener::stop() {
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
TcpConnection TcpListener::accept() {
|
||||
assert(system != nullptr);
|
||||
if (stopped) {
|
||||
throw std::runtime_error("Stopped");
|
||||
}
|
||||
|
||||
void* context = system->getCurrentContext();
|
||||
boost::asio::ip::tcp::socket* socket = new boost::asio::ip::tcp::socket(*static_cast<boost::asio::io_service*>(system->getIoService()));
|
||||
boost::system::error_code errorCode;
|
||||
static_cast<boost::asio::ip::tcp::acceptor*>(listener)->async_accept(*socket, [&](const boost::system::error_code& callbackErrorCode) {
|
||||
errorCode = callbackErrorCode;
|
||||
system->pushContext(context);
|
||||
});
|
||||
|
||||
system->yield();
|
||||
if (errorCode) {
|
||||
delete socket;
|
||||
throw boost::system::system_error(errorCode);
|
||||
}
|
||||
|
||||
return TcpConnection(*system, socket);
|
||||
}
|
43
src/System/TcpListener.h
Normal file
43
src/System/TcpListener.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class System;
|
||||
class TcpConnection;
|
||||
|
||||
class TcpListener {
|
||||
public:
|
||||
TcpListener();
|
||||
TcpListener(System& system, const std::string& address, uint16_t port);
|
||||
TcpListener(const TcpListener&) = delete;
|
||||
TcpListener(TcpListener&& other);
|
||||
~TcpListener();
|
||||
TcpListener& operator=(const TcpListener&) = delete;
|
||||
TcpListener& operator=(TcpListener&& other);
|
||||
void start();
|
||||
void stop();
|
||||
TcpConnection accept();
|
||||
|
||||
private:
|
||||
System* system;
|
||||
void* listener;
|
||||
bool stopped;
|
||||
};
|
82
src/System/TcpStream.cpp
Normal file
82
src/System/TcpStream.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) 2012-2014, 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 "TcpStream.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
TcpStreambuf::TcpStreambuf(TcpConnection& connection) : connection(connection) {
|
||||
setg(&readBuf.front(), &readBuf.front(), &readBuf.front());
|
||||
setp(reinterpret_cast<char*>(&writeBuf.front()), reinterpret_cast<char *>(&writeBuf.front() + writeBuf.max_size()));
|
||||
}
|
||||
|
||||
TcpStreambuf::~TcpStreambuf() {
|
||||
dumpBuffer();
|
||||
}
|
||||
|
||||
std::streambuf::int_type TcpStreambuf::underflow() {
|
||||
if (gptr() < egptr())
|
||||
return traits_type::to_int_type(*gptr());
|
||||
|
||||
size_t bytesRead;
|
||||
try {
|
||||
bytesRead = connection.read(reinterpret_cast<uint8_t*>(&readBuf.front()), readBuf.max_size());
|
||||
} catch (std::exception& ex) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
if (bytesRead == 0) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
setg(&readBuf.front(), &readBuf.front(), &readBuf.front() + bytesRead);
|
||||
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
int TcpStreambuf::sync() {
|
||||
return dumpBuffer() ? 0 : -1;
|
||||
}
|
||||
|
||||
bool TcpStreambuf::dumpBuffer() {
|
||||
try {
|
||||
size_t count = pptr() - pbase();
|
||||
connection.write(&writeBuf.front(), count);
|
||||
pbump(-count);
|
||||
} catch (std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::streambuf::int_type TcpStreambuf::overflow(std::streambuf::int_type ch) {
|
||||
if (ch == traits_type::eof()) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
if (pptr() == epptr()) {
|
||||
if (!dumpBuffer()) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
}
|
||||
|
||||
*pptr() = ch;
|
||||
pbump(1);
|
||||
|
||||
return ch;
|
||||
}
|
43
src/System/TcpStream.h
Normal file
43
src/System/TcpStream.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <streambuf>
|
||||
#include <array>
|
||||
|
||||
#include "TcpConnection.h"
|
||||
|
||||
class TcpStreambuf : public std::streambuf {
|
||||
public:
|
||||
TcpStreambuf(TcpConnection& connection);
|
||||
TcpStreambuf(const TcpStreambuf&) = delete;
|
||||
|
||||
virtual ~TcpStreambuf();
|
||||
|
||||
private:
|
||||
std::streambuf::int_type underflow() override;
|
||||
std::streambuf::int_type overflow(std::streambuf::int_type ch) override;
|
||||
int sync() override;
|
||||
|
||||
bool dumpBuffer();
|
||||
|
||||
TcpConnection& connection;
|
||||
|
||||
std::array<char, 4096> readBuf;
|
||||
std::array<uint8_t, /*1024*/ 16> writeBuf;
|
||||
};
|
70
src/System/Timer.cpp
Normal file
70
src/System/Timer.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) 2012-2014, 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 "Timer.h"
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include "System.h"
|
||||
|
||||
Timer::Timer() : system(nullptr) {
|
||||
}
|
||||
|
||||
Timer::Timer(System& system) : system(&system) {
|
||||
timer = new boost::asio::steady_timer(*static_cast<boost::asio::io_service*>(system.getIoService()));
|
||||
}
|
||||
|
||||
Timer::Timer(Timer&& other) : system(other.system) {
|
||||
if (other.system != nullptr) {
|
||||
timer = other.timer;
|
||||
other.system = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
if (system != nullptr) {
|
||||
delete static_cast<boost::asio::steady_timer*>(timer);
|
||||
}
|
||||
}
|
||||
|
||||
Timer& Timer::operator=(Timer&& other) {
|
||||
if (system != nullptr) {
|
||||
delete static_cast<boost::asio::steady_timer*>(timer);
|
||||
}
|
||||
|
||||
system = other.system;
|
||||
if (other.system != nullptr) {
|
||||
timer = other.timer;
|
||||
other.system = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Timer::sleep(std::chrono::milliseconds time) {
|
||||
assert(system != nullptr);
|
||||
static_cast<boost::asio::steady_timer*>(timer)->expires_from_now(time);
|
||||
void* context = system->getCurrentContext();
|
||||
boost::system::error_code errorCode;
|
||||
static_cast<boost::asio::steady_timer*>(timer)->async_wait([&](const boost::system::error_code& callbackErrorCode) {
|
||||
errorCode = callbackErrorCode;
|
||||
system->pushContext(context);
|
||||
});
|
||||
|
||||
system->yield();
|
||||
if (errorCode) {
|
||||
throw boost::system::system_error(errorCode);
|
||||
}
|
||||
}
|
38
src/System/Timer.h
Normal file
38
src/System/Timer.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) 2012-2014, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
class System;
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
Timer();
|
||||
explicit Timer(System& system);
|
||||
Timer(const Timer&) = delete;
|
||||
Timer(Timer&& other);
|
||||
~Timer();
|
||||
Timer& operator=(const Timer&) = delete;
|
||||
Timer& operator=(Timer&& other);
|
||||
void sleep(std::chrono::milliseconds time);
|
||||
|
||||
private:
|
||||
System* system;
|
||||
void* timer;
|
||||
};
|
Loading…
Reference in a new issue