From 6d741947cb41776bfacc4a2cb9c45083837196c4 Mon Sep 17 00:00:00 2001 From: jezal Date: Mon, 15 Sep 2014 14:48:45 +0400 Subject: [PATCH] New TCP server --- CMakeLists.txt | 2 +- src/System/Event.cpp | 98 ++++++++++++++++++++++++++ src/System/Event.h | 43 +++++++++++ src/System/System.cpp | 133 +++++++++++++++++++++++++++++++++++ src/System/System.h | 46 ++++++++++++ src/System/TcpConnection.cpp | 110 +++++++++++++++++++++++++++++ src/System/TcpConnection.h | 47 +++++++++++++ src/System/TcpConnector.cpp | 67 ++++++++++++++++++ src/System/TcpConnector.h | 41 +++++++++++ src/System/TcpListener.cpp | 88 +++++++++++++++++++++++ src/System/TcpListener.h | 43 +++++++++++ src/System/TcpStream.cpp | 82 +++++++++++++++++++++ src/System/TcpStream.h | 43 +++++++++++ src/System/Timer.cpp | 70 ++++++++++++++++++ src/System/Timer.h | 38 ++++++++++ 15 files changed, 950 insertions(+), 1 deletion(-) create mode 100644 src/System/Event.cpp create mode 100644 src/System/Event.h create mode 100644 src/System/System.cpp create mode 100644 src/System/System.h create mode 100644 src/System/TcpConnection.cpp create mode 100644 src/System/TcpConnection.h create mode 100644 src/System/TcpConnector.cpp create mode 100644 src/System/TcpConnector.h create mode 100644 src/System/TcpListener.cpp create mode 100644 src/System/TcpListener.h create mode 100644 src/System/TcpStream.cpp create mode 100644 src/System/TcpStream.h create mode 100644 src/System/Timer.cpp create mode 100644 src/System/Timer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 243001d1..09493a73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/src/System/Event.cpp b/src/System/Event.cpp new file mode 100644 index 00000000..ddc2a507 --- /dev/null +++ b/src/System/Event.cpp @@ -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 . + +#include "Event.h" +#include +#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(); + } +} diff --git a/src/System/Event.h b/src/System/Event.h new file mode 100644 index 00000000..50125024 --- /dev/null +++ b/src/System/Event.h @@ -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 . + +#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; +}; diff --git a/src/System/System.cpp b/src/System/System.cpp new file mode 100644 index 00000000..fd12d33c --- /dev/null +++ b/src/System/System.cpp @@ -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 . + +#include "System.h" +#include +#include +#include + +namespace { +void contextProcedureStatic(intptr_t context) { + reinterpret_cast(context)->contextProcedure(); +} +} + +System::System() { + ioService = new boost::asio::io_service; + work = new boost::asio::io_service::work(*static_cast(ioService)); + currentContext = new boost::context::fcontext_t; +} + +System::~System() { + assert(procedures.empty()); + assert(resumingContexts.empty()); + while (!contexts.empty()) { + + delete static_cast(contexts.top()); + + contexts.pop(); + } + delete static_cast(work); + if (!static_cast(ioService)->stopped()) { + static_cast(ioService)->stop(); + } + delete static_cast(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&& procedure) { + procedures.emplace(std::move(procedure)); +} + +void System::wake() { + static_cast(ioService)->post([] {}); +} + +void System::yield() { + if (procedures.empty()) { + void* context; + for (;;) { + if (resumingContexts.empty()) { + boost::system::error_code errorCode; + static_cast(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(currentContext); + currentContext = context; +#if (BOOST_VERSION >= 105600) + boost::context::jump_fcontext(oldContext, *static_cast(context), reinterpret_cast(this), false); +#else + boost::context::jump_fcontext(oldContext, static_cast(context), reinterpret_cast(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(currentContext); + currentContext = context; +#if (BOOST_VERSION >= 105600) + boost::context::jump_fcontext(oldContext, *static_cast(context), reinterpret_cast(this), false); +#else + boost::context::jump_fcontext(oldContext, static_cast(context), reinterpret_cast(this), false); +#endif + } +} + +void System::contextProcedure() { + void* context = currentContext; + for (;;) { + assert(!procedures.empty()); + std::function procedure = std::move(procedures.front()); + procedures.pop(); + procedure(); + contexts.push(context); + yield(); + } +} diff --git a/src/System/System.h b/src/System/System.h new file mode 100644 index 00000000..712de348 --- /dev/null +++ b/src/System/System.h @@ -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 . + +#pragma once + +#include +#include +#include + +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&& procedure); + void yield(); + void wake(); + + void contextProcedure(); + +private: + void* ioService; + void* work; + std::stack contexts; + std::queue> procedures; + std::queue resumingContexts; + void* currentContext; +}; diff --git a/src/System/TcpConnection.cpp b/src/System/TcpConnection.cpp new file mode 100644 index 00000000..13a5a41b --- /dev/null +++ b/src/System/TcpConnection.cpp @@ -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 . + +#include "TcpConnection.h" +#include +#include +#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(socket); + } +} + +TcpConnection& TcpConnection::operator=(TcpConnection&& other) { + if (system != nullptr) { + delete static_cast(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(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(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); +} diff --git a/src/System/TcpConnection.h b/src/System/TcpConnection.h new file mode 100644 index 00000000..ce2829e9 --- /dev/null +++ b/src/System/TcpConnection.h @@ -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 . + +#pragma once + +#include +#include + +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; +}; diff --git a/src/System/TcpConnector.cpp b/src/System/TcpConnector.cpp new file mode 100644 index 00000000..703a1f8d --- /dev/null +++ b/src/System/TcpConnector.cpp @@ -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 . + +#include "TcpConnector.h" +#include +#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(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); +} diff --git a/src/System/TcpConnector.h b/src/System/TcpConnector.h new file mode 100644 index 00000000..960d1f1f --- /dev/null +++ b/src/System/TcpConnector.h @@ -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 . + +#pragma once + +#include +#include + +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; +}; diff --git a/src/System/TcpListener.cpp b/src/System/TcpListener.cpp new file mode 100644 index 00000000..75071eac --- /dev/null +++ b/src/System/TcpListener.cpp @@ -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 . + +#include "TcpListener.h" +#include +#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(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(listener); + } +} + +TcpListener& TcpListener::operator=(TcpListener&& other) { + if (system != nullptr) { + delete static_cast(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(system->getIoService())); + boost::system::error_code errorCode; + static_cast(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); +} diff --git a/src/System/TcpListener.h b/src/System/TcpListener.h new file mode 100644 index 00000000..6147257c --- /dev/null +++ b/src/System/TcpListener.h @@ -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 . + +#pragma once + +#include +#include + +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; +}; diff --git a/src/System/TcpStream.cpp b/src/System/TcpStream.cpp new file mode 100644 index 00000000..da058f4b --- /dev/null +++ b/src/System/TcpStream.cpp @@ -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 . + +#include "TcpStream.h" + +#include + +TcpStreambuf::TcpStreambuf(TcpConnection& connection) : connection(connection) { + setg(&readBuf.front(), &readBuf.front(), &readBuf.front()); + setp(reinterpret_cast(&writeBuf.front()), reinterpret_cast(&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(&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; +} diff --git a/src/System/TcpStream.h b/src/System/TcpStream.h new file mode 100644 index 00000000..55c28d55 --- /dev/null +++ b/src/System/TcpStream.h @@ -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 . + +#pragma once + +#include +#include + +#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 readBuf; + std::array writeBuf; +}; diff --git a/src/System/Timer.cpp b/src/System/Timer.cpp new file mode 100644 index 00000000..786d4485 --- /dev/null +++ b/src/System/Timer.cpp @@ -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 . + +#include "Timer.h" +#include +#include "System.h" + +Timer::Timer() : system(nullptr) { +} + +Timer::Timer(System& system) : system(&system) { + timer = new boost::asio::steady_timer(*static_cast(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(timer); + } +} + +Timer& Timer::operator=(Timer&& other) { + if (system != nullptr) { + delete static_cast(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(timer)->expires_from_now(time); + void* context = system->getCurrentContext(); + boost::system::error_code errorCode; + static_cast(timer)->async_wait([&](const boost::system::error_code& callbackErrorCode) { + errorCode = callbackErrorCode; + system->pushContext(context); + }); + + system->yield(); + if (errorCode) { + throw boost::system::system_error(errorCode); + } +} diff --git a/src/System/Timer.h b/src/System/Timer.h new file mode 100644 index 00000000..317f87eb --- /dev/null +++ b/src/System/Timer.h @@ -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 . + +#pragma once + +#include + +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; +};